ChatGPT解决这个技术问题 Extra ChatGPT

Laravel, sync() - how to sync an array and also pass additional pivot fields?

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.

The answer below did not quiet got me through.. could you please post your solutions to that? Thanks!
Good question... all tuturials are full of basics.

C
Cyril Graze

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

Jarek but what if I have for example $speakers = \Input::get( 'speakers' ) (where $speakers becomes an array), and then want to pass $speakers along with =>array( 'is_speaker' => true)?
Not what if. You create sync array like shown above. Build your array with ids as keys, or make it this way in your HTML form.
Jarek, my \Input::get( 'speakers' ) is returning an array of ids. Would something like this work: $training->users()->sync( array( $speakers => array( 'is_speaker' => true ) ) )
@JarekTkaczyk Thanks! The answer to the comment was just what I was looking for!
@JarekTkaczyk looks nice, but each item is updated\inserted with a separate query, which is a bit disappointing, as it will effect performance.
S
Sincere

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

Upvoting this one because it's nice and clean, and I suspect it'd be very easy for any developer coming after to understand and modify.
You can replace ->sync($photo_id_array, false) to ->syncWithoutDetaching($photo_id_array) as well. Upvoting too since this is the most elegant solution.
R
Robin

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

M
Miguel Trevino

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


T
Tom van Tilburg

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

I like your thinking-- better to turn it into something reusable, rather than copied the next time this issue comes up-- though I'd recommend making it a helper function so it could be used anywhere and with any model.
X
X 47 48 - IR

Simply just append your fields and their values to the elements:

$user->roles()->sync([
   1 => ['F1' => 'F1 Updated']
]);

D
Deivid Criollo
$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);

When answering an old post, it would be helpful if you could provide some context to your answer rather than just code, as it might make it more useful to others.
See David Bucks comment. Also, include software and/or system and/or library versions; only way to prevent downvoting or deletion of answer.
H
Healyhatman

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)


E
Edvaldo Torres
    foreach ($request->exercise_id as $key => $exercise_id) {
        $data_plan[$exercise_id] = [
            'serie' => $request->serie[$key],
            'observation' => $request->observation[$key],
        ];
    }

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

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now