dushano's avatar
Level 13

Eloquent best approach

Hi all. I'm interested in how would you approach and what would be your solution to the following.

For example, models Product, ProductVariant, Attribute, AttributeValue. Product has many ProductVariant, Attribute has many AttributeValue, and pivot table between AttributeValue and ProductVariant.

What would be the best approach for getting attribute values grouped by attribute and doing that from Product model. For example, from Product i want to get all the colors that variants of the product have.

0 likes
2 replies
LaryAI's avatar
Level 58

To achieve the desired result, you can use Eloquent's relationships and eager loading to efficiently retrieve the attribute values grouped by attribute for a product. Here's a step-by-step solution:

  1. Define the relationships in your Eloquent models.
class Product extends Model
{
    public function variants()
    {
        return $this->hasMany(ProductVariant::class);
    }
}

class ProductVariant extends Model
{
    public function attributeValues()
    {
        return $this->belongsToMany(AttributeValue::class);
    }
}

class Attribute extends Model
{
    public function values()
    {
        return $this->hasMany(AttributeValue::class);
    }
}

class AttributeValue extends Model
{
    public function attribute()
    {
        return $this->belongsTo(Attribute::class);
    }
}
  1. Create a method in the Product model to retrieve the attribute values grouped by attribute.
class Product extends Model
{
    // ... existing relationships ...

    public function getAttributeValuesGroupedByAttribute()
    {
        return $this->variants()
            ->with('attributeValues.attribute')
            ->get()
            ->pluck('attributeValues')
            ->flatten() // Flatten the collection of collections into a single collection
            ->groupBy(function ($attributeValue) {
                return $attributeValue->attribute->name; // Group by attribute name
            });
    }
}
  1. Use the method to get the attribute values for a specific product.
$product = Product::find($productId); // Replace $productId with the actual product ID
$groupedAttributeValues = $product->getAttributeValuesGroupedByAttribute();

// If you want to get only the colors
$colors = $groupedAttributeValues->get('Color'); // Replace 'Color' with the actual attribute name for colors

This approach will give you a collection where each key is an attribute name and the value is a collection of AttributeValue models that belong to that attribute. If you want to get all the colors that variants of the product have, you can simply access the collection by the attribute name (e.g., 'Color').

Keep in mind that this solution assumes that you have a 'name' column in your attributes table to identify the attribute by name. Adjust the code accordingly if your database schema is different.

Tray2's avatar

I would make that a table for the attributes and their values.

Product:

  • id
  • name
  • price
  • part_no

Product_attributes:

  • id
  • product_id
  • attribute
  • value

That would then mean that if you have a computer and a t-shirt they would have similar to this

  1. Computer
  2. T-shirt
1		1		CPU	Intel i9
2		1		GPU	ATI Radeon 7900
3		1		RAM	32GB
4	    2		Color	White
5		2		Size	XL

that way you will be flexible with the attributes.

1 like

Please or to participate in this conversation.