CakePHP 4.x: Entityのカラム一覧は、DBのスキーマを参照して取得しており、取得結果は schema_cache としてキャッシュされている

CakePHP の実装

  • 実際のスキーマを元に、Entity 取得時に実行される SQL の SELECT 句に指定するカラム一覧を生成している
  • 上記は schema_cache としてキャッシュされる
    • bin/cake schema_cache clear した上で、Entity を取得した際、カラムの一覧を取得する SQL が実行される事を確認
    • bin/cake schema_cache clear せず、Entity を取得した際、カラムの一覧を取得する SQL が実行されない事を確認
  • migration ファイルで \Migrations\Table::update を実行時に schema_cache が再考構築される
    • これにより、通常は、カラム削除を伴う migration を実行しても問題が起こらない

ハマった事

  • BGデプロイメントで、カラム削除を伴う migration をデプロイした際に、ブルー側で、存在しないカラムを SELECT する SQL が実行されエラーになった
  • why
    • グリーン側で migration を行った後、ブルー側で bin/cake schema_cache clear していなかった為、schema_cache がクリアされず、CakePHP内部のカラム一覧と実際のカラム一覧に差異が生じた
    • 差異により、存在しないカラムを SELECT する SQL が実行された
  • 対策
    • 対象 Table クラスのコンストラクタで $this->getSchema()->removeColumn('対象カラム名') を実行する事で、schema_cache が古くても、「存在しないカラムの SELECT」を回避できる
    • migration のデプロイ前に、予め $this->getSchema()->removeColumn('対象カラム名') をデプロイしておく事で今回のエラーを回避できる
// 対象テーブルクラス

public function __construct(array $config = [])
{
    parent::__construct($config);

    // これにより、 `SELECT 削除予定のカラム, ...` が発生しなくなる
    $this->getSchema()->removeColumn('削除予定のカラム名');
}

ドキュメント

アプリケーションをデプロイする時にプラグインを使用する場合、 テーブルのカラムメタデータを更新するように、必ず ORM キャッシュをクリアしてください。 そうしなければ、それらの新しいカラムの操作を実行する時に、カラムが存在しないエラーになります。