CakePHP Migrations Plugin
- Downloads:
- 2015
- Version:
- 1.0.0.0
- Released on:
- 2010-01-11
- Issue Tracker
- Changelog
Subscribe
CakePHP Migrations Plugin
The Migrations plugin provides a comprehensive management system whereby the database schema for a CakePHP project can fluctuate during development involving any number of developers. This is achieved by incrementally managing database changes, providing customisable hooks and callbacks for data migration and changes to meet migration paths, and migration maps to provide flexible application of migration instances.
Migrations is great for any development team, or individual that wants to manage database schema and data changes throughout the development lifetime of a project.
Requirements
CakePHP 1.3 or higher.
If you need a version to use with CakePHP 1.2 please contact us directly.
Related Articles
Overview
- Installation
- Generating Your First Migration
- Generating Schema Diffs
- Generating a New Migration
- Map Files
- Directives
- Directive - Create Table
- Directive - Drop Table
- Directive - Rename Table
- Directive - Create Field
- Directive - Drop Field
- Directive - Alter Field
- Directive - Rename Field
- Console
- Console - Help
- Console - Generate
- Console - Run
Documentation
Installation
Extract the migrations plugin to the app/plugins directory in your application.
The standard directory name is migrations.
Directory Structure
/app
/plugins
/datasources
/debug_kit
/localized
/migrations (Same location as other plugins)
For more information on plugins and app structure, please see the Plugins section of the CakePHP Book.
Generating Your First Migration
The first step to adding migrations to an existing database is to import the database's structure into a format the migrations can work with. Namely a migration file. To create the _first_ migration file run the following command:
cake migration generate This will give us the following prompt:
Cake Migration Shell
---------------------------------------------------------------
Please enter the descriptive name of the migration to generate:
>
Enter in 001 initial migration as the name for the migration and hit return. Since this is the first time you ran this command you will then get the following prompt:
Do you wanna generate a dump from current database? (y/n)
[y] >
Answer y to this question as we want to import the existing database schema into our migrations. This will scan the model paths and import schema for each model found. Once you have been returned to the prompt check app/config/migrations/ for the newly created files. You should see two files in the migrations directory. The first 001_initial_migration is the actual migration containing the table definitions for your database. The second is map.php, this is a special Map file which keeps track of the order of migrations are to be run in. At this point you now have the current database imported into the migration system and can do further schema changes in a regular fashion.
Then the following output will be give as result:
Generating dump from current database...
Generating Migration...
Mapping Migrations...
Done.
Note: If you want import all tables regardless if it has a model or not you can use -f (force) parameter while running the command:
cake migration generate -f Generating Schema Diffs
Once you have Generated your first Migration you will probably do more changes to your database. To simplify the generation of new migration you can do Schema Diffs. To this, you need to follow the steps:
- Generate your first Migration (if haven't generated yet)
- Generate a schema file
- Do changes to your database
- Generate a new migration file
1. Generate your first Migration
As you know, this is the very first step when you install the migrations plugin, for this section read Generating your first Migration
2. Generate a schema file
There is impossible to generate schema diffs across migrations file. So you need to generate a CakeSchema file doing:
cake schema generate
Doing it you will save the current database state.
3. Do changes to your database
Now you can do whatever changes you want to do.
4. Generate a new migration file
Since you Generate a schema file and did some changes to your database, you will be able to compare the schema file to your new database state. By doing it, you will generate a migration file that only contains the difference between the two states.
To generate a new migration file doing this comparison you do:
cake migration generate
This will give us the following prompt:
Cake Migration Shell
---------------------------------------------------------------
Please enter the descriptive name of the migration to generate:
>
Enter in 002 some changes to the database as the name for the migration and hit return. Since there is a schema.php file present in your environment you will then get the following prompt:
Do you wanna compare the schema.php file to the database? (y/n)
[y] >
Answer y to this question as we want to compare the previous database state to the new database state. A new file on app/config/migrations/, named 002_some_changes_to_the_database.php, will be created containing only the difference between the two states.
Then the following output will be give as result:
Comparing schema.php to the database...
Generating Migration...
Mapping Migrations...
Done.
Generating a New Migration
Once you Generated your first Migration and don't want or can't you can generate a regular migration.
Generating migrations is done with the Console.
cake migration generate This will present an interactive console where you can specify the name of the migration, and confirm the schema generation.
Welcome to CakePHP v1.3.0-alpha Console
---------------------------------------------------------------
App : samplemigrations
Path: /samplemigrations
---------------------------------------------------------------
Cake Migration Shell
---------------------------------------------------------------
Please enter the descriptive name of the migration to generate:
> migration title
Do you wanna generate a dump from current database? (y/n)
[y] >
---------------------------------------------------------------
Generating Migration...
Mapping Migrations...
Done.
Map Files
Migrations generates two types of files.
The first is the map.php file, which keeps track of the migrations available, and the order in which they should be processed.
The second is the various migration instances themselves. Depending on the name you choose to give a migration, this filename will change.
map.php
<?php
$map = array(
1 => array(
'initial_schema' => 'M4b040dc7945c4db1b83f26347ff3ec9a'),
);
?>
The map.php file lists all the existing migrations for an application / plugin and is a map between their "public" file name and their "internal" class name.
Migrations are ordered by their creation date, so running cake migration generate will create a migration file placed at the end of the list.
Reordering migrations with the map file
Since the migration map file contains the order migrations are to be run in, reordering migrations in the map file will change the order in which they are executed. Take the following:
<?php
$map = array(
1 => array(
'initial_schema' => 'M4b040dc7945c4db1b83f26347ff3ec9a'),
2 => array(
'added_comment_count' => 'M4b040dc7945c4db1b83f26347fbb1a'),
3 => array(
'added_uploads_table' => 'M5b060dd7846c4cc1a53f26148fa11b'),
);
?>
Now if we wanted to reverse the order the 2nd and 3rd migration are to be run in, we can just re-order the items in the array.
<?php
$map = array(
1 => array(
'initial_schema' => 'M4b040dc7945c4db1b83f26347ff3ec9a'),
2 => array(
'added_uploads_table' => 'M5b060dd7846c4cc1a53f26148fa11b'),
3 => array(
'added_comment_count' => 'M4b040dc7945c4db1b83f26347fbb1a'),
);
?>
The order the migrations will be run in always reflects the order of elements in the $map.
Migration Files
<?php
class M4b040dc7945c4db1b83f26347ff3ec9a extends CakeMigration {
/**
* Migration description
*
* @var string
* @access public
*/
var $description = '';
/**
* Actions to be performed
*
* @var array $migration
* @access public
*/
var $migration = array(
'up' => array(
'create_table' => array(
'ingredients' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'name' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
),
'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM'),
),
'ingredients_recipes' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'ingredient_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
'recipe_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
),
'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM'),
),
'recipes' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'user_id' => array('type' => 'integer', 'null' => false, 'default' => NULL),
'name' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100),
'content' => array('type' => 'text', 'null' => false, 'default' => NULL),
'created' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
'modified' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
),
'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM'),
),
'users' => array(
'id' => array('type' => 'integer', 'null' => false, 'default' => NULL, 'key' => 'primary'),
'name' => array('type' => 'string', 'null' => false, 'default' => NULL, 'length' => 100),
'password' => array('type' => 'string', 'null' => false, 'default' => NULL),
'created' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
'modified' => array('type' => 'datetime', 'null' => false, 'default' => NULL),
'indexes' => array(
'PRIMARY' => array('column' => 'id', 'unique' => 1),
),
'tableParameters' => array('charset' => 'latin1', 'collate' => 'latin1_swedish_ci', 'engine' => 'MyISAM'),
),
),
),
'down' => array(
'drop_table' => array(
'ingredients', 'ingredients_recipes', 'recipes', 'users'
),
),
);
/**
* Before migration callback
*
* @param string $direction, up or down direction of migration process
* @return boolean Should process continue
* @access public
*/
function before($direction) {
return true;
}
/**
* After migration callback
*
* @param string $direction, up or down direction of migration process
* @return boolean Should process continue
* @access public
*/
function after($direction) {
return true;
}
}
?>
This migration file contains all the information describing a migration.
$migration variable
The $migration variable contains two arrays describing actions to perform.
These actions are split into the directions the migration can operate: up or down.
Each set of actions describes schema changes that will be executed either when upgrading to this version or when downgrading from this version.
$description variable
The $description variable contains a readable description of the migration operations.
Callbacks
There are two callbacks that can be implemented: before($direction) and after($direction). These are, as you would expect, called before and after each migration.
The passed parameter $direction indicates whether the migration was up or down. You can use the value this variable to perform different actions on each callback, based on the direction the migration is going.
Callbacks are an ideal place to populate tables or fields with initial data, or to perform data transformations as fields and tables are adjusted through the lifetime of a migration set. Callbacks must return true in order for the migration to run. If either callback returns a non true value the migration will be considered as failed. Returning false from the before() callback is useful when you want to abort the migration based on some conditions, like the ability of the migration to maintain consistent data.
Directives
Introduction
Directives are the key-values that are used in migrations array files to achieve various actions as the migrations run.
These directives are the key to getting the desired results from your migration files.
Directive - Create Table
Details
Name: create_table
Format: array of Tables
Description
Create table is used for the creation of new tables in your database.
Note that migrations will generate errors if the specified table already exists in the database.
Directives exist (Drop, Rename) to deal with existing tables before proceeding with table creation.
Example
'create_table' => array(
'categories' => array(
'id' => array(
'type' =>'string',
'null' => false,
'default' => NULL,
'length' => 36,
'key' => 'primary'),
'name' => array(
'type' =>'string',
'null' => false,
'default' => NULL),
'indexes' => array(
'PRIMARY' => array(
'column' => 'id',
'unique' => 1)
)
),
'emails' => array(
'id' => array(
'type' => 'string',
'length ' => 36,
'null' => false,
'key' => 'primary'),
'data' => array(
'type' => 'text',
'null' => false,
'default' => NULL),
'sent' => array(
'type' => 'boolean',
'null' => false,
'default' => '0'),
'error' => array(
'type' => 'text',
'default' => NULL),
'created' => array(
'type' => 'datetime'),
'modified' => array(
'type' => 'datetime'),
'indexes' => array(
'PRIMARY' => array(
'column' => 'id',
'unique' => 1)
)
)
)
Directive - Drop Table
Details
Name: drop_table
Format: array of table names
Description'
Drop table is used for removing tables from the schema.
Directives exist Create, Rename to handle other table based migration operations.
Example
'drop_table' => array(
'categories',
'emails'
)
Directive - Rename Table
Details
Name: rename_table
Format: array of table names as keys, and new names as values
Description
Changes the name of a table in the database.
Directives exist (Create, Drop) to handle creation and deletion of tables.
Example
'rename_table' => array(
'categories' => 'groups',
'emails' => 'email_addresses'
)
After the successful execution of the above rename_table command, the following will have occurred:
categoriestable will be renamed togroupsemailstable will be renamed toemail_addresses
Directive - Create Field
Details
Name: create_field
Format: array of [Migration Fields](/cakedc/migrations/wiki/migration-fields)
Description
Create Field is used to add fields to an existing table in the schema.
Note that migrations will generate errors if the specified field already exists in the table.
Directives exist (Drop, Rename, Alter) to deal with existing fields before proceeding with field addition.
Example
'create_field' => array(
'categories' => array(
'created' => array(
'type' => 'datetime'),
'modified' => array(
'type' => 'datetime')
)
)
This will result in the addition of a created and modified field to the categories table.
Directive - Drop Field
Details
Name: drop_field
Format: array of table names with field arrays
Description
Drop field is used for removing fields from existing tables in the schema.
Directives exist (Create, Rename, Alter) to handle other field based migration operations.
Example
'drop_field' => array(
'categories' => array(
'created',
'modified'),
'emails' => array(
'error')
)
This example shows the removal of the created and modified fields from the categories table, and the removal of the error field from the emails table.
Directive - Alter Field
Details
Name: alter_field
Format: array of partial Migration Table specifications.
Description
Changes the field properties in an existing table.
Note that partial table specifications are passed, which is a subset of a full array of Table data.
These are the fields that are to be modified as part of the operation.
If you wish to leave some fields untouched, simply exclude them from the Table spec for the alter operation.
Directives exist (Create, Drop, Rename) to handle other field operations.
Example
'alter_field' => array(
'categories' => array(
'indexes' => array(
'NAMES' => false,
'NAME' => array(
'column' => 'name',
'unique' => 0),
)
)
),
This changes the indexes on the categories table.
Directive - Rename Field
Details
Name: rename_field
Format: array of table and field names as keys, and new names as values
Description
Changes the name of a field on a specified table in the database.
Directives exist (Create, Drop, Alter) to handle creation and deletion of fields.
Example
'rename_field' => array(
'categories' => array(
'name' => 'title'
),
'emails' => array(
'error' => 'error_code',
'modified' => 'updated'
),
)
After the successful execution of the above rename_field directive, the following will have occurred:
- name field on the
categoriestable will be renamed totitle - error field on the
emailstable will be renamed toerror_code - modified field on the
emailstable will be renamed toupdated
Console
The Migrations console is the interface into the migrations structure in terms of running, generating and managing your migrations.
There are three commands available that provide all of the migrations functionality:
- Help
- Generate
- Run
Console - Help
The help command displays useful help information to provide assistance in using migrations.
At time of writing, the available help text was the following:
The Migration database management for CakePHP
---------------------------------------------------------------
Usage: cake migration <command> <param1> <param2>...
---------------------------------------------------------------
Params:
-connection <config>
Set db config <config>. Uses 'default' if none is specified.
-plugin
Plugin name to be used
-f
Force 'generate' to compare all tables.
Commands:
migration help
Shows this help message.
migration run <up|down|all|reset|version>
Run a migration to given direction or version.
Provide a version number to get directly to the version.
You can also use all to apply all migrations or reset to unapply all.
migration <generate|add>
Generates a migration file.
To force generation of all tables when making a comparison/dump, use the -f param.
Console - Generate
Generate a new migration
cake migration generate Force migration generation
This is used in the case that you want to generate data for tables without an existing CakePHP model available
cake migration generate -f The -f switch means "force"
Specifying connections
If you wish to use a data source other than that defined on the default connection, specify it with the -connection <name> option:
cake migration generate -connection test This will inspect the connection named test in your app/config/database.php configuration file, and generate migrations based on the information obtained from the datasource.
Console - Run
After generating or being supplied a set of migrations, you can process them to change the state of your database.
This is the crux of the migrations plugin, allowing migration of schemas up and down the migration chain, offering flexibility and easy management of your schema and data states.
Resetting migrations
The reset subcommand of run allows you to reset your schema back to a fresh installation.
cake migration run reset You can also execute this through the interactive console.
This is initiated by running the migration shell with no commands:
cake migration You are immediately shown a list of all migrations, and the date applied, if applied.
You can choose the c options to "clean" the schema.
Downgrade
To revert your database schema to the version previous to the current state, migrate down:
cake migration down Upgrade
Upgrade your database to the next available migration with the following command:
cake migration up Both upgrade and downgrade operations provide output to indicate the process and result of the migration operation.
Any issues will be reported to you in the console.
Migrations for plugins
To apply a migration that is within a plugin, add the -plugin plugin name switch to your command:
cake migration reset -plugin users
cake migration up -plugin users
cake migration down -plugin users