Official Laravel documentation has this on sync()
function:
$user->roles()->sync( array( 1, 2, 3 ) );
You may also associate other pivot table values with the given IDs:
$user->roles()->sync( array( 1 => array( 'expires' => true ) ) );
In the latter example only a single pivot row is being added. What I don't understand is how can I associate other pivot table records if there are more than one rows to be synced?
Thanks in advance.
In order to sync
multiple models along with custom pivot data, you need this:
$user->roles()->sync([
1 => ['expires' => true],
2 => ['expires' => false],
...
]);
Ie.
sync([
related_id => ['pivot_field' => value],
...
]);
edit
Answering the comment:
$speakers = (array) Input::get('speakers'); // related ids
$pivotData = array_fill(0, count($speakers), ['is_speaker' => true]);
$syncData = array_combine($speakers, $pivotData);
$user->roles()->sync($syncData);
This works for me
foreach ($photos_array as $photo) {
//collect all inserted record IDs
$photo_id_array[$photo->id] = ['type' => 'Offence'];
}
//Insert into offence_photo table
$offence->photos()->sync($photo_id_array, false);//dont delete old entries = false
->sync($photo_id_array, false)
to ->syncWithoutDetaching($photo_id_array)
as well. Upvoting too since this is the most elegant solution.
There is now a ->syncWithPivotValues($ids, $pivotValues)
method available if you want to set the same pivot value for all synced items.
Example from the doc:
$user->roles()->syncWithPivotValues([1, 2, 3], ['active' => true]);
Attaching / Detaching
Eloquent also provides a few additional helper methods to make working with related models more convenient. For example, let's imagine a user can have many roles and a role can have many users. To attach a role to a user by inserting a record in the intermediate table that joins the models, use the attach method:
$user = App\User::find(1);
$user->roles()->attach($roleId);
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]);
You can also use Sync if you want to remove old roles and only keep the new ones you are attaching now
$user->roles()->sync([1 => ['expires' => $expires], 2 => ['expires' => $expires]);
The default behaviour can be changed by passing a 'false' as a second argument. This will attach the roles with ids 1,2,3 without affecting the existing roles.
In this mode sync behaves similar to the attach method.
$user->roles()->sync([1 => ['expires' => $expires], 2 => ['expires' => $expires], false);
Reference: https://laravel.com/docs/5.4/eloquent-relationships
Add following trait to your project and append it to your model class as a trait. This is helpful, because this adds functionality to use multiple pivots. Probably someone can clean this up a little and improve on it ;)
namespace App\Traits;
trait AppTraits
{
/**
* Create pivot array from given values
*
* @param array $entities
* @param array $pivots
* @return array combined $pivots
*/
public function combinePivot($entities, $pivots = [])
{
// Set array
$pivotArray = [];
// Loop through all pivot attributes
foreach ($pivots as $pivot => $value) {
// Combine them to pivot array
$pivotArray += [$pivot => $value];
}
// Get the total of arrays we need to fill
$total = count($entities);
// Make filler array
$filler = array_fill(0, $total, $pivotArray);
// Combine and return filler pivot array with data
return array_combine($entities, $filler);
}
}
Model:
namespace App;
use Illuminate\Database\Eloquent\Model;
class Example extends Model
{
use Traits\AppTraits;
// ...
}
Usage:
// Get id's
$entities = [1, 2, 3];
// Create pivots
$pivots = [
'price' => 634,
'name' => 'Example name',
];
// Combine the ids and pivots
$combination = $model->combinePivot($entities, $pivots);
// Sync the combination with the related model / pivot
$model->relation()->sync($combination);
Simply just append your fields and their values to the elements:
$user->roles()->sync([
1 => ['F1' => 'F1 Updated']
]);
$data = array();
foreach ($request->planes as $plan) {
$data_plan = array($plan => array('dia' => $request->dia[$plan] ) );
array_push($data,$data_plan);
}
$user->planes()->sync($data);
Putting this here in case I forget it later and Google it again.
In my case I wanted the extra column to have the same data for each row
Where $syncData is an array of IDs:
$syncData = array_map(fn($locationSysid) => ['other_column' => 'foo'], array_flip($syncData));
or without arrow
$syncData = array_map(function($locationSysid) {
return ['ENTITY' => 'dbo.Cli_Core'];
}, array_flip($syncData));
(array_flip means we're using the IDs as the index for the array)
foreach ($request->exercise_id as $key => $exercise_id) {
$data_plan[$exercise_id] = [
'serie' => $request->serie[$key],
'observation' => $request->observation[$key],
];
}
Success story sharing
$speakers = \Input::get( 'speakers' )
(where $speakers becomes an array), and then want to pass$speakers
along with=>array( 'is_speaker' => true)
?ids
as keys, or make it this way in your HTML form.$training->users()->sync( array( $speakers => array( 'is_speaker' => true ) ) )