>|null */ private static ?array $memo = null; private static bool $loaded = false; /** پاک کردن کش last-good و memo درخواست — برای دکمهٔ همگام‌سازی تنظیمات پیشرفته */ public function flushCache(): void { self::$memo = null; self::$loaded = false; try { Cache::forget(self::LAST_GOOD_CACHE_KEY); } catch (\Throwable $e) { // کش در دسترس نیست } } /** * کش را پاک می‌کند و دوباره از سوپرادمین می‌خواند. * * @return array{ok: bool, count: int, items: array, source: string} */ public function refreshFromSuperAdmin(): array { $this->flushCache(); $map = $this->catalogMap(); if ($map === null) { return [ 'ok' => false, 'count' => 0, 'items' => [], 'source' => 'unavailable', ]; } $items = []; foreach ($map as $key => $row) { if (! is_array($row)) { continue; } $value = $row['value'] ?? null; if ($value === null || $value === '') { continue; } $items[(string) $key] = (string) $value; } return [ 'ok' => true, 'count' => count($items), 'items' => $items, 'source' => 'superadmin', ]; } /** * همهٔ کلیدهای سوپرادمین (حتی value خالی). null = سوپرادمین در دسترس نبود. * * @return array>|null */ public function catalogMap(): ?array { return $this->load(); } /** * فقط کلیدهایی که سوپرادمین مقدار غیرخالی دارد — برای ConfigService. * * @return array>|null */ public function map(): ?array { $full = $this->load(); if ($full === null) { return null; } $withValue = []; foreach ($full as $key => $row) { $value = is_array($row) ? ($row['value'] ?? null) : null; if ($value === null || $value === '') { continue; } $withValue[$key] = $row; } return $withValue; } /** * @return array>|null */ private function load(): ?array { if (self::$loaded) { return self::$memo; } self::$loaded = true; $items = app(SuperAdminProgramSettingsClient::class)->fetchItems(); if ($items !== null) { $this->rememberLastGood($items); } else { $items = $this->lastGoodItems(); if ($items !== null) { \Illuminate\Support\Facades\Log::warning('SuperAdmin program-settings using last-good cache', [ 'count' => count($items), ]); } } if ($items === null) { self::$memo = null; return null; } $map = self::ownedItemsMap($items); self::$memo = $map; return $map; } /** * فقط کلیدهای دسترسی سوپرادمین — بقیهٔ پاسخ remote دور ریخته می‌شود. * * @param array> $items * @return array> */ public static function ownedItemsMap(array $items): array { $map = []; foreach ($items as $row) { if (! is_array($row)) { continue; } $key = trim((string) ($row['key'] ?? '')); if ($key === '' || ! self::isSuperAdminOwned($key)) { continue; } $map[$key] = $row; } return $map; } /** @param array> $items */ private function rememberLastGood(array $items): void { $owned = array_values(self::ownedItemsMap($items)); if ($owned === []) { return; } try { Cache::put( self::LAST_GOOD_CACHE_KEY, $owned, now()->addMinutes(self::LAST_GOOD_CACHE_MINUTES) ); } catch (\Throwable $e) { // کش در دسترس نیست — همان رفتار قبلی } } /** * @return array>|null */ private function lastGoodItems(): ?array { try { $cached = Cache::get(self::LAST_GOOD_CACHE_KEY); } catch (\Throwable $e) { return null; } return is_array($cached) && $cached !== [] ? $cached : null; } /** * @return array> */ public function items(): array { $map = $this->map(); if ($map === null || $map === []) { return []; } return array_values($map); } /** * @return array|null */ public function row(string $key): ?array { $map = $this->map(); if ($map === null) { return null; } $key = trim($key); if ($key === '' || ! self::isSuperAdminOwned($key) || ! array_key_exists($key, $map)) { return null; } return $map[$key]; } public static function isRuntime(string $key): bool { return in_array($key, self::RUNTIME_KEYS, true); } /** * کلیدهای صفحهٔ «ساعت کاری» هم مالکشان پنل خانگی است — اگر از overlay خوانده شوند * مقدار ذخیره‌شده در پنل هیچ‌وقت روی قیمت کاربر اعمال نمی‌شود. */ public static function isLocalOwned(string $key): bool { return in_array($key, self::LOCAL_OWNED_KEYS, true) || in_array($key, ConfigService::TRADING_HOURS_CLIENT_KEYS, true); } public static function isSuperAdminOwned(string $key): bool { return in_array(trim($key), self::SUPERADMIN_OWNED_KEYS, true); } }