お疲れ様です!
システム開発部の山田です。

今回は、Laravelで中間テーブルを用いる際に使用するsyncメソッドについて解説していきます。

syncメソッドとは?

テーブルの関係性が多対多の場合、解決法として基本的に中間テーブルを用いると思います。
その際に、中間テーブルへのデータ登録や更新、削除といった動作をsyncメソッドを用いることで簡単に行うことができる優れものです。
具体的な実例とともに見ていきます。

準備(テーブル構成)

syncメソッドの使用にあたり以下状況を想定します。

  • ユーザーと趣味を紐づけ関係性にコメントを付与したい
  • 1ユーザーは趣味を複数持つことができる
  • 1 つの趣味は複数のユーザーから選ばれる

上記を達成するためのテーブル構成は以下を想定します。

  • ユーザーの名前を保持するusersテーブル
idname
1taro
2hanako
3saburo

 

  • 趣味を名称を保持するhobbiesテーブル
idname
1映画
2youtube
3勉強

 

  • ユーザーと趣味を関係を表し、コメントを付与できる中間テーブル(hobby_userテーブル
iduser_idhobby_idcomment
111結構すき
212そこそこすき
321結構すき

 

以上内容でLaravelでマイグレーションファイルを用意し、users、hobbiesテーブルには記載しているデータを挿入した前提で以降の話を進めます。

準備(Laravelのモデルファイル)

Laravelのモデルファイルに多対多の関係性を表すために以下を記述します。

// hobbyモデル
public function users()
{
return $this->belongsToMany(User::class);
}
// usersモデル
public function hobbies()
{
return $this->belongsToMany(Hobby::class);
}

以上よりsyncメソッドの使用準備が整いましたので以降より使用していきます。

syncメソッド

それでは、まずはデータの登録を行いたいと思います。
taro(user_id:1)の趣味に映画(hobby_id:1)を追加したい場合は以下で表せます。

$user = User::find(1);
$user->hobbies()->sync(1);

コメントや複数の登録を一度に行いたい場合は、以下で表せます。
taro(user_id:1)の趣味にyoutube(hobby_id:2)、勉強(hobby_id:3)を追加しコメントも記載を想定します。

$user = User::find(1);
$user->hobbies()->sync([
2 => ['comment' => '結構すき'],
3 => ['comment' => 'そこそこすき'],
]);

ただし、ここで注意点があります。
以下は先ほどのtaro(user_id:1)の趣味に映画(hobby_id:1)を追加した状態のDBに
今回のコードを実行した場合のDBです。

taro(user_id:1)の趣味に映画(hobby_id:1)を追加したデータが消えております。
これはsyncメソッドが名前の通り、データの状態を指定した内容で同期を行うメソッドであるためです。
※sync: 同調・同期

この同期する性質を利用することでデータの削除、更新も簡単に行うことができます。
taro(id:1)の趣味を以下に変更する事を考えます。
youtube(hobby_id:2)、勉強(hobby_id:3)⇒映画(hobby_id:1)、youtube(hobby_id:2)

現状のDBは以下になります。

これを以下コードを実行した場合

$user = User::find(1);
$user->hobbies()->sync([1,2]);

結果は以下になります。

本来であれば勉強(hobby_id:3)の削除⇒映画(hobby_id:1)の追加を行うところを、syncメソッドを用いることで一発で行うことができました。
また、挙動として知っておきたい箇所はid=2の部分です。
コメントは今回指定していませんが、そのまま残っております。
これは、同期するのはあくまでも指定したuser_idとhobby_idの関係性であり、hobby_id=2は変更する必要が無いため、レコードを更新や削除がされることなく、そのまま残っているためです。

syncメソッドの応用

syncメソッドは、同期するメソッドであると説明しましたが、実は同期をせずに登録のみを行うことも可能です。
その方法は第二引数にfalseを宣言する事です。
先ほどのテーブルに続きに、taro(id:1)の趣味に勉強(hobby_id:3)を追加してみます。

$user = User::find(1);
$user->hobbies()->sync(3, false);

第二引数にfalseを指定することで、元々存在していた映画(hobby_id:1)、youtube(hobby_id:2)は消えることなく、勉強(hobby_id:3)の追加に成功しました。
ただし、falseをつけるのは忘れやすい行動で、もし指定を行わなかった場合は意図せずデータを消す恐れがあります。
そのため、falseを指定する代わりにsyncWithoutDetachingメソッドを指定しても同様の内容を表します。

$user = User::find(1);
$user->hobbies()->syncWithoutDetaching(3);

まとめ

今回はLaravelで中間テーブルの登録や変更、削除を行う際に便利なsyncメソッドを紹介しました。
同期の性質を理解する事さえできれば非常に扱いやすいメソッドだと思います。
また、最後に紹介したsyncWithoutDetachingメソッドはlaravelの内部的にはsyncメソッドにfalseを指定した物を実行するだけですが、
こういった物が用意されている事で、うっかりミスを防ぐことができるので非常に使い勝手のいいメソッドですね。

皆さんもsyncメソッドを使いこなし、日々コーディングを楽しんで行いましょう!
それでは!!