
4 months ago, you published a website on a production server. Ok, no a big deal. You work on next iterations and today you must update the website.
Some git push here, git pull there (or whatever you use). Still ok. But what about the database ? You did upgade you schema, still you cannot delete all existing datas in the production database, right ?
How should you manage that ? Check every field you changed, go to phpMyAdmin and manually build each field and table, launch functional tests to check no error appears ? Come on, let's not get silly ! You'll use Doctrine migration task !
Starting up the project
One upon a time your schema was straight and clear. You basically has a list of members with a fistname and a lastname
Schema at its first version
Member:
columns:
id: { type: integer(4), primary: true, autoincrement: true }
firstname: string(50)
lastname: string(50)
Of course you had some basic fixtures :
Member:
pointbar:
firstname: Stéphane
lastname: Langlois
ioo:
firstname: Lionel
lastname: Chanson
vinyll:
firstname: Vincent
lastname: Agnano
Then you did something like :
symfony doctrine:build --all --and-load
Made your modules, wrote your tests, refactored, enjoyed, had lunch and fun, pushed your site on the staging, got it tested and validated and finally run it in production ! Phew, what a journey you had.
Some time later, you reached today. And today is a great new day because you must update your website. And its database. Push all that in production. Oh, and preserving the datas from that database. Ok ok, you got the point and its issue. Let's go then !
Updating the project
Members are required to get username. A new functionality also comes up as they may have tasks. Easy...
First thing first, you update your schema as necessary :
Task:
columns:
id: { type: integer(4), primary: true, autoincrement: true }
title: string(100)
body: clob
member_id: integer(4)
relations:
Member:
class: Member
local: member_id
foreign: id
foreignAlias: Tasks
Member:
columns:
id: { type: integer(4), primary: true, autoincrement: true }
firstname: string(50)
lastname: string(50)
username: string(20)
And update your fixtures :
Member:
pointbar:
username: pointbar
firstname: Stéphane
lastname: Langlois
ioo:
username: ioo
firstname: Lionel
lastname: Chanson
vinyll:
username: vinyll
firstname: Vincent
lastname: Agnano
Task:
migrations:
title: Finish blog article
body: Will I ever make it ?
Member: vinyll
mediabrowser:
title: Fix sfMediaBrowser tickets
body: "Ask some Windows to solve http://github.com/vinyll/sfMediaBrowserPlugin/issues/issue/5"
Member: vinyll
Update your model
Here is the point. Don't update your schema as you're used to as it would fully recreate your model.
Instead, you'll use the migration generation from difference.
Generating a migration
As of Doctrine 1.1, you can generate migrations classes automatically from schema differences and not type the whole thing. Warning : Do NOT run some "symfony doctrine:build --model" if you don't want to run through some error.
So you may safely hit this line :
symfony doctrine:generate-migrations-diff
Magic comes out and as the tasks says, it generates migration classes from the differences.
Check out /lib/migration/doctrine/ and you'll see 2 new files (2 in our example case). Those are the classes that will updagrade-enable and downgrade-enable our application without reconstructing the whole structure. The first generated file is the basic columns modification while the second is for indexes and relations (as it must be done after columns creation/deletion, database-wise).
Applying a migration
Simply run !
symfony doctrine:migrate
What happened ?
Check out your Base model classes and your database. They have been updated, just as if you had run a "doctrine:build --all" but with the awareness of versionning. We could compare it to svn or git.
Doctrine's versionning system
It actually happens in 2 places :
- One that holds the current version : that's your database ! If you have a look at it, you'll see a table called "migration_version" that has 1 column named "version" and 1 record that holds "2" ("2" in our specific case). That "2" is as you understood the current version you are at !
- The file system : these classes you opened earlier (/lib/migration/doctrine/*) are named by their version number.
Therefore it will be very easy to know at what version you currently are, how far your are from head version and what happens in next/previous version just reading the class files.
Update in staging/prod environment
You'll be required to migrate your prod version as well. First update your files going for a "git pull" or whatever. That brings in your migration classes. Next you just need to run your migration task :
symfony doctrine:migrate
Now you may run your tests again. All datas are preserved. You can go back for lunch and fun.
Comments
4 comments
Cool!
Ryan Weaver just release today a slideshow that you may also want to consider : http://www.slideshare.net/weaverrya...
Really nice post! Thanks for sharing this.
[url=http://www.coach-bags-outlet.com/]... outlet online[/url]
<a href="http://www.chanelbags2010.com/">chanel bags 2010</a>
http://www.coach-bags-outlet.com/ coach bags outlet
[link='http://www.chanelbags2010.com']cha... bags[/link]
O(∩_∩)O~..O(∩_∩)O~