👏

[Laravel]deleteのモデルイベントが発火しなかった件

2024/08/16に公開

背景

あるモデルHogeの更新時/削除時にとある処理を追加したかったので、モデルイベントに処理を追加してみたところ削除時の処理がうまくいかなかった😢

やったこと

  • モデルクラスHogeにsavedイベントを追加
    • static::saved(function (Hoge $model) {
          // 処理内容
      }
      
    • 削除時にモデルイベントが動かなかった🤔
  • モデルクラスHogeにdeletedイベントを追加
    • static::deleted(function (Hoge $model) {
          // 処理内容
      }
      
    • まだ削除時にモデルイベントが動かなかった🤔
  • Eloquent/Modelのdelete()にログを仕込んでメソッドが呼ばれているかを確認
    • 呼ばれていなかった🤔
  • Hogeのdelete()を呼んでいるインスタンスの情報をログに出力
    • Eloquent/ModelクラスのインスタンスではなくEloquent/Builderクラスのインスタンスだった
  • Eloquent/Modelクラスのインスタンスを取得してdelete()を呼ぶように変更
    • // 改修前
      Hoge->where(['id' => xxx])->delete();
      // 改修後
      Hoge->where(['id' => xxx])->first()->delete();
      
    • 削除時のモデルイベントが動いた!✌️

Eloquent/Modelを継承しているクラスのインスタンスでdelete()を呼ばないとモデルイベントが動かないみたいだから気をつけよう><

Modelのdelete()とBuilderのdelete()はどう違うのか?

それぞれのメソッドを追っていってみました
※一部処理を割愛しています

Eloquent/Modelのdelete()

  • Eloquent/Modelのdelete()が呼ばれる
  • 🔥deletingのモデルイベント発火
  • モデルクラスがsoftDeleteをuseしている場合
    • softDeleteのperformDeleteOnModel()が呼ばれる
    • softDeleteのrunSoftDelete()が呼ばれる
    • deleted_atが更新される
    • 🔥trashedイベント発火
  • モデルクラスがsoftDeleteをuseしていない場合
    • Eloquent/ModelのperformDeleteOnModel()が呼ばれる
    • Eloquent/Builderのdelete()が呼ばれる
    • Query/Builderのdelete()が呼ばれる
    • ConnectionInterfaceのdelete()が呼ばれる
  • 🔥deletedイベントの発火
  • おわり

Eloquent/Builderのdelete()

  • Eloquent/Builderのdelete()が呼ばれる
  • モデルクラスがsoftDeleteをuseしている場合
    • onDelete関数が呼ばれる
    • SoftDeletingScopeのexpand()が呼ばれる
    • deleted_atが更新される
    • おわり
  • モデルクラスがsoftDeleteをuseしていない場合
    • Query/Builderのdelete()が呼ばれる
    • ConnectionInterfaceのdelete()が呼ばれる
    • おわり

感想

ひぇ〜

Discussion