Laravel, sync () - як синхронізувати масив, а також передавати додаткові зведені поля?


81

Офіційна документація Laravel має таку sync()функцію:

$user->roles()->sync( array( 1, 2, 3 ) );

Ви також можете пов’язати інші значення зведеної таблиці із заданими ідентифікаторами:

$user->roles()->sync( array( 1 => array( 'expires' => true ) ) );

В останньому прикладі додається лише один зведений рядок. Я не розумію, як я можу зв’язати інші записи зведеної таблиці, якщо для синхронізації існує більше одного рядка?

Заздалегідь спасибі.


Відповідь нижче не спокійно мене зрозумів. Чи можете ви, будь ласка, опублікувати свої рішення? Дякую!
Евіс

Гарне запитання ... усі навчальні посібники повні основ.
Шахід Карімі

Відповіді:


35

Це працює для мене

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

2
Проголосувати за цей, бо він приємний і чистий, і я підозрюю, що будь-якому розробнику, який прийде після цього, буде дуже легко зрозуміти та змінити.
DevBodin

Ви можете також замінити ->sync($photo_id_array, false)на ->syncWithoutDetaching($photo_id_array). Також голосую, оскільки це найелегантніше рішення.
Муса

148

Для того, щоб створити syncдекілька моделей разом із власними зведеними даними, вам потрібно це:

$user->roles()->sync([ 
    1 => ['expires' => true],
    2 => ['expires' => false],
    ...
]);

Тобто.

sync([
    related_id => ['pivot_field' => value],
    ...
]);

редагувати

Відповідаючи на коментар:

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

1
Ярек але що , якщо у мене є, наприклад , $speakers = \Input::get( 'speakers' )(де $ спікери стають масив), а потім хоче пройти $speakersразом з =>array( 'is_speaker' => true)?
Томица Кораћ

1
Не що, якби. Ви створюєте масив синхронізації, як показано вище. Створіть свій масив за допомогою idsключів або зробіть це таким чином у формі HTML.
Ярек Ткачик

Ярек, мій \ Input :: get ('динаміки') повертає масив ідентифікаторів. Щось на зразок цієї роботи:$training->users()->sync( array( $speakers => array( 'is_speaker' => true ) ) )
Томица Кораћ

1
@JarekTkaczyk Дякую! Відповіддю на коментар було саме те, що я шукав!
Патрос

1
@JarekTkaczyk виглядає приємно, але кожен елемент оновлюється \ вставляється за допомогою окремого запиту, що трохи розчаровує, оскільки це вплине на продуктивність.
tylik

4

Кріплення / від'єднання

Eloquent також надає кілька додаткових допоміжних методів, щоб зробити роботу із суміжними моделями більш зручною. Наприклад, уявімо, що користувач може мати багато ролей, а роль може мати багато користувачів. Щоб приєднати роль до користувача, вставивши запис у проміжну таблицю, яка приєднує моделі, використовуйте метод приєднання:

$user = App\User::find(1);

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

Прикріплюючи відношення до моделі, ви також можете передати масив додаткових даних, які потрібно вставити в проміжну таблицю:

$user->roles()->attach($roleId, ['expires' => $expires]);

Ви також можете скористатися синхронізацією, якщо хочете видалити старі ролі та зберегти лише нові, які ви зараз додаєте

$user->roles()->sync([1 => ['expires' => $expires], 2 => ['expires' => $expires]);

Поведінку за замовчуванням можна змінити, передавши 'false' як другий аргумент. Це додасть ролі з ідентифікаторами 1,2,3, не впливаючи на існуючі ролі.

У цьому режимі синхронізація працює так само, як метод приєднання.

$user->roles()->sync([1 => ['expires' => $expires], 2 => ['expires' => $expires], false);

Довідково: https://laravel.com/docs/5.4/eloquent-relationships


2

Додайте наступну ознаку до свого проекту та додайте її до свого класу моделі як ознаку. Це корисно, оскільки це додає функціональність для використання кількох стержнів. Можливо, хтось може це трохи прибрати і вдосконалити;)

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

Модель:

namespace App;

use Illuminate\Database\Eloquent\Model;

class Example extends Model
{
    use Traits\AppTraits;
    // ...
}

Використання:

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

1
Мені подобається ваше мислення - краще перетворити його на щось багаторазове, а не копіювати наступного разу, коли з’явиться ця проблема - хоча я б рекомендував зробити його допоміжною функцією, щоб її можна було використовувати де завгодно та з будь-якою моделлю.
DevBodin

0

Просто додайте свої поля та їх значення до елементів:

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

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

8
Відповідаючи на стару публікацію, було б корисно, якщо б ви могли надати певний контекст своїй відповіді, а не просто код, оскільки це може зробити її більш корисною для інших.
Девід Бак,

Див. Коментар Девіда Бакса. Також включіть версії програмного забезпечення та / або системи та / або бібліотеки; єдиний спосіб запобігти голосуванню чи вилученню відповіді.
ZF007
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.