New to Migrations in 1.1
New to Migrations in 1.1
Posted by jwage 3 months ago
In Doctrine 1.1 migrations are much easier to work with. In addition to the increased stability we have enhanced the migrations in a few ways to simplify the use of them dramatically.
We have introduced the following features.
- Diff Tool - Generate migration classes by simply changing your schema and generating the migrations.
- Down Automation - Doctrine now has the ability to automate the down of of a migration call.
Generating Migrations
Imagine you have the following starting schema.
---
User:
columns:
username: string(255)
password: string(255)
Build your initial models from the schema.
$ ./doctrine generate-models-yaml
Now we want to enhance our schema to add some new columns as well as a new model with the following schema.
---
User:
columns:
username: string(255)
password: string(255)
email_address: string(255)
Phonenumber:
columns:
user_id: integer
phonenumber: string(25)
relations:
User:
onDelete: CASCADE
foreignAlias: Phonenumbers
Now by simply changing our schema we can generate the migrations required to upgrade our database.
$ ./doctrine generate-migrations-models
Now in your migrations directory you will see 3 migration classes created for you.
1224273485_add_user.php
<?php /** * This class has been auto-generated by the Doctrine ORM Framework */ class AddUser extends Doctrine_Migration_Base { public function up() { $this->createTable('up', 'user', array('id' => array('type' => 'integer', 'length' => 8, 'autoincrement' => true, 'primary' => true), 'username' => array('type' => 'string', 'length' => 255), 'password' => array('type' => 'string', 'length' => 255)), array('indexes' => array(), 'primary' => array(0 => 'id'))); } public function down() { $this->dropTable('up', 'user'); } }
1224273485_version1.php
<?php /** * This class has been auto-generated by the Doctrine ORM Framework */ class Version1 extends Doctrine_Migration_Base { public function up() { $this->createTable('up', 'phonenumber', array('id' => array('type' => 'integer', 'length' => 8, 'autoincrement' => true, 'primary' => true), 'user_id' => array('type' => 'integer', 'length' => 8), 'phonenumber' => array('type' => 'string', 'length' => 25)), array('indexes' => array(), 'primary' => array(0 => 'id'))); $this->addColumn('up', 'user', 'email_address', '255', 'string', array ()); } public function down() { $this->dropTable('up', 'phonenumber'); $this->removeColumn('up', 'user', 'email_address'); } }
1224273486_version2.php
<?php /** * This class has been auto-generated by the Doctrine ORM Framework */ class Version2 extends Doctrine_Migration_Base { public function up() { $this->addIndex('up', 'phonenumber', 'phonenumber_user_id_user_id', array('fields' => array(0 => 'user_id'))); $this->createForeignKey('up', 'phonenumber', array('name' => 'phonenumber_user_id_user_id_idx', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user', 'onUpdate' => NULL, 'onDelete' => 'CASCADE')); } public function down() { $this->removeIndex('up', 'phonenumber', 'phonenumber_user_id_user_id', array('fields' => array(0 => 'user_id'))); $this->dropForeignKey('up', 'phonenumber', array('name' => 'phonenumber_user_id_user_id_idx', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user', 'onUpdate' => NULL, 'onDelete' => 'CASCADE')); } }
Down Automation
In addition to Doctrine being able to generate migrations based on your schema changes, you can now easily automate the down of most methods. The last migration class could be simplified a lot by doing the following.
<?php /** * This class has been auto-generated by the Doctrine ORM Framework */ class Version2 extends Doctrine_Migration_Base { public function migrate($direction) { $this->addIndex($direction, 'phonenumber', 'phonenumber_user_id_user_id', array('fields' => array(0 => 'user_id'))); $this->createForeignKey($direction, 'phonenumber', array('name' => 'phonenumber_user_id_user_id_idx', 'local' => 'user_id', 'foreign' => 'id', 'foreignTable' => 'user', 'onUpdate' => NULL, 'onDelete' => 'CASCADE')); } }
Notice that in this example we only have one method named migrate() which receives a direction. Most API methods are easy to automate the opposite down so when migrate is called with $direction = 'down' then the index and foreign key will be dropped instead of added.
Comments (7) [ add comment ]
This makes my day ! - Posted by jukea about 3 months ago.
Hi jwage,
The auto generation of migration classes is really a welcome feature ! Thanks for implementing it !
After reading this article, I still had a few questions unanswered thought :
migration classes are generated by comparing the schema to the models, or to the database ?
what is that number at the beginning of migration classes filenames ?
why 3 files when the schema has been updated one time ?
why add_user instead of version_0 ?
how to actually update the database to reflect the changes to the schema ? I suppose you need
keep up the good work!
oops - Posted by jukea about 3 months ago.
to avoid confusion .."i suppose you need" was a leftover from another sentence :)
Thanks - Posted by Vincent about 3 months ago.
This sounds very useful, thanks!
Posted by Markus Staab about 3 months ago.
would be nice to have a timestamp/date in the head of the comment of the generated files..
also it would be better to read if the migration statements contain some newlines..
nice work!
@jukea - Posted by jwage about 3 months ago.
The migrations can be generated by comparing any two sets of schema information. It is simple a "from" and a "to" and it can be a database, yaml schema files or models and it will compare them and produce a migrations class. The
generate-migrations-modelstask compares the models and the yaml schema file but you can implement your own to do whatever you want.It is just a unique timestamp to ensure uniqueness and proper order of the migration classes. This was changed from the 001, 002 for obvious reasons.
The
generate-migrations-modelscommand builds the migrations to recreate the database if no migration classes exist so first it creates all the migrations to create everything, then the migrations for the differences found between the old models on disk and the modified schema files.The initial migrations creation of all existing models create one class per model and then a class to create all foreign keys so we can name them appropriately. When we generate a class based on a diff it can contain any number of different changes so the name is a simple incremented version number.
You would simply run the
migratecommand.And then rebuild your models from the yaml schema files.
Brilliant work - Posted by David Arthur about 2 months ago.
This is an excellent addition, saves a lot of time and i'd like to say thanks!
symfony - Posted by Matthias about about 1 month ago.
I suppose this is not yet available for / with a symfony plugin?
What about creating another sfDoctrineExtraPlugin that contains additional tasks/whatever or things that require another Doctrine version. (hm.. also requires that there is a way to substitute the Doctrine version of sfDoctrinePlugin.. that can become a bit difficult..)