'Laravel attach pivot to table with multiple values
Background
I'm creating a database revolving around food allergies and I have a many to many relationship between foods and allergies. There is also a pivot value called severity
which has a numerical number representing the severity of the allergy for that food item.
This link table looks like this;
food_id|allergy_id|severity
-------|----------|--------
1 | 1 | 3
1 | 4 | 1
2 | 2 | 1
The problem
When trying to update the link table with Eloquent (where $allergy_ids
is an array)
$food->allergies()->attach($allergy_ids);
How would I go about adding multiple values to this pivot table at once along with the pivot values?
I can add all the allergy_id
's for a particular food item in one go using the above line, but how can I also add in the severity
column at the same time with an array of various severity values? Maybe something like
$food->allergies()->attach($allergy_ids, $severity_ids);
Edit: There could be between 0-20 allergies for a specific food item, and a severity rating from 0-4 for each allergy, if this helps at all.
Solution 1:[1]
You can.
From this example in Docs (4.2, 5.0):
$user->roles()->sync(array(1 => array('expires' => true)));
Hardcoded version for the first two rows:
$food = Food::find(1);
$food->allergies()->sync([1 => ['severity' => 3], 4 => ['severity' => 1]]);
Dynamically, with your arrays $allergy_ids and $severities in a compatible state (size and sort), you shall prepare your sync data before. Something like:
$sync_data = [];
for($i = 0; $i < count($allergy_ids); $i++))
$sync_data[$allergy_ids[$i]] = ['severity' => $severities[$i]];
$food->allergies()->sync($sync_data);
Solution 2:[2]
You can't do it like you' like so I suggest a simple loop:
foreach ($allergy_ids as $key => $id)
{
$food->allergies()->attach($id, array_get($severity_ids, $key));
// should you need a sensible default pass it as a 3rd parameter to the array_get()
}
workaround However if you wanted to attach multiple allergies with single severity level/id then you could do this:
$food->allergies()->attach($allergy_ids, array('severity' => $singleSeverityValue));
Solution 3:[3]
From version 5.1 of Laravel (Currently in Laravel 9.x) onwards it is possible to pass an array as a second argument with all the additional parameters that need to be saved in the intermediate table. As you can read in the documentation
When attaching a relationship to a model, you may also pass an array of additional data to be inserted into the intermediate table:
$user->roles()->attach($roleId, ['expires' => $expires]);
For convenience, attach and detach also accept arrays of IDs as input:
$user->roles()->attach([1 => ['expires' => $expires], 2, 3]);
Then you can simply do
$food->allergies()->attach([1 => ['severity' => 3], 4 => ['severity' => 1]]);
Solution 4:[4]
Easiest indeed is to attach with the extra data, like so:
$retailer->paymentmethods()->attach($paymentmethod, array('currency' => $paymentmethod->currency));
change out the values for food allergy severity, but you get the hint... :-)
Solution 5:[5]
So, on Laravel 9, passing the ids in the array worked for me. Likeso,
$user->roles()->attach([$a->id,$b->id,$c->id]);
and so on.
I guess instead of passing the string. We can pass just the id or else convert the string into array.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Nuno Rafael Figueiredo |
Solution 2 | Jarek Tkaczyk |
Solution 3 | |
Solution 4 | My Brain |
Solution 5 | Usama Munir |