78 lines
2.9 KiB
PHP
78 lines
2.9 KiB
PHP
<?php
|
|
|
|
namespace Modules\Core\Store\Services;
|
|
|
|
use Illuminate\Support\Facades\Cache;
|
|
use Illuminate\Support\Facades\Event;
|
|
use Lunar\Models\Language;
|
|
use Modules\Core\Store\Events\StoreDetailsUpdated;
|
|
use Modules\Core\Store\Models\StoreDetails;
|
|
|
|
/**
|
|
* The only entrypoint that creates/updates the StoreDetails singleton — same
|
|
* shape as Modules\Core\Localization\Services\TranslationService: every
|
|
* write goes through here so it can dispatch StoreDetailsUpdated, which
|
|
* Modules\Core\Store\Listeners\FlushStoreDetailsCache reacts to. Never call
|
|
* StoreDetails::query()->update(...) or $storeDetails->save() directly — a
|
|
* write bypassing this service leaves current()'s forever-cache stale.
|
|
*/
|
|
class StoreDetailsService
|
|
{
|
|
public const CACHE_KEY = 'store-details';
|
|
|
|
/**
|
|
* Forever-cached — read on every storefront request that shows store
|
|
* details (e.g. the checkout confirmation page's bank transfer
|
|
* instructions), so this should never re-query the database on a normal
|
|
* request. Only ever invalidated by update() below, via
|
|
* FlushStoreDetailsCache reacting to StoreDetailsUpdated.
|
|
*/
|
|
public function current(): StoreDetails
|
|
{
|
|
return Cache::rememberForever(
|
|
self::CACHE_KEY,
|
|
fn () => $this->firstOrCreate(),
|
|
);
|
|
}
|
|
|
|
public function update(array $attributes): StoreDetails
|
|
{
|
|
$storeDetails = $this->firstOrCreate();
|
|
|
|
$storeDetails->update($attributes);
|
|
|
|
Event::dispatch(new StoreDetailsUpdated($storeDetails));
|
|
|
|
return $storeDetails;
|
|
}
|
|
|
|
/**
|
|
* A freshly-created row must never leave a translatable column
|
|
* genuinely NULL — Lunar's own TranslatedText component (Modules\Core\
|
|
* Store\Filament\Pages\ManageStoreDetails's `name`/`address`/
|
|
* `bank_transfer_instructions` fields) silently drops every keystroke
|
|
* on re-render when the field it's editing starts out NULL rather than
|
|
* an empty per-locale array. Real-world precedent (PaymentMethod's own
|
|
* translatable `name` column) never hits this, because every
|
|
* PaymentMethod row is created THROUGH the same Filament form that
|
|
* immediately fills `name` — this singleton is instead created blank
|
|
* and opened for editing in the same visit, which is exactly the gap
|
|
* that surfaces the bug. Caught and fixed after the fact, verified via
|
|
* tinker: seeding a real (non-null) array made typing into the field
|
|
* persist correctly, confirming NULL was the trigger.
|
|
*/
|
|
private function firstOrCreate(): StoreDetails
|
|
{
|
|
return StoreDetails::query()->firstOrCreate([], [
|
|
'name' => $this->emptyPerLocale(),
|
|
'address' => $this->emptyPerLocale(),
|
|
'bank_transfer_instructions' => $this->emptyPerLocale(),
|
|
]);
|
|
}
|
|
|
|
private function emptyPerLocale(): array
|
|
{
|
|
return Language::query()->pluck('code')->mapWithKeys(fn (string $code) => [$code => ''])->all();
|
|
}
|
|
}
|