Laravel Pivot-Tabelle einmal Zuordnung erstellen, dann aktualisieren
Frage
Ich habe die folgenden Tabellen:
Benutzer:
userID
...
Lektion:
lessonID
...
Users_Lessons_Status (fungiert als Pivot-Tabelle und enthält andere Informationen):
userID references User.userID
lessonID references Lessons.lessonID
latestSectionID
percentComplete
Was ich tun möchte, ist, dass für jeden Benutzer für jede Lektion eine Zeile in der Pivot-Tabelle vorhanden sein sollte, aus der hervorgeht, wie viel der Benutzer in dieser Lektion abgeschlossen hat und wie seine letzte Abschnitts-ID lautete.Das heißt, es sollte ein eindeutiges Paar mit geben userID
und lessonID
(primärschlüssel?).
Ich habe meine Modelle so eingerichtet:
<?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');
}
}
?>
Meine aktuelle Route sieht so aus:
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')] );
}
});
Dies funktioniert, erstellt jedoch jedes Mal eine neue Zeile, wenn ich sie für dasselbe aktualisiere userID
und lessonID
, also ist das Paar nicht mehr einzigartig.Welche Methoden sollte ich für diesen Zweck verwenden?Ich habe beides ausprobiert save()
, attach()
und push()
in der Dokumentation, aber ich bin mir nicht sicher, welche ich hier verwenden soll.
Bearbeiten:zur Verdeutlichung sollte die resultierende Tabelle ungefähr so aussehen:
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
....
Bearbeiten 2:Das Problem wurde behoben User->belongsToMany()
methode und fügte die hinzu withPivot
nennen.
Lösung
Es scheint ein Fehler zu sein, trotzdem können Sie dies tun:
...->sync([$id], false); // detaching set to false, so it will only insert new rows, skip existing and won't detach anything
bearbeiten:Wie im Kommentar gesagt - es funktioniert bei Ihnen nicht, da Sie Pivot-Daten festlegen möchten.Grundsätzlich gibt es im Moment keine Methode, um dies zu tun, aber so etwas sollte reichen:
// 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);
}
}
Ich werde es testen und wenn es besteht, sende eine Pull-Anfrage an 4.1
Andere Tipps
Ich bin dem kürzlich begegnet und habe es auf diese Weise behoben:
Verwenden updateExistingPivot
zuerst und überprüfen Sie das Ergebnis, wenn das Ergebnis ist 1
es bedeutet, dass es Reihen mit dem gleichen gab userID
und lessonID
und es wurde erfolgreich aktualisiert, andernfalls, wenn das Ergebnis ist 0
es bedeutet, dass es keine Zeilen damit gab userID
und lessonID
, damit Sie es anhängen können, um eine neue Zeile zu erstellen
$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')] );
}
Sie sollten verwenden updateExistingPivot()
.
Aktualisieren Sie Ihren zu verwendenden Code
$us->updateExistingPivot($lesson->lessonID,
["latestSectionID" => Input::get('latestSectionID'), "percentComplete" => Input::get('percentComplete')], true );
Der letzte Parameter aktualisiert die Zeitstempel für alle zugehörigen Modelle.Wenn nicht, können Sie entfernen oder auf false setzen.
Wenn Sie nur anhängen möchten, wenn kein Datensatz vorhanden ist, können Sie so etwas tun...
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);
}
}
});