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

J'ai une relation plusieurs à plusieurs configurée et fonctionnant, pour ajouter un article au panier que j'utilise:

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

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é, 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 uniquement s'il n'existe pas déjà?

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

73
demandé sur Al_ 2013-07-04 17:53:36

4 réponses

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 une condition unicity dans votre base de données, il lancerait une exception lors d'une tentative d'enregistrement d'un doublet.

Vous devriez également jeter un oeil à la réponse plus simple de Barryvdh juste ci-dessous.

59
répondu Alexandre Butynski 2017-07-04 14:33:25

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

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

195
répondu Barryvdh 2016-08-19 17:23:42

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 enregistrer.

Pour utiliser une seule requête, utilisez ceci:

try {
    $cart->items()->save($newItem);
}
catch(\Exception $e) {}
3
répondu Octavian Ruda 2014-02-25 15:45:40

Aussi bien que toutes ces réponses soient parce que je les avais toutes essayées, une chose est toujours laissée sans réponse ou non prise en charge: la question de la mise à jour d'une valeur précédemment cochée (décochée la case cochée[es]). J'ai quelque chose de similaire à la question ci-dessus s'attendre à ce que je veux vérifier et décocher les fonctionnalités des produits dans mon tableau de fonctionnalités de produits (le tableau croisé dynamique). Je suis un débutant et j'ai réalisé 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 quand je veux l'enlever caractéristiques existantes (c'est-à-dire décochez-la)

J'apprécierai toute illumination à cela.

$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, pas sûr que je devrais supprimer la question parce qu'ayant trouvé la réponse moi-même, cela semble un peu stupide, Eh bien la réponse à ce qui précède est aussi simple que de travailler @ 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);
}
0
répondu adeguk 2017-10-06 01:32:51