Skip to content
Draft
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"matchish/laravel-scout-elasticsearch": "^7.11",
"rapidez/blade-components": "^1.10",
"rapidez/blade-directives": "^1.1",
"rapidez/laravel-multi-cache": "^2.0",
"rapidez/laravel-multi-cache": "^2.1",
"tormjens/eventy": "^0.8"
},
"require-dev": {
Expand Down
3 changes: 2 additions & 1 deletion src/Commands/IndexCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Rapidez\Core\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Cache;
use Rapidez\Core\Events\IndexAfterEvent;
use Rapidez\Core\Events\IndexBeforeEvent;
use Rapidez\Core\Facades\Rapidez;
Expand All @@ -27,7 +28,7 @@ public function handle()
? Rapidez::getStores(explode(',', $this->option('store')))
: Rapidez::getStores();

$this->call('cache:clear');
Cache::driver('rapidez:multi')->tags(['attributes', 'swatches'])->flush();

IndexBeforeEvent::dispatch($this);

Expand Down
2 changes: 1 addition & 1 deletion src/Http/Controllers/ProductController.php
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand Down
2 changes: 1 addition & 1 deletion src/Models/Attribute.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ protected function prefix(): CastsAttribute

public static function getCachedWhere(callable $callback): array
{
$attributes = Cache::store('rapidez:multi')->rememberForever('attributes.' . config('rapidez.store'), function () {
$attributes = Cache::store('rapidez:multi')->tags('attributes')->rememberForever('attributes.' . config('rapidez.store'), function () {
return self::all()->toArray();
});

Expand Down
4 changes: 2 additions & 2 deletions src/Models/Config.php
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public static function getValue(
}

if ($options['cache'] ?? true) {
$configCache = Cache::driver('rapidez:multi')->get('magento.config', []);
$configCache = Cache::driver('rapidez:multi')->tags('config')->get('magento.config', []);
$cacheKey = implode(
'.',
[
Expand Down Expand Up @@ -126,7 +126,7 @@ public static function getValue(

if (($options['cache'] ?? true) && isset($cacheKey)) {
Arr::set($configCache, $cacheKey, $resultObject ? $result : false);
Cache::driver('rapidez:multi')->set('magento.config', $configCache);
Cache::driver('rapidez:multi')->tags('config')->set('magento.config', $configCache);
}

return (bool) $options['decrypt'] && is_string($result) ? static::decrypt($result) : $result;
Expand Down
2 changes: 1 addition & 1 deletion src/Models/OptionSwatch.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public static function getCachedSwatchValues(): array
return $attribute['text_swatch'] || $attribute['visual_swatch'];
}), 'id', 'code');

return Cache::rememberForever('swatchvalues', function () use ($swatchAttributes) {
return Cache::store('rapidez:multi')->tags('swatches')->rememberForever('swatchvalues', function () use ($swatchAttributes) {
return self::select('eav_attribute.attribute_code')
->selectRaw('JSON_OBJECTAGG(`eav_attribute_option_value`.`option_id`, JSON_OBJECT(
"label", COALESCE(`eav_attribute_option_value_store`.`value`, `eav_attribute_option_value`.`value`),
Expand Down
12 changes: 7 additions & 5 deletions src/Models/OptionValue.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ 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, []);
$cache = Cache::store('rapidez:multi')->tags('attributes')->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);
Cache::store('rapidez:multi')->forever($cacheKey, $cache);
->value ?? $default);
Cache::store('rapidez:multi')->tags('attributes')->forever($cacheKey, $cache);
}

return $cache[$optionId];
Expand Down
56 changes: 56 additions & 0 deletions src/Models/Product.php
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
35 changes: 35 additions & 0 deletions src/Models/ProductAttribute.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

namespace Rapidez\Core\Models;

use Illuminate\Database\Eloquent\Builder;

class ProductAttribute extends Model
{
protected $table = 'catalog_product_entity_varchar';

protected static function boot(): void
{
parent::boot();

static::addGlobalScope('unions', function (Builder $builder) {
$builder
->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);
}
});
}
}
2 changes: 1 addition & 1 deletion src/Models/Traits/Product/SelectAttributeScopes.php
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down