diff --git a/src/Http/Controllers/ProductController.php b/src/Http/Controllers/ProductController.php index cc11e2460..9876023fa 100644 --- a/src/Http/Controllers/ProductController.php +++ b/src/Http/Controllers/ProductController.php @@ -12,7 +12,7 @@ public function show(int $productId) $productModel = config('rapidez.models.product'); $product = $productModel::selectForProductPage() ->withEventyGlobalScopes('productpage.scopes') - ->with('options') + ->with('options', 'attrs') ->findOrFail($productId); $attributes = [ diff --git a/src/Models/OptionValue.php b/src/Models/OptionValue.php index faadc4b89..3c27bf86d 100644 --- a/src/Models/OptionValue.php +++ b/src/Models/OptionValue.php @@ -10,17 +10,19 @@ class OptionValue extends Model protected $primaryKey = 'value_id'; - public static function getCachedByOptionId(int $optionId): string + public static function getCachedByOptionId(int $optionId, ?int $attributeId = null, mixed $default = false): string { $cacheKey = 'optionvalues.' . config('rapidez.store'); $cache = Cache::store('rapidez:multi')->get($cacheKey, []); if (! isset($cache[$optionId])) { - $cache[$optionId] = html_entity_decode(self::where('option_id', $optionId) + $cache[$optionId] = html_entity_decode(self::where('eav_attribute_option_value.option_id', $optionId) ->whereIn('store_id', [config('rapidez.store'), 0]) + ->join('eav_attribute_option', 'eav_attribute_option.option_id', '=', 'eav_attribute_option_value.option_id') ->orderByDesc('store_id') + ->when($attributeId, fn ($query) => $query->where('attribute_id', $attributeId)) ->first('value') - ->value ?? false); + ->value ?? $default); Cache::store('rapidez:multi')->forever($cacheKey, $cache); } diff --git a/src/Models/Product.php b/src/Models/Product.php index b15cb8acb..eab8e21f7 100644 --- a/src/Models/Product.php +++ b/src/Models/Product.php @@ -233,6 +233,62 @@ public function getThumbnailAttribute($image): ?string return $this->getImageAttribute($image); } + public function attrs(): HasMany + { + return $this->hasMany( + ProductAttribute::class, + 'entity_id', + 'entity_id', + ); + } + + public function getAttribute($key) + { + if (($value = parent::getAttribute($key)) !== null || $this->hasAttribute($key)) { + return $value; + } + + // TOOD: Not sure if this is very efficient, first we're + // searching for the attribute by code for the id and + // after that we're searching for the attribute id + // between the product attributes for the value. + $attributeModel = config('rapidez.models.attribute'); + $attributes = $attributeModel::getCachedWhere(function ($attribute) use ($key) { + return $attribute['code'] == $key; + }); + + if (! count($attributes) || ! $attribute = reset($attributes)) { + return null; + } + + $this->loadMissing('attrs'); + // TODO: Check for a custom value for a store. So if store 1 overwrites store 0. + if (! $value = optional($this->attrs->firstWhere('attribute_id', $attribute['id']))->value) { + return null; + } + + if ($attribute['input'] == 'multiselect') { + foreach (explode(',', $value) as $optionValueId) { + $values[] = OptionValue::getCachedByOptionId($optionValueId, $attribute['id'], $optionValueId); + } + $this->setAttribute($key, $values); + + return $values; + } + + if ($attribute['input'] == 'select' && $attribute['type'] == 'int' && ! ($attribute['system'] ?? false)) { + $value = OptionValue::getCachedByOptionId($value, $attribute['id'], $value); + } + + if ($key == 'url_key') { + return '/' . ($value ? $value . Rapidez::config('catalog/seo/product_url_suffix') : 'catalog/product/view/id/' . $this->entity_id); + } + + $this->setAttribute($key, $value); + + return $value; + } + protected function breadcrumbCategories(): Attribute { return Attribute::make( diff --git a/src/Models/ProductAttribute.php b/src/Models/ProductAttribute.php new file mode 100644 index 000000000..28b6d35f7 --- /dev/null +++ b/src/Models/ProductAttribute.php @@ -0,0 +1,35 @@ +select([ + 'entity_id', + 'attribute_id', + 'store_id', + 'value', + ]) + ->whereIn('store_id', [config('rapidez.store'), 0]) + ->whereNotNull('value'); + + $baseQuery = clone $builder->getQuery(); + foreach (['int', 'text', 'decimal'] as $type) { + $typeTable = 'catalog_product_entity_' . $type; + $typeQuery = (clone $baseQuery)->from($typeTable); + $typeQuery->wheres[0]['column'] = $typeTable . '.entity_id'; + $builder->unionAll($typeQuery); + } + }); + } +} diff --git a/src/Models/Traits/Product/SelectAttributeScopes.php b/src/Models/Traits/Product/SelectAttributeScopes.php index eadbaab5d..c3c085d60 100644 --- a/src/Models/Traits/Product/SelectAttributeScopes.php +++ b/src/Models/Traits/Product/SelectAttributeScopes.php @@ -19,7 +19,7 @@ public function scopeSelectForProductPage(Builder $query): Builder { $attributeModel = config('rapidez.models.attribute'); $this->attributesToSelect = Arr::pluck($attributeModel::getCachedWhere(function ($attribute) { - return $attribute['productpage'] || in_array($attribute['code'], [ + return ($attribute['flat'] || $attribute['type'] === 'select') && $attribute['productpage'] || in_array($attribute['code'], [ 'name', 'meta_title', 'meta_description',