30 Oct

How to keep your database under version control?

Best Practices, CakePHP

I've been looking for a solution to this problem from quite a few days now, and I did find it quite interesting that there's no standard way to do this. So I decided to ask the CakePHP community, while there are many tools available to do the things, but I'm going to share the best solution of all, which is also Cake based. CakePHP has something known as Schema shell, which helps you solving the problem in efficient way.

Let me describe the problem first briefly. There was this comic I saw few days back (can't find it right now), which inspired me to solve this problem. Here goes the text from that cartoon:

 

Alex: Ok, we're ready, let's sync our work on this project today to show to client.

Rob: Ok sure, let me see the database changes and put it to server.

Alex: Oh yea, let me do it too.

Rob: Hey, I made this change, is it yours? And what about this? Where are you using it?

Alex: Yes-No-Yes-….

Boss: And we're screwed.

 

That was happening all the time with our team too, before I found this way.

Here's how it works:

1. Setup

Assuming that you already have a working project to implement db versioning on, start command line console from your 'app' directory. And then run 'cake schema help' to make sure you have the shell, or for necessary instructions.

 

2. Generate first Schema

After you see it working fine, lets output our whole DB structure into a dump file, it's not SQL dump file, its schema file which is in Cake-friendly format. You can play with other commands like 'schema view' to make sure things works. Ok, let's generate our schema with 'cake schema generate'.

Ok, schema.php generated, it would be inside your app/config/sql

Here's how the file will look:

PHP:
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /* App schema generated on: 2008-10-30 23:10:37 : 1225410517*/
  4. class AppSchema extends CakeSchema {
  5.     var $name = 'App';
  6.  
  7.     function before($event = array()) {
  8.         return true;
  9.     }
  10.  
  11.     function after($event = array()) {
  12.     }
  13.  
  14.     var $users = array(
  15.             'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
  16.             'name' => array('type'=>'string', 'null' => false, 'length' => 25),
  17.             'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
  18.         );
  19. }
  20. ?>

Looks good (with the sample db). Now as you have a file for the whole database, you can put it in a repository under version control along with your project.

 

3. Update Schema

Since, there will be changes in database throughout the development of the project, and they will be done by many other developers. We'll need to keep a track of it, to do so, we'll make sure schema files remains updated always – this is something you'll have to instruct your team about.

Let's make a sample change and see how it goes. In my users table, I am going to add a new field called 'password' and then regenerate my schema file.

ALTER TABLE `users` ADD `password` VARCHAR( 20 ) NOT NULL ;

Lets regenerate schema now:

CakePHP's Schema shell had detected the change automatically, and prompted me if I want to over-write the current schema or snapshot it (create a new one). In my case, I want to overwrite it as I already have it in version control. Let's see what new schema looks like:

PHP:
  1. <?php
  2. /* SVN FILE: $Id$ */
  3. /* App schema generated on: 2008-10-30 23:10:33 : 1225411053*/
  4. class AppSchema extends CakeSchema {
  5.     var $name = 'App';
  6.  
  7.     function before($event = array()) {
  8.         return true;
  9.     }
  10.  
  11.     function after($event = array()) {
  12.     }
  13.  
  14.     var $users = array(
  15.             'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
  16.             'name' => array('type'=>'string', 'null' => false, 'length' => 25),
  17.             'password' => array('type'=>'string', 'null' => false, 'length' => 20),
  18.             'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
  19.         );
  20. }
  21. ?>

You see the 'password' field was reflected here as well. Now you can keep your whole DB structure under this schema file with version controlling. However, we've yet to sync the database across different machines. Let's say after updating (svn up) on my local setup, I got a new schema which I would like to implement on my database. Here's how you'll do that in next step.

 

4. Syncing

Let's assume the other user has added a field 'address' in his database, and regenerated the schema. Now I want same change to reflect on my local database. Here's new updated schema looks like (it's only a part of the schema.php file):

PHP:
  1. var $users = array(
  2.             'id' => array('type'=>'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
  3.             'name' => array('type'=>'string', 'null' => false, 'length' => 25),
  4.             'password' => array('type'=>'string', 'null' => false, 'length' => 20),
  5.             'address' => array('type'=>'string', 'null' => false, 'length' => 40),
  6.             'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => 1))
  7.         );

Now there are normally 2 options to update your database:

  • you drop all tables and then import fresh DB structure from schema.
  • Just update (We need this one)

Here's what you'll do:

And done, our database is now synced. You can run the same process across different machines to never worry about manual syncing. [Please note by 'sync' I mean only the structure not the records.]

Hope you enjoyed it!

 

Abhimanyu Grover

 

Tags: , , , ,

11 Responses to “How to keep your database under version control?”

Subscribe to comments with RSS Feed or TrackBack from your own site.


  1. on Fri, 31 October, 2008 at 5:39 am

    Great! The best schema shell coverage out there, congratulations.
    It has just been added to the MUST READ section of my company intranet.

  2. admin said,

    on Fri, 31 October, 2008 at 5:45 am

    @rafaelbandeira3 Thanks for your comment. Hope it’ll prove helpful.


  3. on Mon, 24 November, 2008 at 8:02 am

    […] How to keep your database under version control? - Giga Promoters Blog […]

  4. madsheep said,

    on Sun, 14 December, 2008 at 2:49 am

    Well i was sure that cakephp has a feature do keep database in order, same like RoR migrations - just couldn’t find it. Now i know i was right - thx for the article.

  5. Silver Knight said,

    on Wed, 17 June, 2009 at 1:47 pm

    Thank you for the useful information. One detail that tripped me up is at the end of the post:

    Here’s what you’ll do:

    (I’m not seeing anything at this point in the article, where I assume that there was at one time an explanation about using the schema exported earlier in the post?)

    And done, our database is now synced.

  6. admin said,

    on Wed, 17 June, 2009 at 11:21 pm

    @Silver Knight: Fixed the broken images.

  7. bram said,

    on Wed, 14 October, 2009 at 7:00 am

    If you modified the database that you want to update, make sure you remove all files in /app/tmp/cache/models before running a schema update!!

    While the shell clearly states: “Comparing Database to Schema…”, it actually compares the model cache to the schema. By removing the model cache, it will be regenerated before the comparison takes place.

  8. joebert said,

    on Tue, 20 October, 2009 at 9:45 am

    I couldn’t help but notice the xdebug zend extension warning in your command prompt. :)
    http://develobert.blogspot.com/2008/06/xdebug-must-be-loaded-as-zend-extension.html

  9. admin said,

    on Tue, 20 October, 2009 at 12:55 pm

    Thanks, fixed it longtime back.

  10. mugafuga said,

    on Wed, 27 January, 2010 at 2:46 pm

    wouldn’t it be nice if there were a command line switch to blow out your model cache.

    like ignore cache could be i
    …cake schema generate -fi

    or delete cache could be d
    …cake schema generate -fd

    Or just make it so that -f blows out the cache. That would like make sense instead of searching and searching and searching and searching because the generate command doesn’t seem to see whats in the database ever.

    Or i could just svn:ignore my tmp/cache.

  11. admin said,

    on Wed, 27 January, 2010 at 6:41 pm

    @mugafuga We use our own shell for this nowadays which is called giga_schema shell. This is how we’ve solved the caching problem:

    GigaSchema extends the startup() function of Schema shell like this:

    function startup()
    {
    Utility::cleanDir(TMP.’cache’.DS.’models’.DS); // delete BS
    parent::startup();
    }

    And here’s the code of cleanDir() in Utility class

    function cleanDir($path)
    {
    $folder=& new Folder($path);
    $tree=$folder->tree($path, false);
    foreach ($tree as $files) {
    foreach ($files as $file) {
    if (!is_dir($file)) {
    $file=& new File($file);
    $file->delete();
    }
    }
    }
    return;
    }

    Hope it helps.

Leave A Reply







Hire us

Contact us to get a free quote on your project.