Posted about 1 year ago by jwage
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.
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-diff
Now in your migrations directory you will see 3 migration classes created for you.
1224273485_add_user.php<?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 [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 [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')); } }
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 [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 (14) [ add comment ]
This makes my day ! Posted by jukea about about 1 year 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 about 1 year ago.
to avoid confusion .."i suppose you need" was a leftover from another sentence :)
Thanks Posted by Vincent about about 1 year ago.
This sounds very useful, thanks!
Posted by Markus Staab about about 1 year 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 about 1 year 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 about 1 year 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 year 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..)
Behaviors Posted by Sailor about about 1 year ago.
How can I insert behaviors in a model using migrations ?
Thank's in advance !
Behaviors Posted by Sailor about about 1 year ago.
How can I insert behaviors in a model using migrations ?
Thank's in advance !
Behaviors Posted by Sailor about about 1 year ago.
How can I insert behaviors in a model using migrations ?
Thank's in advance !
Are there typos? Posted by benbac about about 1 year ago.
has anyone successfully ran the 'generate-migrations-models' task to generate the migrations of the diffs (found between the old models on disk and the modified schema file)?
Shouldn't generate-migrations-diff do what generate-migrations-models is supposed to do?
Is there a typo?
Old post Posted by jwage about about 1 year ago.
This post is old and since it was made the task changed. I will update the blog post.
migration Posted by the orm about 11 months ago.
Hi jwage and others,
Im really strugglin with this migration stuff, and im not really sure if doctrine at all is capable of doing what i want it to.
I have an existing solution build in doctrine. It uses 3 models and SQLite database. I have a lot of data!
Now i would like to extend one of my models without loosing all the data in the SQLite database.
I've tried to follow the guides - but never with any luck.
Im using v 1.1.4 on OSX 10.5.8 with MAMP.
Can anyone help?
Thanks!
migration Posted by the orm about 11 months ago.
Hey folks,
I finally got some migration working... not sure if this is the right way to do it, but i worked out for me.
Here is howto.
Having an existing setup, models and db working fine.