【Laravel 5.7】Observer がうまく動かない時のチェックリスト

2018/10/17

結論から。

多分、この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

ネタ元:

これで具体的なメソッド名が 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 が期待した動きをしてくれない、というもの。

この件に関しては、こちらの回答に良い例/悪い例が載っています。

(2016/11 の投稿なのでずいぶん前ですが、5.7の公式のドキュメントにも「Eloquentの複数モデル更新を行う場合、更新モデルに対するsavedとupdatedモデルイベントは発行されません」と書かれているので、今も状況は同じかと思います。)

そもそも、デバッグスキルがしょぼい気が。もうちっと早い段階で見つけられる術は無いもんだろうか・・。

アドバイスありましたらお願いしますm(_ _;)m
[Twitterアカウントはこちらでございます]