CluPilotCloud/app/Support/Settings.php

68 lines
2.3 KiB
PHP

<?php
namespace App\Support;
use Illuminate\Support\Facades\Cache;
use Illuminate\Database\QueryException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
/**
* Runtime settings an operator can change from the console.
*
* Cached because the public-site gate reads one of these on every single
* request; the cache is dropped on write, so a flip takes effect immediately
* rather than "within a minute".
*/
final class Settings
{
private const CACHE_PREFIX = 'app_setting:';
public static function get(string $key, mixed $default = null): mixed
{
$cacheKey = self::CACHE_PREFIX.$key;
if (Cache::has($cacheKey)) {
$raw = Cache::get($cacheKey);
} else {
try {
$row = DB::table('app_settings')->where('key', $key)->value('value');
} catch (QueryException $e) {
// The gate reads a setting on every request, so an unreachable
// or not-yet-migrated table would take the whole site down —
// including during a deploy where new code runs before migrate.
// Fall back to the caller's default, but do NOT cache that:
// caching a failure would keep a hidden site publicly visible
// long after the database came back.
Log::warning('app_settings unavailable, using default', [
'key' => $key, 'error' => $e->getMessage(),
]);
return $default;
}
// Sentinel: distinguishes "stored null" from "never stored", so a
// missing row does not get re-queried on every request.
$raw = $row ?? '__missing__';
Cache::forever($cacheKey, $raw);
}
return $raw === '__missing__' ? $default : json_decode($raw, true);
}
public static function set(string $key, mixed $value): void
{
DB::table('app_settings')->updateOrInsert(
['key' => $key],
['value' => json_encode($value), 'updated_at' => now(), 'created_at' => now()],
);
Cache::forget(self::CACHE_PREFIX.$key);
}
public static function bool(string $key, bool $default = false): bool
{
return (bool) self::get($key, $default);
}
}