[CakePHP3] 特定レコードのsave()が失敗する時はsaveOrFail()を使ってみよう

2020/01/26

author

masyus

CakePHP3で実装したsave()がどういうわけかよく失敗することがありました。その際はExceptionもthrowせずにfalseだけを返すため、原因の特定に苦労したことがあります。今回はその解決策を紹介します。

バージョン情報

  • PHP: 7.4.33
  • CakePHP: 3.6.15

save()が頻繁に失敗するケース

save()が失敗してfalseが返ってくるケースでは、

何らかの理由でExceptionがthrowされた結果、falseが返却される

ことが多いです。

個人的に頻繁に遭遇したケースでは、save()を実行したTableクラスにbuildRules()が設定されており、その外部キー制約に引っかかっていた為にExceptionを吐く条件を満たしていたことがありました。具体的には

$rules->add($rules->existsIn('article_id', 'Articles'));

等です。この制約に引っかかりますとPersistenceFailedExceptionがthrowされます。

saveOrFail()を使おう

このようにExceptionをthrowし、その原因を把握できる状態にしたい場合はsave()の代わりにsaveOrFail()を使いましょう。レコードへ保存する処理はsave()と同じですが、

何らかの制約に引っかかった時にExceptionをthrowしてくれる堅実性がある

ため、try-catchで細かくエラーハンドリングしたい時に便利です。

保存処理は基本的にsave()よりもsaveOrFail()を使うのが良いか?

状況次第ではありますが、例えば

  • buildRules()を頻繁に使い、アプリケーションレイヤーで外部キー制約を設定している
  • レコード保存時の失敗理由を細かくログに吐き出したい

等に該当する場合、保存処理は基本的にsaveOrFail()を使うのが良いと思います。そこまで厳密に実装しなくても良い場合はsave()で事足りるかと思います。