Can anyone help me on how to save many to many relationship? I have tasks, user can have many tasks and task can have many users (many to many), What I want to achieve is that in update formadmin can assign multiple users to specific task. This is done through html multiple select input

name="taskParticipants[]"

The catch here is that through the same form (input) you can add/remove users, that's why I have to use sync(). Maybe I should start from the beginning but don't know where to start...

This is my User model:

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

Task model

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));
        }
    }
}

This is structure of tables tasks id|title|deadline

user_tasks
id|task_id|user_id
shareimprove this question
 
   
I've updated my code. link – SuperManSL Jul 11 '14 at 17:05
4 
$workers = Input::get('taskParticipants'); $task->taskParticipants()->sync($workers);and that's all you need, as long as you pass from that form all the users, assigned to the task. – Jarek Tkaczyk Jul 12 '14 at 9:19
   
@JarekTkaczyk Thanks, That was magical. – Ryu_hayabusa Feb 25 '15 at 18:39
正确答案

tldr; Use sync with 2nd param false


Many-to-many relationship is belongsToMany on both models:

// 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');
}

In order to add new relation use attach or sync.

Difference between the two is:

1 attach will add new row on the pivot table without checking if it's already there. It's good when you have additional data linked to that relation, for example:

User and Exam linked with pivot table attempts: id, user_id, exam_id, score

I suppose this is not what you need in your situation:

$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]

2 sync on the other hand, will either remove all relations and set them up anew:

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

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

or it will setup new relations without detaching previous AND without adding duplicates:

$user->tasks()->sync([5,6,7,8], false); // 2nd param = detach
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,7,8]
shareimprove this answer
 
3 
It'd be nice if that was documented in the main docs rather than the API docs! Rock on. +1. – ceejayoz Jul 11 '14 at 21:25
   
I really like second solution with sync and 2nd parameter. Like I said in comment bellow, I can't afford not to use detach. The story is that admin can assign task to users. He select users from dropdown (multiple), field is participants[]. So... : Step 1: admin assigns task A to three users (your method works, we have 3 records in DB) Step 2: admin updates task A and adds two users (your method works, we have 5 records in DB) Step 3: admin updates task A and removes 1 user (your method fails, we still have 5 users instead of 4) my update method my code – SuperManSL Jul 11 '14 at 21:30
1 
You can simplify your relationship query to just $this->belongsToMany('User') if you use name the table alphabetically and singular (so task_user instead of user_tasks) – Kousha Jul 11 '14 at 21:50
   
@Rok if you always pass an array of all related users, then use sync with detaching, no worries. I suggest using 2nd param set to false whenever you'd like to 'add new task for a user' or 'assign user to a task', when you pass single id of the related model. – Jarek Tkaczyk Jul 12 '14 at 8:43
1 
@FabioAntunes sync returns an array with detachedattached and updated lists. attach doesn't return anything, but in both cases you would get an exception if something unexpected happend in the db calls. – Jarek Tkaczyk Apr 13 '15 at 12:37

Here's my notes on how to save and update on all the Eloquent relationships.

in One to One:

You have to use HasOne on the first model and BelongsTo on the second model

to add record on the first model (HasOne) use the save function

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

to add record on the second model (BelongsTo) use the associate function

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


in One to Many:

You have to use HasMany on the first model and BelongsTo on the second model

to add record on the first table (HasMany) use the save or saveMany functions

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

to add record on the second model (BelongsTo) use the associate function

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


in Many to Many:

You have to use BelongsToMany on the first model and BelongsToMany on the second model

to add records on the pivot table use attach or sync functions

  • both functions accepts single ID or array of ID’s 

  • the difference is attach checks if the record already exist on the pivot table while sync don’t

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


in Polymorphic One to Many:

You have to use MorphMany on the main model and MorphTo on all the (***able) models

to add records on all the other models use the save

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

the pivot table should have the following columns:

. main model ID

. (***able) ID

. (***able) Type


in Polymorphic Many to Many:

You have to use MorphByMany on the main model and MorphToMany on all the (***able) models

to add records on all the other models use the save or saveMany

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

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

the pivot table should have the following columns:

. main model ID

. (***able) ID

. (***able) Type


in Has Many Through (shortcut):

You have to use HasManyThrough on the first table and have the normal relations on the other 2 tables

this doesn’t work for ManyToMany relationships (where there’s a pivot table)

however there’s a nice and easy solution just for that.

shareimprove this answer
 
3 
this should have more upvote – wlin Apr 22 '16 at 19:57
   
I actually placed this answer when they already had over 40 likes on the correct answer, but yes I know how useful this is for me, glad you like it :) – Mahmoud Zalt Apr 23 '16 at 7:09
1 
I wish you know that you're a savior – Chay22 Jul 9 '16 at 13:40
   
this is a great answer. – cora Jan 25 at 20:04

The sync function obliterates the exiting relationships and makes your array the entire list of relations. You want attach instead to add relations without removing others.

shareimprove this answer
 
   
I can't use attach because I'm using this code inside update method. The story is that admin can update task and fill in input participants[] with users that will participate in task. So I need to check if it exists and delete (or not to add new record) it or if it doesn't exist add it. – SuperManSL Jul 11 '14 at 21:18

来自  https://stackoverflow.com/questions/24702640/laravel-save-update-many-to-many-relationship