Laravelは多対多の関係を保存/更新します


89

多対多の関係を保存する方法について誰かが私を助けることができますか?私にはタスクがあり、ユーザーには多くのタスクがあり、タスクには多くのユーザー(多対多)があります。私が達成したいのは、更新フォームで管理者が複数のユーザーを特定のタスクに割り当てることができることです。これは、htmlの複数選択入力を介して行われます

name="taskParticipants[]"

ここでの落とし穴は、同じフォーム(入力)を介してユーザーを追加/削除できることです。そのため、sync()を使用する必要があります。たぶん私は最初から始めるべきですが、どこから始めればいいのかわかりません...

これは私のユーザーモデルです:

public function tasks()
{
    return $this->belongsToMany('Task','user_tasks');
}

タスクモデル

public function taskParticipants()
{
    return $this->belongsToMany('User','user_tasks');
}

TaskController

public function update($task_id)
{
    if (Input::has('taskParticipants'))
    {
        foreach(Input::get('taskParticipants') as $worker)
        {
            $task2 = $task->taskParticipants->toArray();
            $task2 = array_add($task2,$task_id,$worker);
            $task->taskParticipants()->sync(array($task2));
        }
    }
}

これはテーブル タスクの構造ですid | title | deadline

user_tasks
id|task_id|user_id

コードを更新しました。 リンク
SuperManSL 2014

4
$workers = Input::get('taskParticipants'); $task->taskParticipants()->sync($workers);そのフォームからタスクに割り当てられたすべてのユーザーを渡す限り、必要なのはそれだけです。
Jarek Tkaczyk 2014

@JarekTkaczykありがとう、それは魔法でした。
リュウハヤブサ2015

回答:


200

tldr; sync2番目のパラメーターで使用false


多対多の関係はbelongsToMany両方のモデルにあります。

// Task model
public function users()
{
  return $this->belongsToMany('User', 'user_tasks'); // assuming user_id and task_id as fk
}

// User model
public function tasks()
{
  return $this->belongsToMany('Task', 'user_tasks');
}

新しい関係を追加するには、attachまたはsync

2つの違いは次のとおりです。

1 attachは、ピボットテーブルに新しい行があるかどうかを確認せずに、ピボットテーブルに新しい行を追加します。その関係にリンクされた追加のデータがある場合は、次のようになります。

Userそして、Examピボットテーブルとリンクattempts: id, user_id, exam_id, score

私はこれがあなたの状況であなたが必要とするものではないと思います:

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->attach([5,6,7]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,5,6,7]

sync一方、2は、すべての関係を削除して、それらを新たに設定します。

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->sync([1,2,3]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3]

または、以前のANDを切り離さずに、重複を追加せずに新しい関係を設定します。

$user->tasks()->sync([5,6,7,8], false); // 2nd param = detach
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,7,8]

8
それがAPIドキュメントではなくメインドキュメントに文書化されていればいいのですが!ロックオン。+1。
ceejayoz 2014

私は同期と2番目のパラメーターを持つ2番目のソリューションが本当に好きです。以下のコメントで言ったように、私はデタッチを使わないわけにはいかない。ストーリーは、管理者がユーザーにタスクを割り当てることができるということです。彼はドロップダウン(複数)からユーザーを選択し、フィールドは参加者[]です。つまり...:ステップ1:管理者がタスクAを3人のユーザーに割り当てます(メソッドは機能し、DBに3つのレコードがあります)ステップ2:管理者はタスクAを更新し、2人のユーザーを追加します(メソッドが機能し、DBに5つのレコードがあります)ステップ3:管理者がタスクAを更新し、1人のユーザーを削除します(メソッドが失敗し、4人ではなく5人のユーザーがいます) 私の更新メソッド私のコード
SuperManSL 2014

1
$this->belongsToMany('User')テーブルにアルファベット順で単数形の名前を使用する場合にのみ、関係クエリを簡略化できます(task_user代わりにuser_tasks
Kousha 2014

@Rokは、関連するすべてのユーザーの配列を常に渡す場合は、デタッチして使用syncします。心配する必要はありません。id関連するモデルの1つを渡すときに、「ユーザーに新しいタスクを追加する」または「ユーザーをタスクに割り当てる」場合は常に、2番目のパラメーターをfalseに設定することをお勧めします。
Jarek Tkaczyk 2014

1
@FabioAntunessyncdetachedattachedupdatedリストを含む配列を返します。attachは何も返しませんが、どちらの場合も、db呼び出しで予期しないことが起こった場合は例外が発生します。
Jarek Tkaczyk 2015

109

これは、すべてのEloquent関係を保存および更新する方法に関する私のメモです。

マンツーマン

あなたは使用する必要がhasOneのを最初のモデルとにbelongsToの第2のモデルに

最初のモデル(HasOne)にレコードを追加するには、保存 機能を使用します

例:    $post->comments()->save($comment);

2番目のモデル(BelongsTo)にレコードを追加するには、アソシエートを使用し ます関数をます

例:    $user->account()->associate($account);    $user->save();


多くの一つ

最初のモデルとBelongsToでHasManyを使用する必要があります第2のモデルに

最初のテーブル(HasMany)にレコードを追加するには、save またはsaveManyを使用します関数をます

例:    $post->comments()->saveMany($comments);

2番目のモデル(BelongsTo)にレコードを追加するには、アソシエートを使用し ます関数をます

例:    $user->account()->associate($account);    $user->save();


多対多

最初のモデルではBelongsToManyを使用し、BelongsToManyを使用する 必要があります第2のモデルに

ピボットテーブルにレコードを追加するには、アタッチまたは同期機能を使用します

  • どちらの関数も単一のIDまたはIDの配列を受け入れます 

  • 違いは、同期が行われていないときにレコードがピボットテーブルにすでに存在するかどうかをアタッチチェックすることです。

例: $user->roles()->attach($roleId);


多くの多形の一つ

メインモデルとMorphToでMorphManyを使用する 必要があり ますすべて(***こと)のモデルに

他のすべてのモデルにレコードを追加するには、保存を使用し ます

例:    $course->tags()->save($tag);

ピボットテーブルには次の列が必要です。

。メインモデルID

。(***可能)ID

。(***可能)タイプ


多くのポリモーフィック多く

メインモデルとMorphToManyでMorphBy​​Manyを使用する 必要があり ますすべて(***こと)のモデルに

他のすべてのモデルにレコードを追加するには、saveまたはsaveManyを使用します

例:    $course->tags()->save($tag);

例:    $course->tags()->saveMany([$tag_1, $tag_2, $tag_3]);

ピボットテーブルには次の列が必要です。

。メインモデルID

。(***可能)ID

。(***可能)タイプ


多くのスルーがあります(ショートカット):

HasManyThroughを使用する必要があります最初のテーブルでし、他の2つのテーブルで通常の関係を持っている必要があります

これは、ManyToMany関係(ピボットテーブルがある場合)では機能しません

ただし、そのための優れた簡単なソリューションがあります。


これが私が書いた記事で、この答えに触発されました。確認することが重要です:https//hackernoon.com/eloquent-relationships-cheat-sheet-5155498c209


正解にすでに40以上の
いいね

1
あなたが救世主であることを知ってほしい
Chay22 2016

1
これは素晴らしい答えです。
caro 2017年

1
1つを更新する方法は関係するかもしれません。uは追加する方法を説明しました。アップデートについても説明していただけますか?updateManyそのようなレコードを更新する方法はありますか?感謝
Hamidreza

4

syncWithoutDetaching([$id_one, $id_two, $id_three]);あなたが探しているものです。実際には、[ sync2番目のパラメーターを使用してfalse]実行するのとまったく同じことを実行します。


0

このsync関数は、既存の関係を消去し、配列を関係のリスト全体にします。attach代わりに、他の関係を削除せずに関係を追加する必要があります。


updateメソッド内でこのコードを使用しているため、attachを使用できません。ストーリーは、管理者がタスクを更新し、入力参加者[]にタスクに参加するユーザーを入力できるというものです。したがって、存在するかどうかを確認して削除する(または新しいレコードを追加しない)か、存在しない場合は追加する必要があります。
SuperManSL 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.