CodeIgniter: Database Migrations Tutorial

All of my blog posts up to this point have been used to introduce myself and what I have done up-to now. This blog post is the first that is purely aimed at PHP development.

I first started with CodeIginiter about 2 months ago and I’ve spent a lot of my time reading their fantastic user guide. The only problem is that because the framework can do so much it can be very easy to miss some of the great features that it has. The tutorials that are provided in the user guide are only aimed at those just starting out and as such stays at a very basic level.

A feature that was added fairly recently (CodeIgniter 2.1.0) is Migrations. This is a useful Class that allows for you to create and manage your database structure through your code. Migrations aren’t themselves new (they came primarily from Ruby on Rails – an alternative programming languages which influences most of the PHP frameworks). Database migrations are a way of effectively versioning your database changes.

Lets use an example of a CMS product that is self hosted (wordpress for example). Over time the developers of that software will need to roll out database changes, however not everyone will be on the same version of the software. This means you need to be careful to ensure that only the database changes that are required are made when they upgrade their software. This is where the Migration class comes in. You would simply create a new migration versioning file, put in the changes that need to be made and then upgrade the version number in your configuration file.

Getting Started

To get started you simply need to open application/config/migrations.php and change:
$config['migration_enabled'] = FALSE;
to:
$config['migration_enabled'] = TRUE;

A bit lower down in this same file you will see the configuration property called migration_version. This is how the system knows what the curent database version should be for your site. When it recognises that you’re running on a lower version than this it will upgrade your database through all the steps leading up to this version. So once you add a migration you would increase this version number to match.

Next we need to create a directory in the application directory called migrations. This is where our database migrations will reside. Unfortunately there doesn’t seem to be a way to get CodeIgniter to generate these migration files for you (I’m not sure if Rails will do this?) so if you already have a database structure in place then it’ll take some work to get the inital structure reproduced in a file. Your version 1 migration file will basically match your existing/starting database structure.

Migration Files

You need to create a file inside this new directory and the naming format has to start with your version number followed by the name of your class (make it is descriptive of the changes that you are making i.e. your first one might be: initial_schema). My first migration file was called: 001_initial_schema.php and my next one could be 002_add_comments.
Your file would look something like this:

<?php
defined('BASEPATH') OR exit('No direct script access allowed');

class Migration_Initial_schema extends CI_Migration {

	public function up()
	{
		$this->dbforge->add_field(array(
			'postid' => array(
				'type' => 'INT',
				'constraint' => 11,
				'unsigned' => TRUE,
				'auto_increment' => TRUE
			),
			'title' => array(
				'type' => 'VARCHAR',
				'constraint' => '100',
			),
			'content' => array(
				'type' => 'TEXT',
				'null' => TRUE,
			),
		));

		$this->dbforge->create_table('posts');
	}

	public function down()
	{
		$this->dbforge->drop_table('posts');
	}
}

You’ll notice that there are two functions (up and down) in this class. The up function is run when you upgrade to/past this version and likewise the down function is run if you downgrade your database (using the config file) below this version. Your down function will always do the reverse of what your up function does. Essentially restoring your database to the state that it was before that version was added. Also notice that the name of the class above matches the suggested file name I gave earlier (except for the word Migration), the code expects for the class to be named in this way and won’t work without it.

I won’t go into detail about the format to use for the field array when creating or modifying tables as CodeIgniter’s user guide on the Database Forge Class already explains this perfectly.

The only caveat I noticed is when you want to have a text or varchar field with a null default value. Normally in phpMyAdmin you would expect to tick the Null field and also set the default value to Null.  However all you need to do here is specify null as TRUE which you should be able to see from my example above. If you try to define default as null then it will actually set the default as a blank string. I assume that this issue will get cleared up eventually but as long as you keep it in mind then it’s not hard to avoid.

Putting into Practice

Working in this way may seem a little clunky to start with but this functionality comes into it’s own when you have a product that you need to deploy to your customers. You don’t want to be giving them the SQL to enter into phpMyAdmin themselves. Instead this is something you can build directly into your install/upgrade scripts. You just need to load the library and call it’s current method (as below) and your database will automatically be upgraded/downgraded to the version defined in your config file.

load->library('migration');
$this->migration->current();

I would recommend building more into your script, in-case there are any errors etc but those two lines will do all the magic. So there you have it, you now have a version controlled database that can be rolled forwards/backwards whenever you want.

Is there a particular feature from CodeIgniter that you would like for me to delve into next? Have you used CodeIgniter or any other PHP framework before? Do you have any experience with Ruby on Rails? I’d love to hear from you so please Get in Touch or leave a comment below.

Related Posts:

Tagged with:
Posted in CodeIgniter, PHP Development
  • http://polycademy.com/ Roger Qiu

    Hey, great post, I’m just getting into this database migrations. If you already
    manually exported the tables (that has different data) from development
    to production, can you still create a version 1 migration. Does it
    delete the data if the tables already exist? Furthermore, what If I want to
    keep the data in development and production different, but the schema
    the same, what do I do then?

    • http://robertsettle.com/ Robert Settle

      Hey, sorry about the late response. What I did with my development and production systems was generally keep data out of it, and started from scratch with both systems. It’s not intended to be used for backing up data. Other than a couple of tiny tables (such as one storing date formats) my migrations were purely structural.

      My version 1 migration creates all of the tables in my database (took quite a while to write all that code lol) so that if I created another site I could get it to the full structure just by running the migration script.

      • http://polycademy.com/ Roger Qiu

        I see, so you basically just have avoid writing any kind of migration that transports SQL data. All the migration does is recreate or edit the table structure where or not if those tables exist already. So that if the tables already exist, they will just edit the structure (such as removing columns) and not do anything to the other data. And if they don’t exist, they’ll just create it. Am I getting this right? Therefore I can have 2 different data sets between development and production and only just migrate the structure, not data.

        • http://robertsettle.com/ Robert Settle

          Exactly, what you could always do is export the data before putting in all the migration stuff and then re-import the data afterwards. The main benefit is being able to update multiple websites/environments structure in a controlled manner.

          I’ve had situations in the past where the code had been updated but the database hadn’t so the code is then trying to use fields that don’t actually exist. I’m using a similar idea for an app I’m working on atm.

          The main thing to keep in mind is making sure the down function is the exact reverse of the up function (restoring to how it was before), so if you create a table, then the down would drop the table (obviously losing any data in that table). You should be able to go backwards and forwards through your migrations without the script failing (trying to add the same table twice).

  • panduwana

    That’s great for manual migration, thanks! Is there any CLI command for auto-generating them when my model changes?

    • http://robertsettle.com/ Robert Settle

      I think there are CLI libraries around for CodeIgniter but I’ve always preferred doing things myself, so I’m not really sure. I did have a quick look at the time to see if it could generate my initial structure and couldn’t find anything at the time.

      The situation may well have changed though. It is an actively developed project with lots of additions being made by the community.