CakePHP などを利用してサーバサイドプログラムを実装する場合、DB に値を保存したり登録することが多々あります。システムの変更にともない DB のカラムやテーブルを修正したり追加したりするのですが、この際きちんと履歴をコマンドベースで保存しておかないと、他の環境への反映や別の開発者の環境へ修正を反映する際に分からなくなってしまい、管理が煩雑になってしまいます。
上記を解決するため、CakePHP3 に標準で組み込まれた Migration の機能を利用して、データベースの変更のバージョン管理を行う方法を記述します。
空のマイグレーションファイルの作成
初期からマイグレーション前提で実施しておくと後でやりやすくなるので、最初から開発環境にて空のマイグレーションファイルを作成します。
CakePHP3 は、デフォルトでマイグレーションに Phinx を利用します。したがって、CakePHP3 のマニュアルに書いてある内容以外にも Phinx のマニュアルを参照することで色々できることの幅は広がりますが、なるべく CakePHP3 のマニュアルにしたがって統一性をもたせることにしました。まずは以下のコマンドを実行して空のマイグレーションファイルを作成します。
# ローカルの開発環境内、app ディレクトリに移動
cd /usr/share/nginx/html/サイト名/app/
bin/cake bake migration Initial
これで以下ディレクトリに日付 + 時間 + _Initial.php という空のマイグレーションファイルが作成されます。
# 書き出されるファイル
app/config/Migrations/YYYYmmddHHiiss_Initial.php
マニュアルには完全にコントロールしたい場合、以下コマンドを利用できると書いてありましたが、今回は利用を避けました。このコマンドを実行した場合は、作成されるファイル名がキャメルケースではなくアンダースコアケースになってしまうことと、作成されたファイルのクラスが CakePHP が準備した抽象クラスではなく Phinx の抽象クラスから継承されたためです。
# CakePHP の抽象クラスを継承
bin/cake bake migration Initial
# Phinx の抽象クラスを継承
bin/cake migrations create Initial
マイグレーションファイルの中身を記述
空のマイグレーションファイルを作成したので、内容を記述します。今回は例としてお問い合わせフォーム用テーブルを作成する内容を記述しました。
use Migrations\AbstractMigration;
class Initial extends AbstractMigration
{
public $autoId = false;
public function change()
{
$this->table('contacts')
->addColumn('id', 'uuid')
->addColumn('name', 'string', ['limit' => 128])
->addColumn('email', 'string')
->addColumn('message', 'text')
->addColumn('created', 'datetime', ['null' => true])
->addColumn('modified', 'datetime', ['null' => true])
->addPrimaryKey(['id'])
->create();
}
}
上記内容の解説を以下に記述します。ご存知の方はスキップしても問題ありません。
1 行目 – use Migrations\AbstractMigration;
CakePHP3 が準備した抽象クラスを継承するため、CakePHP3 のクラスをインポートします。Phinx のクラスでないことを確認してください。継承するクラス名はCakePHP, Phinx ともに同じクラス名なので気づかずにうまく動作せず困ってしまうことがあります。
# CakePHP の抽象クラスをインポート
use Migrations\AbstractMigration;
# Phinx の抽象クラスをインポート
use Phinx\Migration\AbstractMigration;
6 行目 – public $autoId = false;
Phinx はデフォルトでテーブルの作成時に id カラムを auto_incriment の primary_key として自動付与します。今回は CakePHP の uuid を id に使いたかったのでこれを指定しました。
8 行目 – public function change()
ここの中にテーブルの作成やカラム追加などを記述します。今回はテーブル作成のみ記述しました。なお、change() の他に up(), down() で記述する方法もありますが、bake した場合は change() が書き出されました。これは up() と down() をともに併せ持つメソッドで migrate や rollback で自動的に何を実行するのか、何を元に戻すのかが判断されます。
# 自動判断される
change(){
}
# 自分で制御する
up(){
}
down(){
}
テーブルの作成は rollback する場合、テーブルの破棄しかないので今回は bake された change() を利用しました。自動で判断ができないものを記述する場合には change() メソッドを削除してup(), down() メソッドをそれぞれ自分で記述する必要があります。Phinx のマニュアルに共存できないと記載されていますので、共存させないことをお勧めします。
10 行目 – $this->table(‘contacts’)
操作するテーブルを指定します。今回は contacts テーブルを作成したいのでこのように記述しました。
11 行目以降 – ->addColumn(name, type, options)
addColumn メソッドは、1 つ目の引数にカラム名、2 つ目の引数にタイプ、3 つ目の引数に配列でオプションを渡します。オプションはデフォルトで以下になります。
$options = [
'null' => false,
'limit' => それぞれのタイプに応じたもの
]
11 行目 – ->addColumn(‘id’, ‘uuid’)
id には CakePHP が準備している uuid を利用したいので、このように指定しました。uuid は char(36) の文字列で重複が発生しないものです。今回は特に理由がありませんが、使いたかったのでこれにしました。
12 行目 – ->addColumn(‘name’, ‘string’, [‘limit’ => 128])
タイプに string を渡すと VARCHAR 型、オプションで limit を渡しているので、長さ 128 になります。
13 行目 – ->addColumn(‘email’, ‘string’)
タイプに string を渡すと VARCHAR 型、オプションで limit 渡していないので、デフォルトの長さ 255 になります。
14 行目 – ->addColumn(‘message’, ‘text’)
タイプに text を渡すとデフォルトで TEXT 型、オプションで limit 渡していないので、長さ制限の指定なしになります。
15, 16 行目 – ->addColumn(‘created’, ‘datetime’, [‘null’ => true])
タイプに datetime を渡すとデフォルトで DATETIME 型、オプションで null が true と渡しているので null が許可されます。
18 行目 – ->addPrimaryKey([‘id’])
6 行目に自動判断を拒否したので、明示的に自分でどのカラムが主キーなのか指定します。
19 行目 – ->create();
テーブルを作成するので今回は create() を指定しました。
マイグレーション、ロールバックの実行
マイグレーションファイルの保存が完了したら実行します。以下コマンドを実行して無事テーブルが作成されたり破棄されたりすることを確認してください。
cd appディレクトリ
# マイグレーションの実行、今回はテーブルが作成される
bin/cake migrations migrate
# マイグレーションのロールバック、今回はテーブルが削除される
bin/cake migrations rollback
本番環境に反映
マイグレーションの実行に問題ないことを確認したら、マイグレーションファイルを git 管理に加え、それを本番環境に反映して先ほどと同じコマンドを実行してテーブルを作成してください。これで DB をファイル管理し、開発環境から本番環境に反映することができました。複数人開発を行う場合は他の開発者の環境で同様のコマンドを実行すればその方の開発環境にもテーブルが作成されます。
補足: 直接DBを変更してマイグレーションファイルに変更内容を書き出す
CakePHP2 系では、直接 DB を操作してそれをマイグレーションファイルに書き出す方法がありました。CakePHP3 系でも同じようにできますが、まだ完璧とはいえなかったので、最後に補足として記述しておきます。書き出されたファイルを修正して期待通りの動作を確保してください。
# MigrationFileName は書き出されるマイグレーションファイルの名前
bin/cake bake migration_diff MigrationFileName
終わりに
このような形で、修正内容の様々な環境への反映はコードベースで行えるようになりました。何か不明点があれば、お問い合わせよりご質問ください。
Enjoy!!