結論から。
多分、この2つのどちらかではないかと。
- ケアレスミス。クラス名のTYPOとか、違うクラス指定してるとか。
- UPDATE時にゴニョゴニョしたい、という場合は書き方に注意が必要。
公式マニュアル内の「複数モデル更新」→Noteの枠内に記載されてます。
詳細
きっかけは、Seeding した時にエラーが発生して上手くいかなかったのが始まり。
php artisan db:refresh --seed
とやっても、
Seeding: FormElementsTableSeeder Symfony\Component\Debug\Exception\FatalThrowableError : Function name must be a string
というエラーが出てしまい、ここでずいぶん悩みました。
エラーを調べても、メソッド指定がうまく行っていない、というのが分かるだけで、原因となる個所の特定が出来ません。( -v 付きでやってもあまり変わらず・・。)
ブラウザ上でのエラーならリモートデバッグ出来るのになぁ・・と思っていたら、php artisan 実行時のデバッグ方法としてこんなのがあるのを発見。
IDE側でデバッグ実行モードにしておいて・・
php -dxdebug.remote_enable=1 -dxdebug.remote_mode=req -dxdebug.remote_port=9000 -dxdebug.remote_host=127.0.0.1 -dxdebug.remote_autostart=on artisan my:command
ネタ元:Xdebug laravel artisan commands – Stack Overflow
これで具体的なメソッド名が create だというのが分かり(ほんとはエラーメッセージにも出てたんだけど半信半疑だった)、
あ、DBの新規登録時に、カラムに自動で値が入るように Observer 入れてたけど、あれか・・。
と、気づきまして・・。
ところが、ざっと調べてみてもおかしな部分が見当たらず、悩むこと数時間・・(-_-;)
結局、FooObserver::class と記述しなければいけないところに、 Foo::class (Observerじゃないモデルクラス)を指定していたのが原因でした。
さらに…
さて、これで Seeding は無事に動きました。
ところが、新規登録時に、期待通りの挙動をしてくれません。
どうも Observer のイベントが発火していないみたい。デバッグモードにしても、ブレイクポイントが効かないんです。
で、こちらもしばらく悩んだ結果、 AppServiceProvider で、該当の Observerクラスが use 指定されていなかった、ということに(たまたま)気づきまして、無事に期待通りの動きをするようになったのでした。
ということで、以下にチェックリストを。
- AppServiceProvider の boot() 内に、モデルと Observer との紐付けを記載し忘れてないか。
- Foo::observe(FooObserver::class); の記載自体を忘れてないか?
- Foo::observe()メソッド内で指定しているクラス名が間違っていないか。
- ○ Foo::observe(FooObserver::class);
- × Foo::observe(Foo::class);
- AppServiceProvider で App\Observers\FooObserver が use 指定されているか。
- (自分の場合はモデルクラスのみ use 指定されてて、Observer クラスが無かった。)
ちなみに、今回の現象を調査している中で多くみかけた記事は、Update 時に Observer が期待した動きをしてくれない、というもの。
この件に関しては、こちらの回答に良い例/悪い例が載っています。
Model Observers, Updated/Updating not Firing ・ Issue #11777 ・ laravel/framework ・ GitHub
(2016/11 の投稿なのでずいぶん前ですが、5.7の公式のドキュメントにも「Eloquentの複数モデル更新を行う場合、更新モデルに対するsavedとupdatedモデルイベントは発行されません」と書かれているので、今も状況は同じかと思います。)
そもそも、デバッグスキルがしょぼい気が。もうちっと早い段階で見つけられる術は無いもんだろうか・・。
アドバイスありましたらお願いしますm(_ _;)m
[Twitterアカウントはこちらでございます]