Laravel зберігає / оновлює стосунки багатьох до багатьох


85

Хто-небудь може мені допомогти, як заощадити стосунки багатьох до багатьох? У мене є завдання, користувач може мати багато завдань, і завдання може мати багато користувачів (багато-багато-багато). Що я хочу досягти, так це те, що у формі оновлення адміністратор може призначити декількох користувачів для конкретного завдання. Це робиться за допомогою вводу кількох виділень html

name="taskParticipants[]"

Фішка тут полягає в тому, що за допомогою тієї ж форми (введення) ви можете додавати / видаляти користувачів, ось чому я повинен використовувати sync (). Можливо, мені слід почати спочатку, але не знаю, з чого почати ...

Це моя модель користувача:

public function tasks()
{
    return $this->belongsToMany('Task','user_tasks');
}

Модель завдання

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

Це структура таблиць завдань ідентифікатор | заголовок | термін

user_tasks
id|task_id|user_id

Я оновив свій код. посилання
SuperManSL

4
$workers = Input::get('taskParticipants'); $task->taskParticipants()->sync($workers);і це все, що вам потрібно, якщо ви переходите з цієї форми до всіх користувачів, призначених для завдання.
Ярек Ткачик

@JarekTkaczyk Дякую, це було чарівно.
Ryu_hayabusa

Відповіді:


191

tldr; Використовувати syncз 2-м параметромfalse


Відносини багато-до-багатьох belongsToManyстосуються обох моделей:

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

Для того, щоб додати нове відношення, використовуйте attachабо sync.

Різниця між ними:

1 attach додасть новий рядок у зведену таблицю, не перевіряючи, чи він уже там. Добре, коли у вас є додаткові дані, пов’язані з цим відношенням, наприклад:

Userі Examпов’язані зі зведеною таблицеюattempts: id, user_id, exam_id, score

Я вважаю, це не те, що потрібно у вашій ситуації:

$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 з іншого боку, або видалить всі відносини, і встановить їх заново:

$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6]

$user->tasks()->sync([1,2,3]);
// then
$user->tasks()->getRelatedIds(); // [1,2,3]

або це налаштує нові відносини без від'єднання попередніх І без додавання дублікатів:

$user->tasks()->sync([5,6,7,8], false); // 2nd param = detach
// then
$user->tasks()->getRelatedIds(); // [1,2,3,4,5,6,7,8]

8
Було б непогано, якби це було задокументовано в основних документах, а не в документах API! Рок на. +1.
ceejayoz,

Мені дуже подобається друге рішення із синхронізацією та 2-м параметром. Як я вже сказав у коментарі нижче, я не можу дозволити собі не використовувати від'єднання. Історія полягає в тому, що адміністратор може призначити завдання користувачам. Він вибирає користувачів зі спадного меню (кілька), поле учасників []. Отже ...: Крок 1: адміністратор призначає завдання A трьом користувачам (ваш метод працює, у нас є 3 записи в БД) Крок 2: адміністратор оновить завдання A і додає двох користувачів (ваш метод працює, у нас є 5 записів у БД) Крок 3: адміністратор оновлює завдання A та видаляє 1 користувача (ваш метод не працює, у нас все ще є 5 користувачів замість 4) мій метод оновлення мій код
SuperManSL

1
Ви можете спростити запит щодо стосунків, лише $this->belongsToMany('User')якщо ви використовуєте назву таблиці в алфавітному та одиничному (таким чином, task_userзамість user_tasks)
Kousha

@Rok, якщо ви завжди передаєте масив усіх пов'язаних користувачів, тоді використовуйте syncз від'єднанням, не турбуйтеся. Я пропоную використовувати параметр 2, встановлений у значення false, коли ви хочете "додати нове завдання для користувача" або "призначити користувача для завдання", коли ви передаєте одну idз пов'язаних моделей.
Ярек Ткачик

1
@FabioAntunes syncповертає масив detached, attachedі updatedсписки. attachнічого не повертає, але в обох випадках ви отримаєте виняток, якщо в дзвінках db трапиться щось несподіване.
Ярек Ткачик

106

Ось мої примітки про те, як зберегти та оновити всі красномовні стосунки.

в один до одного :

Вам потрібно використовувати HasOne для першої моделі та BelongsTo для другої моделі

щоб додати запис на першу модель ( HasOne ) використовувати збереження  функції

приклад:    $post->comments()->save($comment);

щоб додати запис на другий моделі ( BelongsTo ) використовувати  ад'юнкт функцію

приклад:    $user->account()->associate($account);    $user->save();


в одному до багатьох :

Вам потрібно використовувати HasMany для першої моделі та BelongsTo для другої моделі

щоб додати запис на першому столі ( HasMany ) використовувати зберегти  або saveMany функції

приклад:    $post->comments()->saveMany($comments);

щоб додати запис на другий моделі ( BelongsTo ) використовувати  ад'юнкт функцію

приклад:    $user->account()->associate($account);    $user->save();


у багатьох до багатьох :

Ви повинні використовувати  BelongsToMany для першої моделі та BelongsToMany для другої моделі

додавати записи про використання зведеної таблиці приєднувати або синхронізації функції

  • обидві функції приймають один ідентифікатор або масив ідентифікаторів 

  • різниця полягає у перевірці вкладень, якщо запис уже існує у зведеній таблиці, а синхронізація - ні

приклад: $user->roles()->attach($roleId);


у поліморфному - одному до багатьох :

Ви повинні використовувати  MorphMany для основної моделі та  MorphTo для всіх моделей (*** здатних)

щоб додати записи на всіх інших моделях, використовуйте  збереження

приклад:    $course->tags()->save($tag);

зведена таблиця повинна мати такі стовпці:

. основний ідентифікатор моделі

. (*** здатний) посвідчення особи

. (*** здатний) Тип


у поліморфному багато до багатьох :

Ви повинні використовувати  MorphByMany для основної моделі та  MorphToMany для всіх моделей (*** здатних)

щоб додати записи на всіх інших моделях, використовуйте save або saveMany

приклад:    $course->tags()->save($tag);

приклад:    $course->tags()->saveMany([$tag_1, $tag_2, $tag_3]);

зведена таблиця повинна мати такі стовпці:

. основний ідентифікатор моделі

. (*** здатний) посвідчення особи

. (*** здатний) Тип


у має багато наскрізних (ярлик):

Вам потрібно використовувати HasManyThrough у першій таблиці, а нормальні відносини - у інших 2 таблицях

це не працює для відносин ManyToMany (де є зведена таблиця)

однак є гарне і просте рішення саме для цього.


Ось стаття, яку я написав, натхненний цією відповіддю. Важливо перевірити це: https://hackernoon.com/eloquent-relationships-cheat-sheet-5155498c209


Я насправді розмістив цю відповідь, коли вони вже мали понад 40 вподобань за правильну відповідь, але так, я знаю, наскільки це корисно для мене, радий, що вам сподобалось :)
Махмуд Зальт

1
Я хотів би, щоб ти знав, що ти спаситель
Chay22

1
це чудова відповідь.
caro

1
як оновити один до травня. Ви пояснили, як додати. Ви можете пояснити оновлення? чи існує метод оновлення записів подібним чином updateMany? подяка
Хамідреза


0

syncФункція стирає залишають відносини і робить ваш масив весь список відносин. Ви хочете attachнатомість додати стосунки, не видаляючи інших.


Я не можу використовувати вкладення, оскільки я використовую цей код всередині методу оновлення. Історія полягає в тому, що адміністратор може оновити завдання та заповнити учасників введення [] користувачами, які братимуть участь у завданні. Тому мені потрібно перевірити, чи він існує, і видалити (або не додавати новий запис) його, або якщо він не існує, додати його.
SuperManSL
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.