Laravel8 記述の違いによるモデル周りの動作の違いについて

Laravelロゴ

Laravel8のModel::insert()メソッドでレコードを登録したら、なぜかcreated_byがNullで入っていました。
あれ?自動でいれてくれるんじゃなかったのか?と思って調べたら、どうやら記述方法で動作が変わるらしい。

記述方法で若干動作が違う

レコードの編集系の操作は大まかにModelオブジェクトからとQueryBuilderオブジェクトの2つの方法があり、それぞれメソッドがありますが、それぞれ動作が違うようです。
具体的には、記述方法でコールバックイベントが発火したりしなかったり、タイムスタンプが更新されたりされなかったりということが起きるようです。

とても詳しく検証してくれているサイトがあったので、詳しくはこちらを参照してください。

クラスやメソッドによって、また、データの書き換えがあるかどうかによって、タイムスタンプが更新されたりされなかったり、イベントが呼ばれたり呼ばれなかったりということがあるようです。
うーん。こんなの覚えられないよ~。なぜこうする必要があるのか、いまいち理由がわからないですね。

とりあえずは・・・

基本的な使用方法

ということで、とりあえず、レコードを保存する場合は、基本的にこの3つだけ使うようにしましょう。
Model::save()
Model::create()
Model::update()

コールバックイベント

コールバックイベントは、保存前や保存後に何かしら処理が必要な時に使います。呼ばれる/呼ばれない条件はかなり複雑なので、よくよく調べてから&デバッグを入念にしてください。

要注意

こちらは動作を調べてから使いましょう。
Model::insert()は基本使わない。
バルクインサート(複数レコードを一気に挿入する)を使う場合は仕方がないが、タイムスタンプが必要な場合は自分でセットしておく必要があります。

QueryBuilder::update()は要注意です。
QueryBuilderの検索結果を更新するというのはありがちな処理なので、知らず知らずのうちに使っちゃいそうです。こちらは、イベントが呼ばれないだけでタイムスタンプの更新はされるようなので、普通に使う分にはあまり影響はないかもしれませんが、イベントコールバックが呼ばれないというのは頭の片隅に入れておくべきです。Collectionで取得してループすればModelが取得できますので、そこでupdateすればよいかと思います。

また、実際にデータが更新されているかどうかで更新日付を変更するかどうかが決まる場合があります。
どちらの実装が良いのかはプロジェクトのルール次第だと思います。

Model::update()だと中身に変更がなければ更新日付は更新されません。
QueryBuilder::update()だと、中身にかかわらず呼ばれた段階で更新日付が変わります。

まとめ

更新日付に関しては、中身の変更がないのにPOSTされた場合、更新日付をどうするかをあらかじめ決めておいて、データの呼び出しをfind()系をつかうかwhere(‘id’,ID番号)系を使うか決めておくといいかなと思います。

ただ、イベントコールバックに関しては、あらかじめ使うかどうかを決めておいた方がいいと思います。
データの取得をwhere()系にしちゃった場合は後々のイベント処理が必要になった時に大変な工数が発生する必要があります。

ですので、基本的には保存を伴うデータの呼び出しはfind()系を使うということに統一しておいた方がいいと思います。

一応、紹介したサイトには、ModelやQueryBuilderをオーバーライドして処理を統一する方法も載っていますので、参考にするとよいと思います。ただ、個人的には、将来どうなるかわからないのでこの辺りはあんまりいじりたくないなぁというのが感想です。

まさかこんな変な実装があるとは思いませんでした。
Laravelは自由度が高いフレームワークですが、へんなところでかゆいところに手が届かないといった感じの実装が多くてCakeとかRailsとかを使っていた人はモヤっとすることが多いような気がします。

タイトルとURLをコピーしました