Fix: Updating Product Options Registry and adding handle to the meilisearch index

This commit is contained in:
2026-08-27 11:14:56 +03:00
parent cb3fe095d9
commit e95ea4a43c
8 changed files with 80 additions and 55 deletions
@@ -18,7 +18,7 @@ class ProductOptionResourceExtension extends ResourceExtension
{
public function extendForm(Form $form): Form
{
$options = app(ProductOptionTypeManager::class)->all()
$options = collect(ProductOptionTypeManager::get()->all())
->keys()
->mapWithKeys(fn (string $key) => [$key => Str::headline($key)])
->all();
@@ -20,7 +20,7 @@ class ValuesRelationManagerExtension extends RelationManagerExtension
/** @var ProductOption $option */
$option = $this->caller->getOwnerRecord();
$type = app(ProductOptionTypeManager::class)->resolve($option->meta['option_type'] ?? null);
$type = ProductOptionTypeManager::get()->resolve($option->meta['option_type'] ?? null);
if ($type === null) {
return $form;
+4 -3
View File
@@ -6,9 +6,10 @@ use Filament\Forms\Components\ColorPicker;
use Modules\Core\Product\Contracts\ProductOptionTypeInterface;
/**
* Reference implementation: describes a 'color' ProductOption's values as
* carrying a hex code in `meta.hex`, editable via a Filament color picker.
* Not auto-registered — a shop opts in via config('core.product_option_types').
* Describes a 'color' ProductOption's values as carrying a hex code in
* `meta.hex`, editable via a Filament color picker. Registered automatically by
* `Modules\Core\Providers\ProductServiceProvider` — a shop's admin still has to
* pick "Color" from the Option Type dropdown per-ProductOption for it to apply.
*/
class ColorOptionType implements ProductOptionTypeInterface
{
+1
View File
@@ -112,6 +112,7 @@ class ProductIndexer extends BaseProductIndexer
'purchasable' => $variant->purchasable,
'options' => $variant->values->map(fn ($value) => [
'option' => $this->translatedName($value->option->name),
'handle' => $value->option->handle,
'value' => $this->translatedName($value->name),
'meta' => $value->meta,
])->all(),
@@ -2,7 +2,6 @@
namespace Modules\Core\Product\Services;
use Illuminate\Support\Collection;
use Modules\Core\Product\Contracts\ProductOptionTypeInterface;
/**
@@ -12,29 +11,58 @@ use Modules\Core\Product\Contracts\ProductOptionTypeInterface;
* tied to the option's `handle`, since a shop's own handle naming (e.g. transliterated
* Greek, legacy imports) shouldn't have to match a type's key.
*
* The available keys come from `config('core.product_option_types')` — a plain list,
* not a config array, because the mapping from option to type is an admin's per-option
* choice made in the UI (see ValuesRelationManagerExtension/ProductOptionResourceExtension),
* not something config alone can express.
* A singleton registry, same shape as `Modules\Core\Notification\NotificationRegistry`
* — a consuming app calls `ProductOptionTypeManager::get()->register([...])` from its
* own service provider `boot()`, rather than listing classes in a published config
* file.
*/
class ProductOptionTypeManager
{
/**
* @return Collection<string, ProductOptionTypeInterface> keyed by getKey()
*/
public function all(): Collection
private static ?self $instance = null;
/** @var array<string, class-string<ProductOptionTypeInterface>> */
private array $types = [];
private function __construct() {}
public static function get(): static
{
return collect(config('core.product_option_types', []))
->map(fn (string $class) => app($class))
->keyBy(fn (ProductOptionTypeInterface $type) => $type::getKey());
if (static::$instance === null) {
static::$instance = new static();
}
return static::$instance;
}
/**
* @param array<class-string<ProductOptionTypeInterface>> $types
*/
public function register(array $types): void
{
foreach ($types as $class) {
$this->types[$class::getKey()] = $class;
}
}
public function unregister(string $key): void
{
unset($this->types[$key]);
}
public function resolve(?string $key): ?ProductOptionTypeInterface
{
if ($key === null) {
if ($key === null || ! isset($this->types[$key])) {
return null;
}
return $this->all()->get($key);
return app($this->types[$key]);
}
/**
* @return array<string, class-string<ProductOptionTypeInterface>>
*/
public function all(): array
{
return $this->types;
}
}
+6
View File
@@ -6,11 +6,17 @@ use Illuminate\Support\ServiceProvider;
use Lunar\Models\ProductOption;
use Lunar\Models\ProductOptionValue;
use Modules\Core\Product\Observers\ProductOptionReindexObserver;
use Modules\Core\Product\OptionTypes\ColorOptionType;
use Modules\Core\Product\Services\ProductOptionTypeManager;
class ProductServiceProvider extends ServiceProvider
{
public function boot(): void
{
ProductOptionTypeManager::get()->register([
ColorOptionType::class,
]);
$observer = new ProductOptionReindexObserver;
ProductOption::saved(fn (ProductOption $option) => $observer->optionSaved($option));