web-dev-qa-db-fra.com

Empêcher Laravel ajouter plusieurs enregistrements à un tableau croisé dynamique)

J'ai plusieurs relations à mettre en place et à utiliser pour ajouter un article au panier que j'utilise:

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

Ce qui ajoute un élément au tableau croisé dynamique (comme il se doit), mais si l'utilisateur clique à nouveau sur le lien pour ajouter un élément déjà ajouté, il crée une entrée en double dans le tableau croisé dynamique.

Existe-t-il un moyen intégré d’ajouter un enregistrement à un tableau croisé dynamique s’il n’existe pas déjà?

Si non, comment puis-je consulter le tableau croisé dynamique pour rechercher si un enregistrement correspondant existe déjà?

84
Al_

Vous pouvez vérifier la présence d'un enregistrement existant en écrivant une condition très simple comme celle-ci:

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

Ou/et si vous pouvez ajouter une condition d'unicité dans votre base de données, une exception serait lancée lors d'une tentative d'enregistrement d'un doublet.

Vous devriez également jeter un coup d'œil à la réponse plus simple de Barryvdh juste en dessous.

70
Alexandre Butynski

Vous pouvez également utiliser la méthode $model->sync(array $ids, $detaching = true) et désactiver le détachement (le deuxième paramètre).

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

Mise à jour: Depuis Laravel 5.3 ou 5.2.44, vous pouvez également appeler syncWithoutDetaching:

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

Ce qui fait exactement la même chose, mais plus lisible :)

234
Barryvdh

La méthode @alexandre Butynsky fonctionne très bien, mais utilise deux requêtes SQL.

Un pour vérifier si le panier contient l'article et un pour sauvegarder.

Pour utiliser une seule requête, utilisez ceci:

try {
    $cart->items()->save($newItem);
}
catch(\Exception $e) {}
2
Octavian Ruda

Même si toutes ces réponses sont valables parce que je les ai toutes essayées, une chose est toujours laissée sans réponse ou non prise en charge: le problème de la mise à jour d'une valeur vérifiée précédemment (décochez la case cochée). J'ai quelque chose de similaire à la question ci-dessus, attendez-vous à vérifier et décocher les fonctionnalités des produits dans mon tableau de fonctionnalités (le tableau croisé dynamique). Je suis un débutant et je me suis rendu compte qu'aucun de ce qui précède ne l'a fait. Les deux sont bons lors de l’ajout de nouvelles fonctionnalités, mais pas lorsque je souhaite supprimer des fonctionnalités existantes (c-à-d. Décochez-la)

J'apprécierai toute illumination à ce sujet.

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

ou

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

Désolé les gars, je ne suis pas sûr que je devrais supprimer la question parce que, ayant trouvé la réponse moi-même, cela semble un peu stupide, et bien la réponse à ce qui précède est aussi simple que de travailler avec @Barryvdh sync () comme suit; avoir lu de plus en plus sur:

$features = $request->get('features');
if (isset($features) && Count($features)>0){
    $product->features()->sync($features);
}
1
adeguk Loggcity

Vous pouvez simplement utiliser

$cart->items()->sync($items)

À partir de Laravel 5.7:

Synchronisation d'associations Vous pouvez également utiliser la méthode sync pour construire des associations plusieurs à plusieurs. La méthode sync accepte un tableau d'ID à placer sur la table intermédiaire. Tous les ID qui ne figurent pas dans le tableau donné seront supprimés de la table intermédiaire. Ainsi, une fois cette opération terminée, seuls les ID du tableau donné existeront dans la table intermédiaire:

1
Shreyansh Panchal

Il y a déjà d'excellentes réponses postées. Je voulais jeter celui-ci ici aussi.

Les réponses de @AlexandreButynski et @Barryvdh sont plus lisibles que ma suggestion. Cette réponse ajoute une certaine efficacité.

Il ne récupère que les entrées de la combinaison actuelle (en réalité, seul l'id) et le lie s'il est inexistant. La méthode sync (même sans détacher) récupère tous les identifiants actuellement attachés. Pour les plus petits ensembles avec de petites itérations, cela ne fera guère de différence, ... vous comprenez mon point.

Quoi qu'il en soit, ce n'est certainement pas aussi lisible, mais ça fait l'affaire.

if (is_null($book->authors()->find($author->getKey(), [$author->getQualifiedKeyName()])))
    $book->authors()->attach($author);
0
Peter de Kok