An introduction to database migrations in Yii
If you’re new to Yii migrations, these sources might be a help for you:
- General information: Database Migration topic in The Definitive Guide to Yii.
How to create initial migration basing on current database state, explains this Stack Overflow question and GitHub Gist (with
InitialDbMigrationCommand
class’ code) to support it.
To use migrations, you have to properly configure console version of your Yii application. Details follows.
Configuring and tweaking up migrations system
For using migrations, you need to setup correctly console configuration. In particular, you need do define correct database connection — that is the db
element of components
group in your console application configuration file (usually console.php
). In most cases, your db
component will be exactly the same as in case of regular application configuration, unless you need to use different database connection or configuration for executing console commands.
By default, all your migrations will be stored in tbl_migration
table. If you want to change this (for example to just migrations
, to match names of your other tables) you need to override migrate
command in commandMap
group, in console application configuration, like this:
'commandMap'=>array
(
'migrate'=>array
(
'class'=>'system.cli.commands.MigrateCommand',
'migrationPath'=>'application.migrations',
'migrationTable'=>'migrations',
'connectionID'=>'db'
)
)
Put this into main array of your console application configuration and migrations in your application should now start using non-standard table name.
Using migrations
The very basic idea, is to do following after each git pull
:
cd protected
yiic migrate
And then hit Y
to run all migrates from current point to the newest migration.
Above is an equivalent of yiic migrate up
. So, you can expect, that executing yiic migrate down
will do something exactly opposite, that is — run all migrations from current point to the very bottom (to the initial migration), executing their down()
or safeDown()
(see below) methods to revert all the changes done by each of these migrations.
Running yiic migrate redo
will do a redo operation, which is an execution of down()
or safeDown()
method followed by execution of up()
or safeUp()
method.
You can also execute yiic migrate up N
, yiic migrate down N
or yiic migrate redo N
to force yiic
to run up, down or redo N
migrations from current point.
Some resources:
- If you need to run single migration, that is not the current one, here is a solution on how to do this.
- You may consider linking
yiic migrate
command as post-pull hook to be executed automatically, after eachgit pull
. Or running it periodically via CRON. Interested? Then this link and that one maybe useful for you. - If you need to run migrations stored inside your modules you can use this method or install
migrate-command
extension, which offers this (and many more) functionalities.
Note, however, that even though storing migration commands in modules is an interesting idea to provide full module separation, you should consider it twice, as it is not suggested one method (you should keep all your migrations in protected/migrations
folder).
Creating new migration
Execute yiic migrate create NAME
to create new migration with a given NAME
. A file named DATE_TIME_NAME.php
will be created, containing DATE_TIME_NAME
class inside, a descent (extension) of CDbMigration
class and prefilled with empty up()
and down()
methods.
Write your code, add some coments, test and deploy. Voila!
Note, that Yii migrations system (CDbMigration) offers two types of methods — up()
plus down()
and safeUp()
plus safeDown()
. Second set differs from first one only in that it is run as transaction and rolled back entirely, if any part of migration fails. Keep in mind, that CDbMigration always runs ONLY ONE sets of commands, either standard or “safe” one; never both of them. You have to decide, if you want particular migration to be run directly or enclosed entirely inside a transaction. To workaround this problem, you can also, split particular operation into two migrations, one run directly and one enclosed in a transaction.
In a very rare situation, where you would really have to combine transaction-based and transaction-less command in one migration, you can use dbConnection
property, which returns the currently active database connection (a CDbConnection
object), and start a transaction through it. An example of this is given in an introduction to CDbConnection
and includes something like this:
$transaction = $connection->beginTransaction();
try
{
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
$transaction->commit();
}
catch(Exception $e)
{
$transaction->rollback();
}
Put this into your up()
or down()
method to separate part of SQL statements into a transaction.