CakePHPでデータベースのカスタムバリデーションが動かないときはnewEntityかpatchEntityを使っているか確認する

執筆日:
この記事の目次
chevron_right 事象
chevron_right 解決方法
chevron_right 改善例
chevron_right 参考

事象

CakePHPで、カスタムバリデーションが動作しない自体が発生しました。
コードを追いかけると以下のようなコードでした(元のコードを元にサンプル作成)

// 記事を公開するかどうか
$isPublish = $this->request->getData('is_publish');

// 該当記事のEntityを取得
$articles = $this->Articles->get($page);

// 公開・非公開の情報をEntityにセット
$articles->is_publish = $isPublish;

// DBに保存
$this->Articles->save($articles);

一見間違いなさそうに見えますが、CakePHPでは、newEntityまたはpatchEntity実行時にしかカスタムバリデーションが発火しないとのこと。

解決方法

CakePHPでは、newEntityまたはpatchEntity実行時にしかカスタムバリデーションが発火しないので、上記のコードをnewEntityまたはpatchEntityを使って更新してあげればOKでした。

改善例

// 記事を公開するかどうか
$isPublish = $this->request->getData('is_publish');

// 該当記事のEntityを取得
$articles = $this->Articles->get($page);

// DBに保存
$articleEntity = $this->Articles->patchEntity($articles, ['is_publish' => $isPublish]);
$this->Articles->save($articleEntity);

他のバリデーションが邪魔をする場合

単純にバリデーションがかかっているならいいのですが、
例えば「記事のタイトルが必須」などの条件が含まれている場合、上記のコードでは

cakephp patchEntity This field is required

のようなエラーが発生します。

これは、newEntityまたはpatchEntity実行時にバリデーションが実行されるので、更新項目にタイトルが含まれていないから起こります。
このような場合は、全データを追加してあげることで回避できそうです。

// 記事を公開するかどうか
$isPublish = $this->request->getData('is_publish');

// 該当記事のEntityを取得
$articles = $this->Articles->get($page);

// 全データを配列に
$articleArray = $articles->toArray();

// 更新したい要素を上書きする
$articleArray['is_publish'] = $isPublish;

// DBに保存
$articleEntity = $this->Articles->patchEntity($articles, $articleArray);
$this->Articles->save($articleEntity);

以上です

参考

おすすめの本
この記事を書いた人
Nな人(えぬなひと)。
Nは本名から取っています。
Laravelが大好きなPHPerで、WEBを作るときはLaravelを技術スタックに絶対推すマン。
PHP、Pythonと、昔はperlを書いていたP言語エンジニア。
最近はNimを書いたりしています。