feat: refactor product attributes handling to use product_attribute table and update related models and requests

This commit is contained in:
2026-06-30 16:35:56 -03:00
parent 191a40fcb9
commit cb15905c46
15 changed files with 189 additions and 63 deletions

View File

@@ -9,6 +9,7 @@ use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough;
#[Fillable([
'tenant_codigo',
@@ -53,10 +54,25 @@ class Attribute extends Model
}
/**
* @return HasMany<ProductVariantDefinition, $this>
* @return HasMany<ProductAttribute, $this>
*/
public function variantDefinitions(): HasMany
public function productAttributes(): HasMany
{
return $this->hasMany(ProductVariantDefinition::class, 'attribute_id');
return $this->hasMany(ProductAttribute::class, 'attribute_id');
}
/**
* @return HasManyThrough<ProductVariantDefinition, ProductAttribute, $this>
*/
public function variantDefinitions(): HasManyThrough
{
return $this->hasManyThrough(
ProductVariantDefinition::class,
ProductAttribute::class,
'attribute_id',
'products_attribute_id',
'id',
'id'
);
}
}

View File

@@ -5,6 +5,7 @@ namespace App\Domains\Catalog\Models;
use App\Domains\Attachable\Models\Attachment;
use App\Domains\Catalog\Models\Brand;
use App\Domains\Catalog\Models\Category;
use App\Domains\Catalog\Models\ProductAttribute;
use App\Domains\Tenant\Models\Tenant;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
@@ -83,6 +84,14 @@ class Product extends Model
)->withTimestamps();
}
/**
* @return HasMany<ProductAttribute, $this>
*/
public function productAttributes(): HasMany
{
return $this->hasMany(ProductAttribute::class, 'product_id');
}
/**
* @return BelongsToMany<Attachment, $this>
*/
@@ -170,20 +179,25 @@ class Product extends Model
protected function validateVariantDefinitions(array $definitions): void
{
foreach ($definitions as $definition) {
$attributeId = $definition['attribute_id'] ?? null;
if (!$attributeId) {
$productAttributeId = $definition['products_attribute_id'] ?? null;
if (! $productAttributeId) {
continue;
}
$attribute = Attribute::find($attributeId);
if (!$attribute) {
throw new \InvalidArgumentException("Attribute with ID {$attributeId} not found.");
$productAttribute = $this->productAttributes()
->with('attribute.options')
->find($productAttributeId);
$attribute = $productAttribute?->attribute;
if (! $productAttribute || ! $attribute) {
throw new \InvalidArgumentException("Product attribute with ID {$productAttributeId} not found for product {$this->id}.");
}
if ($attribute->type === \App\Domains\Shared\Enums\FieldType::Select) {
$allowedValues = $attribute->options()->pluck('value')->toArray();
$val = $definition['value'] ?? null;
if ($val !== null && !in_array($val, $allowedValues, true)) {
if ($val !== null && ! in_array($val, $allowedValues, true)) {
throw new \InvalidArgumentException("The value '{$val}' is not a valid option for the select attribute '{$attribute->nombre}'.");
}
} elseif ($attribute->type === \App\Domains\Shared\Enums\FieldType::Multiselect) {
@@ -202,7 +216,7 @@ class Product extends Model
}
}
foreach ($values as $v) {
if (!in_array($v, $allowedValues, true)) {
if (! in_array($v, $allowedValues, true)) {
throw new \InvalidArgumentException("The value '{$v}' is not a valid option for the multiselect attribute '{$attribute->nombre}'.");
}
}

View File

@@ -0,0 +1,44 @@
<?php
namespace App\Domains\Catalog\Models;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
#[Fillable([
'product_id',
'attribute_id',
])]
class ProductAttribute extends Model
{
use HasFactory;
protected $table = 'products_attributes';
/**
* @return BelongsTo<Product, $this>
*/
public function product(): BelongsTo
{
return $this->belongsTo(Product::class, 'product_id');
}
/**
* @return BelongsTo<Attribute, $this>
*/
public function attribute(): BelongsTo
{
return $this->belongsTo(Attribute::class, 'attribute_id');
}
/**
* @return HasMany<ProductVariantDefinition, $this>
*/
public function variantDefinitions(): HasMany
{
return $this->hasMany(ProductVariantDefinition::class, 'products_attribute_id');
}
}

View File

@@ -9,7 +9,7 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
#[Fillable([
'producto_variante_id',
'attribute_id',
'products_attribute_id',
'value',
])]
class ProductVariantDefinition extends Model
@@ -27,10 +27,10 @@ class ProductVariantDefinition extends Model
}
/**
* @return BelongsTo<Attribute, $this>
* @return BelongsTo<ProductAttribute, $this>
*/
public function attribute(): BelongsTo
public function productAttribute(): BelongsTo
{
return $this->belongsTo(Attribute::class, 'attribute_id');
return $this->belongsTo(ProductAttribute::class, 'products_attribute_id');
}
}