Product Attribute Management in Laravel, storing Product attributes such as Size, Color, Weight.
Products (id, name, desc, visible)
# 1, Shirt, Description, true
# 2, Laptop, Description, true
Skus (id, price, slug, product_id, stock_qty, on_stock = true)
# 1, 5.00, 'sku-100', 1, 55 // S-Blue
# 2, 6.00, 'sku-200', 1, 66 // S-Red
# 3, 7.00, 'sku-300', 1, 77 // M-Blue
# 4, 8.00, 'sku-400', 1, 88 // M-Red
# 10, 500, 'sku-501', 2, 3 // Intel-32GB
# 11, 600, 'sku-502', 2, 5 // Intel-64GB
# 12, 500, 'sku-601', 2, 8 // Amd-32GB
# 13, 600, 'sku-602', 2, 4 // Amd-64GB
Attributes (id, product_id, name)
# 1, 1, Size
# 2, 1, Color
# 3, 2, Procesor
# 4, 2, Ram
Properties (id, attribute_id, name)
# 1, 1, S
# 2, 1, M
# 3, 2, Blue
# 4, 2, Red
# 5, 3, Intel
# 6, 3, Amd
# 7, 4, 32GB
# 8, 4, 64GB
# Pivot table (or with 'property_id' not 'value')
attribute_sku (id, attribute_id, sku_id, value)
# 1,1,1,S
# 2,2,1,Blue
# 3,1,2,S
# 4,2,2,Red
# 5,1,3,M
# 6,2,3,Blue
# 7,1,4,M
# 8,2,4,Red
# 21,3,10,Intel
# 22,4,10,32GB
# 23,3,11,Intel
# 24,4,11,64GB
# 25,3,12,Amd
# 26,4,12,32GB
# 27,3,13,Amd
# 28,4,13,64GB
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Product extends Model
{
/** @use HasFactory<\Database\Factories\ProductFactory> */
// use HasFactory;
protected $with = [];
protected $guarded = [];
protected function casts(): array
{
return [
'created_at' => 'datetime:Y-m-d H:i:s',
];
}
public function skus(): HasMany
{
return $this->hasMany(Sku::class, 'product_id');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\MorphOne;
use Illuminate\Database\Eloquent\Relations\MorphMany;
class Sku extends Model
{
/** @use HasFactory<\Database\Factories\SkuFactory> */
// use HasFactory;
protected $with = ['attributes', 'images', 'product'];
protected $guarded = [];
protected function casts(): array
{
return [
'created_at' => 'datetime:Y-m-d H:i:s',
];
}
public function product(): BelongsTo
{
return $this->belongsTo(Product::class, 'product_id');
}
public function attributes(): BelongsToMany
{
return $this->belongsToMany(Attribute::class, 'attribute_sku')->withPivot(['value']);
}
public function images(): MorphMany
{
return $this->morphMany(Image::class, 'imageable')->chaperone();
}
public function latestImage(): MorphOne
{
return $this->morphOne(Image::class, 'imageable')->latestOfMany();
}
public function oldestImage(): MorphOne
{
return $this->morphOne(Image::class, 'imageable')->oldestOfMany();
}
public function bestImage(): MorphOne
{
return $this->morphOne(Image::class, 'imageable')->ofMany('likes', 'max');
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
class Attribute extends Model
{
/** @use HasFactory<\Database\Factories\AttributeFactory> */
// use HasFactory;
protected $with = [];
protected $guarded = [];
protected function casts(): array
{
return [
'created_at' => 'datetime:Y-m-d H:i:s',
];
}
public function product(): BelongsTo
{
return $this->belongsTo(Product::class, 'product_id');
}
public function skus(): BelongsToMany
{
return $this->belongsToMany(Sku::class, 'attribute_sku')->withPivot(['value']);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
class Image extends Model
{
/** @use HasFactory<\Database\Factories\ImageFactory> */
// use HasFactory;
protected $with = [];
protected $guarded = [];
protected function casts(): array
{
return [
'created_at' => 'datetime:Y-m-d H:i:s',
];
}
/**
* Get the parent model (skus or other).
*/
public function imageable(): MorphTo
{
return $this->morphTo();
}
}
$product->skus->pluck('attributes')->flatten()->groupBy('name')->map(function ($item) {
return $item->keyBy('pivot.value');
});
https://laracasts.com/discuss/channels/laravel/best-way-to-store-product-attributes-like-size-color-etc?page=1&replyId=752232