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

2020/01/26

author

masyus

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

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

save()が失敗してfalseが返ってくる場合、実際には

Exceptionをthrowする条件が満たされている

ことが多いです。

個人的に頻繁に直面したケースとしては、save()しようとしたEntityに該当するTableにbuildRules()が設定されており、その外部キー制約に引っかかっていた為にExceptionを吐く条件を満たしていたことがありました。一例ですが、保存しようとするEntityに該当するTableクラスにbuildRules()として

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

等が実装されている時は要注意です。PersistenceFailedExceptionがthrowされる可能性があります。

saveOrFail()を使おう

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

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

ので便利です。

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

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

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

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