CakePHP3.xのマイグレーションを試してみる

/

導入

WebアプリケーションのフレームワークではデータベースにSQLがよく使われていますが、多くのフレームワークでは直接SQLコマンドを実行せずにマイグレーション機能を使ってフレームワーク側からデータベースを管理する事が出来ます。

CakePHPにもマイグレーション用のプラグインが用意されているので、実際にアプリケーションを開発していく前にCakePHPのマイグレーション機能を試してみました。

VagrantにCakePHP ver3.3をインストールする/Koltatt
CakePHPのデーターベース設定/Koltatt
CakePHP3.xを組み込みサーバーとSQLiteで起動する。/Koltatt

実行環境

  • ubuntu 16.04
  • CakePHP 3.3
  • SQLite3

マイグレーション

CakePHPではMigrationプラグインを利用することで、SQLコマンドを使用せずにPHPで書いたソースコードによってデーターベースのスキーマを変更する事が出来ます。

またマイグレーションでは実行する内容が記述されたファイルを元にデータベースへの処理が行われるため、実行した処理が履歴として残る事になるのでGitなどのバージョン管理システムのようにデーターベースの編集内容を後から簡単に追跡する事が出来るようになります。

Migrations – Cake PHP Cook Book

Phinx

CakePHPのMigrationプラグインはPHPのデータベースマイグレーションライブラリであるPhinx のラッパーとして実装されています。そのためマイグレーションファイルで利用できるメソッド等はPhinxのドキュメントを参照する事が出来ます。

インストール

MigrationプラグインはCakePHPのアプリケーション作成時にデフォルトでインストールされています。
マイグレーションプラグインを利用するにはconfig/bootstrap.phpからプラグインがロードされている必要があります。

Plugin::load('Migrations');

マイグレーションファイル

CakePHPでマイグレーションを実行するには、実行内容の元となるマイグレーションファイルが必要です。
マイグレーションファイルはCakePHPアプリケーションのconfig/Migration以下に置かれます。

マイグレーションファイルの作成

マイグレーションファイルはbakeコマンドで作成する事が出来ます。

bakeコマンドによるマイグレーションファイルの作成は以下の規約に従うことで、あらかじめ指定した処理が記述された状態で作成する事が出来ます。

マイグレーションファイル名
マイグレーション名は下記のパターンに従うことができます。

(/^(Create)(.*)/) 指定したテーブルを作成します。
(/^(Drop)(.*)/) 指定したテーブルを削除します。フィールドの指定は無視されます。
(/^(Add).*(?:To)(.*)/) 指定したテーブルにカラム追加します。
(/^(Remove).*(?:From)(.*)/) 指定のテーブルのカラムを削除します。
(/^(Alter)(.*)/) 指定したテーブルを変更します。 CreateTable と AddField の別名。
マイグレーションの名前に アンダースコア_形式 を使用できます。例: create_products
Migration – CakePHP

# Blogテーブルの作成を指定
$ bin/cake bake migration CreateBlog

bakeコマンドが実行されるとタイムスタンプが記入されたマイグレーションファイルが作成されます。

<?php
use Migrations\AbstractMigration;

class CreateBlog extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('blogs');
        $table->create();
    }
}

テーブルの作成時にカラムを同時に作成する事も出来ます。

$ bin/cake bake migration CreateBlog title:string created: datetime modified: datetime
<?php
use Migrations\AbstractMigration;

class CreateBlog extends AbstractMigration
{
    public function change()
    {
        $table = $this->table('blogs');
        $table->addColumn('title', 'string', [
            'default' => null,
            'limit' => 255,
            'null' => false,
        ]);
        $table->addColumn('created', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->addColumn('datetime', 'string', [
            'default' => null,
            'limit' => 255,
            'null' => false,
        ]);
        $table->addColumn('modified', 'datetime', [
            'default' => null,
            'null' => false,
        ]);
        $table->create();
    }
}

マイグレーションの実行

マイグレーションファイルを作成しただけではデータベースの内容はまだ変更されていないので、ターミナルからコマンドを実行してマイグレーションファイルの内容をデータベースに反映させます。

# マイグレーションを全て適用
$ bin/cake migrations migrate

マイグレーションのステータスの表示

statusコマンドでアプリケーションに適用されたマイグレーションファイルのリストを確認する事が出来ます。

$ bin/cake migrations status

 Status  Migration ID    Migration Name 
-----------------------------------------
     up  20161207042909  CreateBlog 

「CreateBlog」のStatusがupになっているのが確認出来ます。

SQLite3

アプリケーションからマイグレーションが実行出来たのでデータベースを直接参照してみると、マイグレーションファイルで指定した内容が実際にデータベースに反映されている事が確認出来ます。

$ sqlite3 app.sql
# テーブルの一覧の表示
$ .table
blogs phinxlog

# blogsテーブルのスキーマを表示
$ .schema blogs
CREATE TABLE `blogs` (`id` INTEGER NULL PRIMARY KEY AUTOINCREMENT, `title` VARCHAR(255) NULL, `created` DATETIME NULL, `datetime` VARCHAR(255) NULL, `modified` DATETIME NULL);

マイグレーションファイルの追加

カラムの追加

bakeコマンドではテーブルの新規作成だけではなく、既存のテーブルに新たにカラムを追加するマイグレーションファイルを作成する事も出来ます。

bin/cake bake migration AddBodyToBlog body:text

フィールドの長さの指定

カラムの追加時に[]で値を指定するとフィールドの長さの上限を設定する事が出来ます。

bin/cake bake migration AddDescrtiptionToBlog description:string[200]
$ bin/cake migrations migrate
$ bin/cake migrations status

 Status  Migration ID    Migration Name 
-----------------------------------------
     up  20161207042909  CreateBlog            
     up  20161207043353  AddBodyToBlog         
     up  20161207043529  AddDescrtiptionToBlog
$ sqlite3 app.sql
.schema blogs

# descriptionにフィールドの長さが指定されている。
CREATE TABLE `blogs` (`id` INTEGER NULL PRIMARY KEY AUTOINCREMENT, `title` VARCHAR(255) NULL, `created` DATETIME NULL, `datetime` VARCHAR(255) NULL, `modified` DATETIME NULL, `body` TEXT NULL, `description` VARCHAR(200) NULL);

ロールバック

ロールバックを実行する事でデータベースに適用されたマイグレーションファイルの内容を以前の状態に戻すことが出来ます。

# マイグレーションを一つ前の状態に戻す
$ bin/cake migrations rollback

$ bin/cake migrations status

# AddDescrtiptionToBlogのStatusがdownになっている
 Status  Migration ID    Migration Name 
-----------------------------------------
     up  20161207042909  CreateBlog    
     up  20161207043353  AddBodyToBlog 
   down  20161207043529  AddDescrtiptionToBlog

対象のファイルを指定してのロールバック

ロールバックは任意のマイグレーションファイルを指定して実行する事も出来ます。

# 全てのマイグレーションを適用
$ bin/cake migrations migrate
# マイグレーションのバージョン番号を指定してロールバックを実行
$ bin/cake migrations rollback -t 20161207042909

$ bin/cake migrations status

# 指定したバージョンの状態までマイグレーションが戻っている
 Status  Migration ID    Migration Name 
-----------------------------------------
     up  20161207042909  CreateBlog 
   down  20161207043353  AddBodyToBlog 
   down  20161207043529  AddDescrtiptionToBlog 

要素の削除

Migrationプラグインでは既に作成した要素をデータベースから取り除きたい時には既存のマイグレーションファイルを削除するのではなく、要素の削除を実行する内容のマイグレーションファイルを新たに作成してマイグレーションを実行します。

カラムの削除

カラムを削除するマイグレーションファイルを作成して、データベースに存在するカラムを削除します。

$ bin/cake bake migration RemoveBodyFromBlog body
$ bin/cake migrations migrate

$ sqlite3 app.sql
.schema blogs

# テーブルからbodyが削除されている
CREATE TABLE `blogs` (`id` INTEGER NULL PRIMARY KEY AUTOINCREMENT, `title` VARCHAR(255) NULL, `created` DATETIME NULL, `datetime` VARCHAR(255) NULL, `modified` DATETIME NULL, `description` VARCHAR(200) NULL);

テーブルの削除

カラム同様にテーブルを削除する事も出来ます。

$ bin/cake bake migration DropBlog
$ bin/cake migrations migrate

$ sqlite3 app.sql
# テーブル一覧の表示
$.tables

# blogsテーブルが削除されている
phinxlog

あとがき

Webアプリケーションにおいてデータベースは重要な要素の一つなので、アプリケーションの開発が複数の開発者で行われたり開発と保守が別の人によって行われる事を考えるとデータベースに行った処理の記録を残すことは非常に重要だと思います。

また以前CakePHPの開発環境用のデータベースとしてSQLiteを設定してみましたが、MySQL等とSQLiteでは使えるコマンドや文法が微妙に違っていてSQLを直接操作するとなると環境毎にその都度調整が必要になってしまいますが、今回試した限りではマイグレーションプラグインを使えば上手く処理してくれるようなのでデータベースの操作はフレームワーク側で管理したほうがデプロイ作業もスムーズに実行出来るようです。

参照

Migration – CakePHP