From a3c4cb1aeab6adcd8fef86d0aaa72b10c9c102b9 Mon Sep 17 00:00:00 2001 From: xboard Date: Fri, 4 Jul 2025 22:16:19 +0800 Subject: [PATCH] fix(setting): Resolve admin_setting helper incompatibility with Octane Updated the `admin_setting` and `admin_settings_batch` helpers to retrieve the `Setting` instance from the service container. This fixes a fatal error and ensures correct behavior in a Laravel Octane environment by preventing the use of stale, shared static instances. --- app/Helpers/Functions.php | 4 +- app/Providers/SettingServiceProvider.php | 3 +- app/Support/Setting.php | 191 ++++++++--------------- 3 files changed, 70 insertions(+), 128 deletions(-) diff --git a/app/Helpers/Functions.php b/app/Helpers/Functions.php index 58c7123..bc3af0b 100644 --- a/app/Helpers/Functions.php +++ b/app/Helpers/Functions.php @@ -12,7 +12,7 @@ if (! function_exists('admin_setting')) { */ function admin_setting($key = null, $default = null) { - $setting = Setting::getInstance(); + $setting = app(Setting::class); if ($key === null) { return $setting->toArray(); @@ -37,6 +37,6 @@ if (! function_exists('admin_settings_batch')) { */ function admin_settings_batch(array $keys): array { - return Setting::getInstance()->getBatch($keys); + return app(Setting::class)->getBatch($keys); } } diff --git a/app/Providers/SettingServiceProvider.php b/app/Providers/SettingServiceProvider.php index 921f02d..fbf59a2 100644 --- a/app/Providers/SettingServiceProvider.php +++ b/app/Providers/SettingServiceProvider.php @@ -5,6 +5,7 @@ namespace App\Providers; use App\Support\Setting; use Illuminate\Support\ServiceProvider; use Illuminate\Contracts\Foundation\Application; +use Illuminate\Support\Facades\Log; class SettingServiceProvider extends ServiceProvider { @@ -16,7 +17,7 @@ class SettingServiceProvider extends ServiceProvider public function register() { $this->app->scoped(Setting::class, function (Application $app) { - return Setting::getInstance(); + return new Setting(); }); } diff --git a/app/Support/Setting.php b/app/Support/Setting.php index 7d80615..858182a 100644 --- a/app/Support/Setting.php +++ b/app/Support/Setting.php @@ -5,130 +5,110 @@ namespace App\Support; use App\Models\Setting as SettingModel; use Illuminate\Support\Arr; use Illuminate\Support\Facades\Cache; +use Illuminate\Contracts\Cache\Repository; class Setting { const CACHE_KEY = 'admin_settings'; - private $cache; - private static $instance = null; - private static $inMemoryCache = null; - private static $cacheLoaded = false; + private Repository $cache; + private ?array $loadedSettings = null; // 请求内缓存 - private function __construct() + public function __construct() { $this->cache = Cache::store('redis'); } - /** - * 获取单例实例 - */ - public static function getInstance(): self - { - if (self::$instance === null) { - self::$instance = new self(); - } - return self::$instance; - } - /** * 获取配置. - * - * @param string $key - * @param mixed $default - * @return mixed */ - public function get($key, $default = null) + public function get(string $key, mixed $default = null): mixed { - $key = strtolower($key); - return Arr::get($this->getInMemoryCache(), $key, $default); - } - - /** - * 获取内存缓存数据 - */ - private function getInMemoryCache(): array - { - if (!self::$cacheLoaded) { - self::$inMemoryCache = $this->fromDatabase(); - self::$cacheLoaded = true; - } - return self::$inMemoryCache ?? []; - } - - /** - * 清除内存缓存 - */ - public static function clearInMemoryCache(): void - { - self::$inMemoryCache = null; - self::$cacheLoaded = false; + $this->load(); + return Arr::get($this->loadedSettings, strtolower($key), $default); } /** * 设置配置信息. - * - * @param string $key - * @param mixed $value - * @return bool 设置是否成功 */ public function set(string $key, mixed $value = null): bool { - $key = strtolower($key); - SettingModel::createOrUpdate($key, $value); - $this->cache->forget(self::CACHE_KEY); - - // 清除内存缓存,下次访问时重新加载 - self::clearInMemoryCache(); - + SettingModel::createOrUpdate(strtolower($key), $value); + $this->flush(); return true; } /** * 保存配置到数据库. - * - * @param array $settings 要保存的设置数组 - * @return bool 保存是否成功 */ public function save(array $settings): bool { foreach ($settings as $key => $value) { - $key = strtolower($key); - SettingModel::createOrUpdate($key, $value); + SettingModel::createOrUpdate(strtolower($key), $value); } - - // 批量更新后清除缓存 - $this->cache->forget(self::CACHE_KEY); - self::clearInMemoryCache(); - + $this->flush(); return true; } /** * 删除配置信息 - * - * @param string $key - * @return bool */ - public function remove($key): bool + public function remove(string $key): bool { SettingModel::where('name', $key)->delete(); - $this->cache->forget(self::CACHE_KEY); - self::clearInMemoryCache(); + $this->flush(); return true; } /** - * 获取配置信息. - * @return array + * 更新单个设置项 */ - public function fromDatabase(): array + public function update(string $key, $value): bool { + return $this->set($key, $value); + } + + /** + * 批量获取配置项 + */ + public function getBatch(array $keys): array + { + $this->load(); + $result = []; + + foreach ($keys as $index => $item) { + $isNumericIndex = is_numeric($index); + $key = strtolower($isNumericIndex ? $item : $index); + $default = $isNumericIndex ? config('v2board.' . $item) : (config('v2board.' . $key) ?? $item); + + $result[$item] = Arr::get($this->loadedSettings, $key, $default); + } + + return $result; + } + + /** + * 将所有设置转换为数组 + */ + public function toArray(): array + { + $this->load(); + return $this->loadedSettings; + } + + /** + * 加载配置到请求内缓存 + */ + private function load(): void + { + if ($this->loadedSettings !== null) { + return; + } + try { - // 统一从 value 字段获取所有配置 $settings = $this->cache->rememberForever(self::CACHE_KEY, function (): array { return array_change_key_case( - SettingModel::pluck('value', 'name')->toArray(), + SettingModel::pluck('value', 'name')->toArray(), CASE_LOWER ); }); @@ -137,65 +117,26 @@ class Setting foreach ($settings as $key => $value) { if (is_string($value)) { $decoded = json_decode($value, true); - if (json_last_error() === JSON_ERROR_NONE && $decoded !== null) { + if (json_last_error() === JSON_ERROR_NONE) { $settings[$key] = $decoded; } } } - return $settings; - } catch (\Throwable $th) { - return []; + $this->loadedSettings = $settings; + } catch (\Throwable) { + $this->loadedSettings = []; } } /** - * 将所有设置转换为数组 - * - * @return array + * 清空缓存 */ - public function toArray(): array + private function flush(): void { - return $this->getInMemoryCache(); - } - - /** - * 更新单个设置项 - * - * @param string $key 设置键名 - * @param mixed $value 设置值 - * @return bool 更新是否成功 - */ - public function update(string $key, $value): bool - { - return $this->set($key, $value); - } - - /** - * 批量获取配置项,优化多个配置项获取的性能 - * - * @param array $keys 配置键名数组,格式:['key1', 'key2' => 'default_value', ...] - * @return array 返回键值对数组 - */ - public function getBatch(array $keys): array - { - $cache = $this->getInMemoryCache(); - $result = []; - - foreach ($keys as $index => $item) { - if (is_numeric(value: $index)) { - // 格式:['key1', 'key2'] - $key = strtolower($item); - $default = config('v2board.'. $item); - $result[$item] = Arr::get($cache, $key, $default); - } else { - // 格式:['key1' => 'default_value'] - $key = strtolower($index); - $default = config('v2board.'. $index) ?? $item; - $result[$index] = Arr::get($cache, $key, $default); - } - } - - return $result; + // 清除共享的Redis缓存 + $this->cache->forget(self::CACHE_KEY); + // 清除当前请求的实例内存缓存 + $this->loadedSettings = null; } }