2013-07-04 13 views
60

Mam wiele do wielu relacji skonfigurowana i działa, aby dodać element do koszyka używać:Zapobieganie laravel dodanie wielu rekordów do tabeli przestawnej

$cart->items()->attach($item); 

który dodaje element do tabeli przestawnej (tak jak powinien), ale jeśli użytkownik kliknie link ponownie, aby dodać element, który już dodał, tworzy zduplikowany wpis w tabeli przestawnej.

Czy jest wbudowany sposób dodawania rekordu do tabeli przestawnej tylko wtedy, gdy jeszcze nie istnieje?

Jeśli nie, jak mogę sprawdzić tabelę przestawną, aby sprawdzić, czy pasujący rekord już istnieje?

Odpowiedz

54

można sprawdzić obecność istniejącego rekordu pisząc bardzo prosty stan podobny do tego:

if (! $cart->items->contains($newItem->id)) { 
    $cart->items()->save($newItem); 
} 

i/lub można dodać warunek jedyności w bazie danych, to wyjątek podczas próby uratowania dubletu.

Powinieneś również rzucić okiem na bardziej bezpośrednią odpowiedź od Barryvdha tuż poniżej.

+1

parametr id $ dla metody 'attach()' jest mieszana, to może być int lub instancja modelu;) - zobacz https://github.com/laravel /framework/blob/master/src/Illuminate/Database/Eloquent/Relations/BelongsToMany.php?source=cc#L589 –

+0

Dziękujemy @RobGordijn. Nauczyłem się czegoś dzisiaj! Odpowiedź edytowana. –

+0

Jaki jest cel oświadczenia "zawiera"? Nie mogłem znaleźć żadnych duplikatów dla mnie, więc nadal mam błąd duplikacji, gdy używam tego. –

2

Metoda @samxandre Butynsky działa bardzo dobrze, ale używa dwóch kwerend sql.

Jeden do sprawdzenia, czy koszyk zawiera przedmiot i jeden do zapisania.

Aby skorzystać tylko jedno zapytanie użyj:

try { 
    $cart->items()->save($newItem); 
} 
catch(\Exception $e) {} 
+0

Tak właśnie zrobiłem w moim projekcie. Ale problem polega na tym, że nie wiesz, czy ten wyjątek jest spowodowany przez zduplikowany wpis lub cokolwiek innego. –

+1

dlaczego byłby to wyjątek? Byłoby, gdyby był jakiś unikalny klucz. –

169

Można również użyć metody $model->sync(array $ids, $detaching = true) i wyłączyć odłączania (drugi param).

$cart->items()->sync([$item->id], false); 

Aktualizacja: Od laravel 5.3 lub 5.2.44, można również zadzwonić syncWithoutDetaching:

$cart->items()->syncWithoutDetaching([$item->id]); 

który robi dokładnie to samo, ale bardziej czytelny :)

+9

Najmądrzejsza odpowiedź w historii. –

+2

Drugi parametr boolowski, który zapobiega odłączaniu niepublicznych identyfikatorów, nie znajduje się w głównej dokumentacji L5. Bardzo dobrze jest wiedzieć - wydaje się być jedynym sposobem, aby "dołączyć, jeśli nie jest już dołączony" w jednym oświadczeniu. – Jason

+3

To powinno być zaakceptowane jako odpowiedź, jest to o wiele lepszy sposób niż zaakceptowana odpowiedź – Daniel

0

Tak dobre, jak wszyscy te odpowiedzi są, ponieważ wypróbowałem je wszystkie, jedna rzecz wciąż pozostaje bez odpowiedzi lub nie zajęta: kwestia aktualizacji poprzednio sprawdzonej wartości (odznaczono pole wyboru [es]). Mam coś podobnego do powyższego pytania, chcę sprawdzić i odznaczyć funkcje produktów w mojej tabeli funkcji produktu (tabela przestawna). Jestem początkującym i zdałem sobie sprawę, że żaden z powyższych nie zrobił tego. Oba są dobre przy dodawaniu nowych funkcji, ale nie wtedy, gdy chcę usunąć istniejące funkcje (to jest usunąć zaznaczenie).

Doceniam każde oświecenie.

$features = $request->get('features'); 

if (isset($features) && Count($features)>0){ 
    foreach ($features as $feature_id){ 
     $feature = Feature::whereId($feature_id)->first(); 
     $product->updateFeatures($feature); 
    } 
} 

//product.php (extract) 
public function updateFeatures($feature) { 
     return $this->features()->sync($feature, false); 
} 

lub

public function updateFeatures($feature) { 
    if (! $this->features->contains($features)) 
     return $this->features()->attach($feature); 
} 
//where my attach() is: 
public function addFeatures($feature) { 
     return $this->features()->attach($feature); 
} 

Sorry chłopaki, nie wiem, to powinienem usunąć pytanie, ponieważ mający znaleźć odpowiedź sam, brzmi to nieco głupie, ale odpowiedź na powyższe jest tak proste jak praca @Barryvdh sync() w następujący sposób; po zapoznaniu się coraz więcej na temat:

$features = $request->get('features'); 
if (isset($features) && Count($features)>0){ 
    $product->features()->sync($features); 
} 
Powiązane problemy