先日、CakePHP を使ったあるプロジェクトで、テーブル定義の変更とデータ移行を行いました。
その際に「マイグレーションファイルからシードを流す」ということをしたかったのですが、この方法がわからず意外と苦戦したのでメモしておきます。
同じ問題に悩む方の助けになれば幸いです。

やりたいこと

cakephp/migrationsプラグインを使って作成したマイグレーションファイルから特定の Seed を実行したい

やったこと

use 句で呼ぶ(失敗)

まず、コントローラやモデルでやるように use 句で呼ぶことを考えました。
ただ、そもそも bake コマンドで作成したマイグレーションファイルやシードファイルには namespace が存在しないため、use することができません。

use Migrations\AbstractMigration;
use Seed\DummySeed; // これができない

class ChangeColumnToTablesAndRecoveryData extends AbstractMigration
{
}

composer.json に namespace を追加することも考えましたが、それだと bake コマンドでファイルを作成するたびに追加する必要があり面倒なので、別の方法を考えることにしました。

CommandRunner で実行する(失敗)

次に、CommandRunner クラスを使うことを考えました。

use App\Application;
use Cake\Console\CommandRunner;
use Migrations\AbstractMigration;

class ChangeColumnToTablesAndRecoveryData extends AbstractMigration
{
    $app = new Application(dirname(__DIR__));
    $runner = new CommandRunner($app);
    $runner->run(['seed', '--seed', 'DummySeed']);
}

ただ、これだと実行時にエラーになりうまくいきませんでした。
もう少しフレームワークのコードを追えば実装できそうでしたが、そこまで頻度が発生するわけではなさそうだったことと、ある程度スピーディーに進める必要があったため、他の方法を探すことにしました。

Seed クラスで実行する(成功)

そもそも、cakephp/migrations プラグインはどうやって実行しているのかが気になり、プラグインのコードを読んでみました。
その結果、以下のようにすれば実行できることがわかりました。

use Migrations\Command\Seed;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\ConsoleOutput;

class ChangeColumnToTablesAndRecoveryData extends AbstractMigration
{
    $seed = new Seed();
    // 戻り値はコマンドの終了コード
    $exitCode = $seed->run(new ArrayInput(['--seed' => 'DummySeed']), new ConsoleOutput());
}

コードもかなりシンプルですし、特殊な実装をせずとも無事実行することができました。

少し前までは Django ばかりでしたが、最近また CakePHP のプロジェクトに関わることが増えてきました。
もうすぐバージョン4も出るようなので、またコミットしていきたいですね。