CakePHP 4 のデータベースのマイグレーション機能の使い方

はじめに
開発におけるバージョン管理システムの導入は、もはや当たり前のように思います。
CakePHP 4 にはデータベースのマイグレーション機能が付属しており、ソースコードだけでなくデータベースの変更履歴も簡単に管理することができます。
そのマイグレーション機能は CakePHP Migrationsというプラグインで提供されており、Phinxというライブラリがベースになっています。
- Phinx
- https://phinx.org/
以前「CakePHP 3 のマイグレーション機能でDBから自動で差分取得」でご紹介した CakePHP 3 ではCakePHP Migrations のバージョンは 2.x でしたが、CakePHP 4 からは 3.x が採用されています。
この CakePHP Migrations には、変更差分を自動抽出や、任意の状態への変更、データの入出力など便利な機能が搭載されています。
今日は僕がよく使っている CakePHP 4 のデータベースのマイグレーション機能の使い方(コマンド)をご紹介します。
今回は Windows で動作確認をしていますが Mac でも同様に動きます。
以下で参考ページとして紹介している CakePHP Migrations 3.x Cookbook ですが、まだ制作途中で不完全なところがあるようです。参照される場合はご注意ください。
- CakePHP
- 4.0.8
- CakePHP Migrations
- 3.0.0
- Phinx
- 0.12.1
- PHP
- 7.4.5
- MariaDB
- 10.4.11
1. 下準備
今回はこのテーブルを例にご説明します。
CREATE TABLE drinks (
id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
name varchar(255) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
INSERT INTO drinks (id, name) VALUES
(1, 'コーラ'),
(2, 'ジンジャーエール'),
(3, 'サイダー');
2. 構造出力: 初回(既存の全テーブル)
既存データベースの全テーブルの構造をエクスポートしたい場合には bake migration_snapshot を使います。
下記の Initial の部分は好きな名前で OK です。
> bin/cake bake migration_snapshot Initial
型が TINYINT で長さが 2 以上のフィールドがある場合は変更が必要です。
下記「TINYINT 型の調整」をご確認ください。
上記コマンドを実行すると、/config/Migrations/20200621123456_Initial.php のようなファイルが生成され、この中に構造の変更情報が記載されています。
同フォルダに schema-dump-default.lock も作成されますが、このファイルはデータベースの構造が記録されるもので、エクスポートする度に更新されます。
データベースには phinxlog テーブルが追加されます。ここにはマイグレーションに関する情報が格納されますが、このテーブルはマイグレーション対象にはなりません。
- Generating migrations from an existing database (CakePHP Migrations 3.x Cookbook)
- https://book.cakephp.org/migrations/3/en/index.html#generating-migrations-from-an-existing-database
3. 構造出力: 差分
本題に入る前に、上記サンプルテーブルを作られた方は、下記変更を加えてから読み進めてください。
ALTER TABLE drinks ADD price TINYINT(3) UNSIGNED NULL DEFAULT NULL AFTER name;
さて、テーブルへの変更差分は bake migration_diff で抽出できます。
> bin/cake bake migration_diff AddPriceToDrinks
AddPriceToDrinks の部分は状況に応じて分かりやすい名称を付けてください。
サンプルテーブルのように、長さが 2 以上の TINYINT 型がある場合はこのままでは使えず、次に説明する変更が必要になりますので、ご注意ください。
今回の例では /config/Migrations/20200621234512_AddPriceToDrinks.php のようなファイルがつくられ、 schema-dump-default.lock が更新されます。
- Generating a diff between two database states (CakePHP Migrations 3.x Cookbook)
- https://book.cakephp.org/migrations/3/en/index.html#generating-a-diff-between-two-database-states
4. 構造出力: TINYINT 型の調整
型が TINYINT で長さが 2 以上のフィールドがあるテーブルを扱う場合は、マイグレーションファイルを下記のように変更する必要があります。
<?php
declare(strict_types=1);
use Migrations\AbstractMigration;
use Phinx\Db\Adapter\MysqlAdapter; // ← 追加
class AddPriceToDrinks extends AbstractMigration
{
public function up()
{
$this->table('drinks')
->addColumn('price', 'integer', [ // ← integer に変更
...
'length' => MysqlAdapter::INT_TINY, // ← INT_TINY を指定
...
])
->update();
}
...
}
この変更をしないと、変更適用時に「InvalidArgumentException: An invalid column type "tinyinteger" was specified for column "price".」のようなエラーが出るのでご注意ください。
以前は SMALLINT でもエラーが出たのですが、現バージョンでは出ないようです。
もし出た場合には同様に、addColumn の第2引数を integer にして、
length を MysqlAdapter::INT_SMALL にすれば大丈夫だと思います。
- Limit Option and MySQL (Phinx 0.x Cookbook)
- https://book.cakephp.org/phinx/0/en/migrations.html#limit-option-and-mysql
5. 構造の変更適用
最新のマイグレーションまで適用するためには、下記のように migrations migrate を実行します。コマンドに bake が含まれないのでご注意ください。
bake はファイル出力するときだけ使う、と覚えておくと良いかもしれません
> bin/cake migrations migrate
任意の箇所まで適用したいときは -t オプションをつけて、指定したいファイル名の先頭にあるタイムスタンプ部分を入力します。
# 20200621123456_Initial.php だけを適用したい場合
> bin/cake migrations migrate -t 20200621123456
- migrate : Applying Migrations (CakePHP Migrations 3.x Cookbook)
- https://book.cakephp.org/migrations/3/en/index.html#migrate-applying-migrations
6. ロールバック
過去の状態に戻したい場合には migrations rollback を使います。
こちらもコマンドに bake は含まれません。
下記のようにオプションを何もつけずに実行すると、1つ前の状態に戻ります。
# 1つ前の状態に戻したい場合
> bin/cake migrations rollback
任意の箇所に戻すには、オプション -t をつけて、戻したいファイル名の先頭にあるタイムスタンプ部分を入力します。
# 20200621123456_Initial.php に戻したい場合
> bin/cake migrations rollback -t 20200621123456
- rollback : Reverting Migrations (CakePHP Migrations 3.x Cookbook)
- https://book.cakephp.org/migrations/3/en/index.html#rollback-reverting-migrations
7. データを Seed ファイルに出力
登録されているデータをファイルに出力する場合は bake seed を使います。
下記では drinks テーブルのデータを抽出しています。
> bin/cake bake seed --data Drinks
上記コマンドを実行すると /config/Seeds/DrinksSeed.php が作られます。このファイルがある状態で、再度上記コマンドを実行すると上書きするかの確認が出ますので、差支えがなければ「y」を押してください。
File `\path\to\cakephp4\config\Seeds\DrinksSeed.php` exists
Do you want to overwrite? (y/n/a/q)
[n] >
- seed : Seeding your database (CakePHP Migrations 3.x Cookbook)
- https://book.cakephp.org/migrations/3/en/index.html#seed-seeding-your-database
8. Seed ファイルからデータ入力
Seed ファイルからデータを入力するには migrations seed コマンドを使います。
下記コマンドを実行すると、すべての Seed ファイルからデータをインポートします。インポートする前には当該テーブルを空にしてください。(ID 重複によるエラーや、データの重複が生じます)
> bin/cake migrations seed
任意の Seed だけを入力したい場合には --seed オプションが使えます。ここで指定するのは Seed ファイル名です。
> bin/cake migrations seed --seed DrinksSeed
テーブルで utf8mb4 を使っていてる場合は app.php を下記のように変更しないと、インポート時に文字化けすると思います。
'Datasources' => [
...
'default' => [
...
// 下記のように変更
// (初期ではコメントアウトされている)
'encoding' => 'utf8mb4',
- seed : Seeding your database (CakePHP Migrations 3.x Cookbook)
- https://book.cakephp.org/migrations/3/en/index.html#seed-seeding-your-database
9. おわりに
マイグレーション機能を使う前までは、ダンプファイルと差分の SQL を使って開発をしていたのですが、使い始めると本当に便利だなと思います。
特に CakePHP の機能で強力だと思うのが、データベースから構造の差分を自動で出力できるところです。
コマンド入力に不慣れな方は億劫に感じるかもしれませんが、それを乗り越えてでも使う価値があると思います。
是非、導入してみてください。