121 votes

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

J'ai mis en place une relation de type "many to many" qui fonctionne pour ajouter un article au panier :

$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 qu'il a déjà ajouté, cela 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 uniquement s'il n'en existe pas déjà un ?

Sinon, comment puis-je vérifier le tableau croisé dynamique pour savoir si un enregistrement correspondant existe déjà ?

317voto

Robert Points 1

Vous pouvez également utiliser le $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 en plus lisible :)

81voto

Alexandre Butynski Points 6417

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 vous pouvez ajouter la condition d'unicité dans votre base de données, cela lancerait une exception lors d'une tentative de sauvegarde d'un doublet.

Vous devriez également consulter la réponse plus directe de Barryvdh.

2voto

Octavian Ruda Points 87

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

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

Pour n'utiliser qu'une seule requête, utilisez ceci :

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

1voto

adeguk Loggcity Points 124

Aussi bonnes que soient toutes ces réponses, car je les ai toutes essayées, une chose reste sans réponse ou n'est pas prise en compte : le problème de la mise à jour d'une valeur précédemment cochée (décochage de la ou des cases cochées). J'ai quelque chose de similaire à la question ci-dessus : je veux cocher et décocher les caractéristiques des produits dans mon tableau des caractéristiques des produits (le tableau croisé dynamique). Je suis un débutant et j'ai réalisé qu'aucune des solutions ci-dessus ne permettait de le faire. Elles sont toutes deux efficaces pour ajouter de nouvelles caractéristiques, mais pas pour supprimer des caractéristiques existantes (c'est-à-dire les décocher).

J'apprécierai tout éclaircissement à 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 doive supprimer la question parce que, ayant trouvé la réponse moi-même, elle semble un peu stupide, mais la réponse à ce qui précède est aussi simple que de faire fonctionner @Barryvdh sync() comme suit ; ayant lu de plus en plus sur.. :

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

1voto

Peter de Kok Points 11

D'excellentes réponses ont déjà été postées. Mais je voulais aussi vous soumettre celle-ci.

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

Il récupère seulement les entrées pour la combinaison courante (en fait seulement l'id) et il l'attache ensuite si elle n'existe pas. La méthode de synchronisation (même sans détachement) récupère tous les ids actuellement attachés. Pour les petits ensembles avec peu d'itérations, cela ne fera pas de différence, ... vous comprenez ce que je veux dire.

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

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X