Сводная таблица Laravel создает ассоциацию один раз, а затем обновляет

StackOverflow https://stackoverflow.com//questions/23019239

  •  21-12-2019
  •  | 
  •  

Вопрос

У меня есть следующие таблицы:

Пользователь:

userID
...

Урок:

lessonID
...

Users_Lessons_Status (который действует как сводная таблица и содержит другую информацию):

userID references User.userID
lessonID references Lessons.lessonID
latestSectionID
percentComplete

Я хочу, чтобы для каждого пользователя, для каждого урока в сводной таблице была строка, в которой сообщалось, сколько пользователь выполнил на этом уроке и каков был его последний идентификатор раздела.То есть должна быть уникальная пара с userID и lessonID (первичные ключи?).

Я настроил свои модели следующим образом:

<?php

class User extends Eloquent implements UserInterface, RemindableInterface {

...


    public function lessonStatuses() 
    {
        return $this->belongsToMany('Lesson', 'users_lessons_status', 'lessonID', 'userID')->withPivot('latestSectionID', 'percentComplete');
    }

}

<?

class Lesson extends Eloquent {

protected $table = 'lessons';
protected $primaryKey = 'lessonID';

public function userStatuses()
{
    return $this->belongsToMany('User', 'users_lessons_status', 'userID', 'lessonID');
}


}

?>

Мой текущий маршрут выглядит так:

Route::post('dbm/users/setLatestSectionID', function() {
    if(Auth::check()) {
        $user = User::find(Input::get('userID'));
        $lesson = Lesson::find(Input::get('lessonID'));
        $us = $user->lessonStatuses(); 
        $us->attach($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    }
});

Это работает, однако оно создает новую строку каждый раз, когда я обновляю ее для одного и того же userID и lessonID, поэтому пара больше не уникальна.Какие методы следует использовать для этой цели?Я попробовал оба save(), attach() и push() в документации, но я не уверен, какой из них использовать здесь.

Редактировать:для ясности, результирующая таблица должна выглядеть примерно так:

id|userID|lessonID|latestSectionID|percentComplete
1    1      1             X             Y
2    1      2        
3    1      3         
4    2      1          
5    3      1
6    3      2
....

Редактировать 2:Исправлено User->belongsToMany() метод и добавил withPivot вызов.

Это было полезно?

Решение

Это похоже на ошибку, но вы можете сделать это:

...->sync([$id], false); // detaching set to false, so it will only insert new rows, skip existing and won't detach anything

редактировать:Как сказано в комментарии, у вас это не сработает, так как вы хотите установить сводные данные.Итак, на данный момент нет способа сделать это, но что-то вроде этого должно сделать:

// belongsToMany.php
public function attachOrUpdate($id, array $attributes = array(), $touch = true)
{
    if ($id instanceof Model) $id = $id->getKey();

    if ( ! $this->allRelatedIds()->contains($id)) // getRelatedIds() in prior to v5.4
    {
        return $this->attach($id, $attributes, $touch); 
    }
    else if ( ! empty($attributes))
    {
        return $this->updateExistingPivot($id, $attributes, $touch);
    }
}

Я протестирую его, и если он пройдёт, отправлю запрос на включение в версию 4.1.

Другие советы

Недавно я столкнулся с этим и исправил это следующим образом:

Использовать updateExistingPivot сначала и проверьте результат, если результат 1 это значит, что были такие же строки userID и lessonID и он был успешно обновлен, в противном случае, если результат 0 это значит, что с этим не было строк userID и lessonID, поэтому вы можете прикрепить его, чтобы создать новую строку

    $update_result = $us->updateExistingPivot($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    if($update_result == 0) {
        $us->attach($lesson->lessonID, 
            ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')] );
    }

Вы должны использовать updateExistingPivot().

Обновите свой код для использования

    $us->updateExistingPivot($lesson->lessonID, 
        ["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')], true );

Последний параметр обновит временные метки для всех связанных моделей.Если нет, вы можете удалить или установить значение false.

Если вы хотите прикреплять только тогда, когда запись не существует, вы можете сделать что-то вроде этого...

Route::post('dbm/users/setLatestSectionID', function() {
    if(Auth::check()) {
        $user = User::find(Input::get('userID'));

        $lesson = [
            "latestSectionID" => Input::get('latestSectionID'), 
            "percentComplete" => Input::get('percentComplete')
        ];

        $num_lessons = $user->lessonStatuses()->where('id', Input::get('lessonID'))->count();

        if($num_lessons == 0) {
            $user->attach($lesson->lessonID, $lesson);
        } else {
            $user->updateExistingPivot($lesson->lessonID, $lesson);

        }
    }
});
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top