I have ProductCollection
Model and AttributeValue
Model which have a common table product_collection_attributes
that has 2 columns: product_collection_id
and attribute_value_id
that are a foreign key to their respective tables and are both a primary key.
In ProductCollection Model relation is:
public function attributes()
{
return $this->belongsToMany(AttributeValue::class, 'product_collection_attributes', 'product_collection_id');
}
And in AttributeValue Model relation is:
public function product_collections()
{
return $this->belongsToMany(ProductCollection::class, 'product_collection_attributes', 'attribute_value_id');
}
My query is: $productCollection->attributes()->get()
; which is returning an empty array,
However if query was DB::table('product_collection_attributes')->where('product_collection_id', $productCollection->id)->get();
its returning a full array!!
AND THE MOST IMPORTANT Thing this happens only after the following code, WHICH IS BREAKING with error: (Exception: "SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry '2-2' for key 'product_collection_attributes.PRIMARY' (Connection: mysql, SQL: insert into
product_collection_attributes (
attribute_value_id,
product_collection_id) values (2, 2))"
): `
$productCollection->update([
SOMEINFO...,
'allow_price_change' => 0
]);
$data['attributes'] = [1,2];
$productCollection->attributes()->delete();
if (isset($data['attributes']) && count($data['attributes'])) {
$data['attributes'] = array_unique($data['attributes']);
$data['attributes'] = array_values(array_filter($data['attributes']));
$productCollection->attributes()->attach($data['attributes']);
}
SO I REPLACED THE ABOVE CODE WITH:
$productCollection->update([
SOMEINFO...,
'allow_price_change' => 0
]);
$data['attributes'] = [1,2];
DB::table('product_collection_attributes')->where('product_collection_id', $productCollection->id)->delete();
if (isset($data['attributes']) && count($data['attributes'])) {
$data['attributes'] = array_unique($data['attributes']);
$data['attributes'] = array_values(array_filter($data['attributes']));
$productCollection->attributes()->attach($data['attributes']);
}
And NOW I have this problem, $productCollection->attributes()->get()
doesn’t work anymore!! and only DB::table('product_collection_attributes')->where('product_collection_id', $productCollection->id)->get();
works!!
And note that if I update something in product collection that isn't a boolean all works fine!!, so update $productCollection->update(['name' => 'aaa', ...]) then update attributes will be fine
I don’t know why and it is important to use ProductCollection::with(['attributes'])
in almost all of my cases specially with joins, and it is forcing me to use DB instead!
How can we fix that?
2
Answers
The problem was in the way I was doing the delete of $productCollection->attributes().
The Correct way
$productCollection->attributes()->detach();
And not ->delete().Problem was easy to see after migration refresh. What actually happened the record of the AttributeValue was deleted!! and I was using soft deletes so it was hard to notice!!
The new migration showed that.
SO fix is:
$productCollection->attributes()->detach();
the code seems to be functioning, there’s a potential issue in the product_collections() method definition. It’s defined in the AttributeValue model, but it’s named like it’s intended to fetch related ProductCollections. If you’re intending to get related ProductCollections, you should define the relationship in the AttributeValue model as productCollections() or something similar.