【Laravel】hasMany<->belongsToでManyToManyのsyncのようにアップデートできるようにしたい!

【Laravel】hasMany<->belongsToでManyToManyのsyncのようにアップデートできるようにしたい!

ManyToManyのリレーションにおいては、syncという便利なメソッドで中間テーブルの更新がとても楽チンにできる。

公式ドキュメント内の【Syncing Associations】がそれ。

sync時にリレーションキーのidの配列を渡すと、中間テーブルをアップデートしてくれます。

その中で特に便利だと感じたのが、配列に含まれていないものは削除されるという機能。

つまり例えばデータベースに[ 1, 2, 3, 4, 5 ]というデータがあったとき、[ 1, 2, 4, 7 ]という配列でsyncしてあげるとデータベースに残るのは [ 1, 2, 4, 7 ]になるということ。

配列に含まれていない3と5はdeleteされます。

この機能はアップデートするときにめちゃくちゃ便利だと感じました。

しかし今回はManyToManyの関係ではなくてhasMany<->belongsToの関係において同じようなことを実装したかったです。

状況はこんな感じ

  • Create時にはHogeモデルのデータひとつに対して複数のMogeモデルのデータを登録
  • Update時にMogeモデルを減らす可能性がある

つまりupdate時に、更新されたMogeの内容を書き込むだけではなく、削除されていた場合、データベースからそのデータも削除しなくてはならない。

【案1】更新するHogeに紐づいているすべてのMogeを削除して、全て入れ直す。

非常にシンプルですが、ググってみるとこの解決案が散見されました。

なるほど。この場合だと、更新時に変更を加えていない項目に関しても新しく入れ直すためにデータが必要になりそうですね。もはやフォーム周りはcreateとほとんど同じ感じかな。

  1. 更新したかどうかに関わらず、とりあえず削除されてないMogeの情報を全て配列に入れて送信。
  2. Hogeに紐づく全てのMogeをdelete。
  3. 現存するMogeを全てCreate。

参考:  Synchronizing a one-to-many relationship in Laravel

【案 2】whereNotIn()を使ってsyncと同じようなことを実現。

今回この方法を調べるにあたって初めて知った関数がwhereNotIn()。

https://readouble.com/laravel/5.3/ja/queries.html

これはほぼsync!笑

この関数を使えば自作のsync的なものをつくれそうです。

手順としては

  1. 更新したかどうかに関わらず、とりあえず削除されてないMogeのidを全て配列に入れて送信。
  2. whereNotInで配列に含まれていない(削除された)Mogeをデータベースから削除。
  3. 更新されたMogeの更新部分を普通にupdate。

いけそう。

案 1よりは確実にスマートな感じがします。

 

参考: Is there a shortcut for syncing one-to-many relationships?

【案 3】募集中。

自分の中ではこれまでLaravelってこういう機能ないのかな?って思うたびにスマートすぎる解を提供してくれていて本当に便利だと感じているのですが、今回はないのかなあと探しています。

 

プログラミングカテゴリの最新記事