Migrations Plugin for CakePHP

19th June, 2012 @ Pollenizer HQ

About me

Simon Males

Platform Engineer at Pollenizer

- sime.net.au / @simonmales

Purpose

  • Version schema changes
  • Stop changing production database by hand
  • Bring more developers to the party

Inspiration

Migrations Plugin for CakePHP by CakeDC

Installation

First get the plugin!


$ cd app/Plugin
$ git clone git://github.com/CakeDC/migrations.git
$ rm -rf app/Plugin/migrations/.git # Optional
					

Add the following to app/Config/bootstrap.php


CakePlugin::load('Migrations');
					

Installation

Confirm installation with the CakePHP shell


$ app/Console/cake

Available Shells:

migration [Migrations]
					

First migration


$ app/Console/cake Migrations.migration generate -f

Cake Migration Shell
---------------------------------------------------------------
Do you want generate a dump from current database? (y/n)
[y] > y
---------------------------------------------------------------
Generating dump from current database...
Do you want to preview the file before generation? (y/n) 
[y] > y
Please enter the descriptive name of the migration to generate:  
> InitialMigration
Generating Migration...

Done.

					

The above assuming you database.php is setup and working

Migration file

Migration file is generated!


$ cat app/Config/Migration/1339635086_initial.php
					

Migration table

Migration table is generated!


mysql> SELECT * FROM schema_migrations;
+----+----------------------------+------------+---------------------+
| id | class                      | type       | created             |
+----+----------------------------+------------+---------------------+
|  1 | InitMigrations             | Migrations | 2012-06-14 10:50:34 |
|  2 | ConvertVersionToClassNames | Migrations | 2012-06-14 10:50:34 |
|  3 | IncreaseClassNameLength    | Migrations | 2012-06-14 10:50:34 |
|  4 | Initial                    | app        | 2012-06-14 10:51:26 |
+----+----------------------------+------------+---------------------+
4 rows in set (0.00 sec)

					

Important: Schema File

'Master' version of the schema, used for local comparison


$ app/Console/cake schema generate -f
Cake Schema Shell
---------------------------------------------------------------
Generating Schema...
Schema file: schema.php generated
					

Only need to do this on initial migration, the plugin handles it from here on


$ cat app/Config/Schema/schema.php
					

Let's drop stuff


$ app/Console/cake Migrations.migration reset

Cake Migration Shell
---------------------------------------------------------------
Running migrations:
  [1339635086] 1339635086_initial
      > Dropping table posts.
      > Dropping table users.

All migrations have completed.

					

mysql> show tables;
+----------------------+
| Tables_in_migrations |
+----------------------+
| schema_migrations    |
+----------------------+
1 row in set (0.00 sec)

					

Back to life


$ app/Console/cake Migrations.migration all

Cake Migration Shell
---------------------------------------------------------------
Running migrations:
  [1339635086] 1339635086_initial
      > Creating table posts.
      > Creating table users.

All migrations have completed.

					

mysql> show tables;
+----------------------+
| Tables_in_migrations |
+----------------------+
| posts                |
| schema_migrations    |
| users                |
+----------------------+
3 rows in set (0.00 sec)
					

New schema!

New table: roles


mysql> CREATE TABLE `roles` (
  `id` int(11) NOT NULL,
  `name` varchar(45) DEFAULT NULL,
  `created` varchar(45) DEFAULT NULL,
  `modified` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
					

New schema: roles


$ app/Console/cake Migrations.migration generate -f

Cake Migration Shell
---------------------------------------------------------------
Do you want compare the schema.php file to the database? (y/n)
[y] > y
---------------------------------------------------------------
Comparing schema.php to the database...
Do you want to preview the file before generation? (y/n)
[y] > y
Please enter the descriptive name of the migration to generate:
> Roles
Generating Migration...

Done.
Do you want update the schema.php file? (y/n)
[y] > y

Welcome to CakePHP v2.1.3 Console
---------------------------------------------------------------
App : app
Path: /Users/simonmales/Development/migrations/app/
---------------------------------------------------------------
Cake Schema Shell
---------------------------------------------------------------
Generating Schema...
Schema file exists.
 [O]verwrite
 [S]napshot
 [Q]uit
Would you like to do? (o/s/q)
[s] > o
Schema file: schema.php generated

					

What?

  • Compare you database to current schema.php
  • Generate 'Roles' migration
  • Overwrite schema.php

Hooks

But I need some rows!

Let's bake


$ app/Console/cake bake Model Role
					

Take advantage of the after hook in roles migration


// File: app/Config/Migration/1339636753_roles.php
public function after($direction) {
	if ($direction == 'up') {
		$this->Role = ClassRegistry::init('Role');
		$data = array (
			array('id' => 1, 'name' => 'Admin'),
			array('id' => 2, 'name' => 'User')
		);
		$this->Role->saveAll($data);
	}
	return true;
}

					

Look ma no hands!


$ app/Console/cake Migrations.migration down
$ app/Console/cake Migrations.migration up
					

mysql> SELECT * FROM roles;
+----+-------+------------+------------+
| id | name  | created    | modified   |
+----+-------+------------+------------+
|  1 | Admin | 1339637668 | 1339637668 |
|  2 | User  | 1339637668 | 1339637668 |
+----+-------+------------+------------+
2 rows in set (0.00 sec)

					

Rules

  • Never edit a commited/pushed migration
  • Run 'migrations all' prior to generating new migration

Pro tip

Git

Update .gitignore from:


/app/Config/
					

To:


/app/Config/database.php
					

But you can brew you own solution

Deployment

Do it!

Capistrano


after "deploy:update_code", :roles => :app do
  # Execution migrations
  run "#{release_path}/app/Console/cake -app #{release_path}/app/ Migrations.migration all"
end
					

THE END

BY Simon Males / @pollenizer