georgi

CakePHP Migrations without PEAR

Rails fans out there?

It is no secret that CakePHP was born to implement the ideas of Ruby on Rails to the world of PHP – wonderful ideas, indeed, and I think we should pay tribute to the guys at 37signals.

But what CakePHP still lacks, in my opinion, is pure and complete DB abstraction. It is true that most recent versions of Cake ( v.2 RC3 as of now ) have done a lot in that area – the framework is now strongly decoupled from MySQL, although I personally have never heard of study cases that use Oracle, for example.

To the point – in a multi-developer environment it is critical to have a versioning control system ( you know you should be using git, right? ) and a database ‘versioning’ system – that is where Rails is much more powerful than CakePHP – it has database migrations.

Some migrations’ background

If you know what migrations are – skip that part and go directly to the next one. Otherwise – here is a simple explanation: they are related to the database like git ( or svn or cvs ) is related to the source. They simple provide a way to go back or forth to a previous or succeeding state ( or version ) of the database schema. The features of migrations are:

  • They are DB agnostic – this means that they are not affected by the type of the DB server you’re using and help you in deploying your apps on different environments
  • They help you with your agile development – you can put info in and out without affecting the rest of the project
  • They provide you with a quick way to revert back to a previous state of the DB in case something went wrong
  • DB migrations can save your life if you work in a team

To illustrate the all said, I have a simple example: You create a blog ( of course a blog – that’s probably the most often used example in the world ). Let’s split the development into three simple parts – development of blog posts CRUD; adding ACL; adding Comments to posts and.. that’s it – we want a simple example, after all.

So, first – blog posts Create, Read, Update, Delete. You begin by creating your DB schema. You need a simple posts’ table with a few fields – id, title, body, created. Then you write your PHP code, of course ( out of scope here ).

But one beautiful day you decide more than one person should be able to add posts and modify their own posts only – that’s when you read about Access Control Lists. Now you need a few more tables – users, aros, acos, acl and you need to add a field to the posts’ table ( user_id, for example ). Our small blog is getting just a bit more complex.

Finally, you want comments! But you have no time and ask your cousin for a favor ( he is a good dev, after all ). He adds another table for that. And then decides only registered users ( who cannot write new posts ) can add comments. And, of course, writes some more code. And inserts some more data in the db.

You ( and your cousin ) have went through 3 distinctive phases of agile development. You have, of course, used git ( oh, well, maybe svn or cvs ) to keep track of your code and make sure everything is ok and that you can revert back to a previous, stable version, if anything goes wrong. But then, one day – something really goes wrong. And you need to revert from state 3 to state 2 – i.e. remove the comments. But … your cousin is

  • out of town
  • mad at you because you behaved badly on his last birthday party
  • has no idea what he did for you so many months ago

No problem – you use your source versioning system and do the reversal. But.. something is still wrong – your database stays unchanged. What did you add from v2 to v3? Did you remove something? And you know nothing about Database Server X – can you write the SQLs to revert the schema?

That is where DB migrations come in and save your life. Well, maybe not that important with your blog but imagine 100+ development iterations and 10+ developers working simultaneously on your project and maintaining it on many different platforms – this can turn into a small nightmare.

Joel Moss and his migrations

In his article at the Bakery Joel Moss describes how to use his CakePHP migrations shell. Although that project was my inspiration and I highly respect his work, his approach has several drawbacks:

  • it uses PEAR – I don’t like it – that’s why I use CakePHP. I do not find necessary to explain this – I guess it is highly subjective.
  • it is non-modular – you cannot use it to deploy applications – it is just a shell with no ‘core’
  • it cannot make a snapshot of your already existing schema – you haven’t used migrations yet? That’s something you will need.
  • it cannot merge your tables – that can be crucial when you already have different versions of the schema on different platforms and you just want them all to be standardized

So, I proudly present you with

My CakePHP Yaml Migrations and Fixtures

The idea was born when Eelco and I started working on PagebakeryCMS some time ago and was later further developed when we decided we needed a standardized CakePHP App Installer. You can get a copy of the project and follow it, too. What I personally find useful in it:

  • no external libraries – only the SPYC class used to parse YAML files ( that is authored by Chris Wanstrath )
  • can easily complement your source versioning system – use it for team collaboration
  • can be used for DB abstraction installers – when deploying your applications on different platforms you don’t want to modify your SQLs – and the project is DB agnostic. The package also has fixtures ( well, the terms is not used correctly – this is for adding initial data to your database )
  • can be used to standardize already installed applications on different platforms
  • can help you make your apps DB agnostic by generating a YAML structure of your schema from where you can go on with the agnostic aproach

How it works

Just put all files in your CakePHP vendors folder.

If you want to use the API only, simply include the classes in your code

App::Import('vendor', 'migrations' )

and/or

App::Import('vendor', 'fixtures' )

And then, for example

$migrations = new Migrations();
$migrations->load('comments.yml');
$migrations->up();

For more usages – dig into the code a bit 🙂

Tags: , , , , , , , ,

One Response to “CakePHP Migrations without PEAR”

  1. Grzegorz Pawlik Says:

    Hey, that plugin is really great. I just have one question about fixtures: Is there a way to generate fixture from actual database contents? (tried ./cake fixtures, but that’s just import).

    Plus I needed to add
    App::import(‘core’, ‘ConnectionManager’);
    in Your vendors/fixtures/fixture.php according to use ./cake fixtures 🙂

    Maybe You will be interested in my ImageBehavior I published recently (http://bakery.cakephp.org/articles/view/imagebehavior-best-from-database-blobs-and-file-storage)

    Cheers!

Leave a Reply