ChatGPT解决这个技术问题 Extra ChatGPT

Laravel save / update many to many relationship

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 form admin 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
I've updated my code. link
$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.
@JarekTkaczyk Thanks, That was magical.

A
Alexxus

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]

It'd be nice if that was documented in the main docs rather than the API docs! Rock on. +1.
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
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)
@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.
@FabioAntunes sync returns an array with detached, attached 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.
M
Mahmoud Zalt

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.

Here's an article I wrote, inspired by this answer. Important to check it: https://hackernoon.com/eloquent-relationships-cheat-sheet-5155498c209


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 :)
how to update one to may relation. u explained how to add . could you please explain the update too? is there a method to update records like updateMany something like that? thanks
M
Moslem Deris

syncWithoutDetaching([$id_one, $id_two, $id_three]); is what you are looking for. Actually it does the exact thing [sync with 2nd param false] does!


H
Hashmat Waziri

Solved: Use the updateOrInsert(array $attributes, array $values = [])

     DB::table('your_pivot_table')->updateOrInsert([
                'col' => $someValue
                

            ],[

                    'otherColumn' => $otherVlaue,
                   
                ]);
            

        }

c
ceejayoz

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.


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.
R
Rama Ranneh

for those who are searching for adding pivot attributes (the middle table attributes), you can use syncWithPivotValues and it also has the second parameter like this

$user->tasks()->syncWithPivotValues($tasksIDs,['day_number' => $day],false);

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now