Laravelは多対多リレーションを使って、データを色々な形で保存できます。
意外と便利なのが、syncWithoutDetaching。
完全重複以外は、重複OKにできちゃいます。
syncWithoutDetachingを直訳すると「デタッチ(紐づけ解除)せずに、シンク(同期)をする」という意味。
他の方法との比較と、使い方を解説していきますね。
attach, sync, syncWithoutDetachingの比較と使い方
【リレーションでデータ保存する方法比較】
attach | 中間テーブルにデータを挿入できる
重複はいくらでもOK |
---|---|
sync | 中間テーブルに【値を重複させず】データを挿入できる
重複した場合は削除 |
syncWithoutDetaching | 中間テーブルに【値を重複させず】データを挿入できる
完全重複以外は、重複OK |
なお、どの方法を使うにしても最初にふたつのモデル同士でリレーションを作っておきましょう。
今回はQuizモデルとUserモデルでリレーションを作ります。
前準備
まずは前準備をしておきます。
すでにリレーションができている方は、この項目はスキップしてください。
①リレーション作り
Quizモデルファイルに、次のように入れておきます。
1 2 3 |
public function users(){ return $this->belongsToMany(App\Models\User)->withTimestamps(); } |
Userモデルファイルには、次のように入れます。
1 2 3 |
public function quizes(){ return $this->belongsToMany('\App\Models\User')->withTimestamps(); } |
リレーションの作り方は、下記の記事でモデルの作り方から解説しています。
②ルート設定
ルート設定を作成します。
メソッドは 【put】としておきます。
1 |
Route::put('/quiz/{quiz}/completed', 'HomeController@completed')->name('quiz.completed'); |
アドレスなどはお好きなように設定してください。
③ビューファイル(blade.php)作成
ビュー部分を作っておきます。
今回は、ボタンを押すと、コントローラーで処理が行われるようにします。
blade.phpファイルに次のようなボタンを追加しておきましょう。
1 2 3 4 5 |
<form method="post" action="{{ route('quiz.completed', $quiz) }}"> @method('put') @csrf <button type="submit" class="btn btn-danger w-50">クイズ完了</button> </form> |
attachを使った場合
それでは、コントローラー側の処理を記述していきましょう。
まずはattachから。
フォームからデータを受け取った後、コントローラーのコードは、こんなふうになります。
1 2 3 4 |
$quizId=$inputs['quiz_id']; $userId=$inputs['user_id']; $quiz=Quiz::find($quizId); $quiz->users()->attach($userId); |
attachを使うと、完全重複を含め、すべてのデータが中間テーブルに保存されます。
買い物かごに商品を追加する時などには、使えます。
ただ、完全に同じデータは保存不要、という場合には向きません。
syncを使った場合
次はsync。syncは重複なしで登録したい場合に使います。
コントローラーの記述はこんなふうにします。
1 2 3 4 |
$quizId=$inputs['quiz_id']; $userId=$inputs['user_id']; $quiz=Quiz::find($quizId); $quiz->users()->sync($userId); |
この状態でデータを保存していくとしましょう。
例えば、次のようなデータがあるとします。
ここで、quiz_id=4, user_id=2のデータを保存してみます。
すると次のように、quiz_id=4, user_id=4 のデータが削除されてしまいました。
syncはこのように重複を消してくれます。
ただ、自動的に【削除=紐づけ解除】してしまうので、注意してください。
勝手に削除したくない場合は、次のように引数にfalseを入れます。
1 |
$quiz->users()->sync($userId, false); |
ただ、なんだか怖いですし処理がメンドウ。
そこで、便利なのが次のsyncWithoutDetachingです。
syncWithoutDetachingを使った場合
syncWithoutDetachingはその名のとおり、デタッチ(紐づけ解除)なしでsyncができるメソッド。
コード例はこちら。
1 2 3 4 |
$quizId=$inputs['quiz_id']; $userId=$inputs['user_id']; $quiz=Quiz::find($quizId); $quiz->users()->syncWithoutDetaching($userId); |
次のように、完全重複以外は、重複OK。
ケースバイケースですが、syncWithoutDetachingは活躍の場が多いような気がします。
ただ名前が長すぎるせいか^^; あまり知られていない気も。
機会があったら、お試しください。