カテゴリー
Linux

Laravel のモデルのリレーション先のモデルを削除するベストプラクティス

関連したモデルの挿入、更新については公式ドキュメントに記述があります。

しかし、削除については言及されていません。

そこで、自分なりにたどり着いた最適な削除方法を残します。

気をつけたこと、満たしたい要件

  • 関連したモデルを削除するときにも イベント が発生するようにする。
  • 判定構文は使いたくない。

関連したモデルの削除、自分なりのベストプラクティス

リレーションの関係が、 1 対 1 でも 1 対多でも次の方法がよいと思います。

$user->phone()->each(function ($phone) {
    $phone->delete();
});

eachIlluminate\Database\Eloquent\Collection ではなく、Illuminate\Support\Collection クラスのメソッドです。

多対多の場合は、リレーション先のモデルというよりも、 中間テーブルのモデルの操作 となりますので今回のケースが当てはまらない場合もあるかと思います。

他の、ベストではないが、関連したモデルを削除する方法

判定構文を使う方法

判定構文を使いたくないが、使う場合です。直感的で書きやすいです。 Laravel を探究しなければこの方法以外は無いでしょう。 $phone = $user->phone; の部分は、 $phone = $user->phone()->first(); でもよいでしょう。

$phone = $user->phone;
if ($phone) {
    $phone->delete();
}

上記は 1 対 1 の場合です。 1 対多の場合は次のようになります。 $post->comments()->get(); の部分は $post->comments; でも問題ありません。

$comments = $post->comments()->get();
if ($comments) {
    $comments->each(function ($comment) {
        $commnet->delete();
    })
}

ここまでくるとかえって複雑に感じます。そこで判定は不要なのではと考えると、自然と私なりのベストな方法へと行き着くように思います。

シンプルだがイベントが発生しない方法

シンプルですが、関連するモデルの deleteingdeleted イベントが発生しません。このことを充分に承知していれば、採用してもよいでしょう。

1 対 1 のリレーションの場合

$user->phone->delete(); とすると次のエラーとなる場合がある点に注意です。

ERROR: Call to a member function delete() on null

次のように書けば、もし関連モデル (Phone) が紐づいていなくてもエラーとはなりません。

$user->phone()->delete();

1 対多のリレーションの場合

$post->comments->delete(); とすると次のエラーとなる点に注意です。

ERROR: Method Illuminate\Database\Eloquent\Collection::delete does not exist.

次のように書けば、もし関連モデル (Card) が 0 件でもエラーとはなりません。

$user->cards()->delete();

おわりに

もっとよい削除の方法があるはず、と思いこれまで何度か調べては同じ結論にたどり着いています。

そこで、今回投稿いたしました。

以上です。

コメントを残す