関連したモデルの挿入、更新については公式ドキュメントに記述があります。
しかし、削除については言及されていません。
そこで、自分なりにたどり着いた最適な削除方法を残します。
気をつけたこと、満たしたい要件
- 関連したモデルを削除するときにも イベント が発生するようにする。
- 判定構文は使いたくない。
関連したモデルの削除、自分なりのベストプラクティス
リレーションの関係が、 1 対 1 でも 1 対多でも次の方法がよいと思います。
$user->phone()->each(function ($phone) {
$phone->delete();
});
each
は Illuminate\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();
})
}
ここまでくるとかえって複雑に感じます。そこで判定は不要なのではと考えると、自然と私なりのベストな方法へと行き着くように思います。
シンプルだがイベントが発生しない方法
シンプルですが、関連するモデルの deleteing
、 deleted
イベントが発生しません。このことを充分に承知していれば、採用してもよいでしょう。
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();
おわりに
もっとよい削除の方法があるはず、と思いこれまで何度か調べては同じ結論にたどり着いています。
そこで、今回投稿いたしました。
以上です。