Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing Laravel adding multiple records to a pivot table

You can also use the $model->sync(array $ids, $detaching = true) method and disable detaching (the second param).

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

Update: Since Laravel 5.3 or 5.2.44, you can also call syncWithoutDetaching:

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

Which does exactly the same, but more readable :)


You can check the presence of an existing record by writing a very simple condition like this one :

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

Or/and you can add unicity condition in your database, it would throw an exception during an attempt of saving a doublet.

You should also take a look at the more straightforward answer from Barryvdh just below.


@alexandre Butynsky method works very well but use two sql queries.

One to check if cart contains the item and one to save.

To use only one query use this:

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

As good as all this answers are because I had tried them all, one thing is still left unanswer or not taken care of: the issue of updating a previously checked value (unchecked the checked box[es]). I do have something similar to the above question expect i want to check and uncheck features of products in my product-feature table (the pivot table). I am a newbie and I have realised none of the above did that. The are both good when adding new features but not when i want to remove existing features (i.e. uncheck it)

I will appreciate any enlightenment in to this.

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

or

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 guys, not sure is I should delete the question because having figure out the answer myself, it sounds a bit stupid, well the answer to the above is as simple as working @Barryvdh sync() as follows; having read more and more about:

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

There are some great answers posted already. I wanted to throw this one out here as well though.

The answers from @AlexandreButynski and @Barryvdh are more readable than my suggestion, what this answer adds is some efficiency.

It retrieves only the entries for the current combination (actually only the id) and it than attaches it if it does not exist. The sync method (even without detaching) retrieves all currently attached ids. For smaller sets with little iterations this will hardly be a difference, ... you get my point.

Anyway, it is definitely not as readable, but it does the trick.

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