112 lines
2.9 KiB
PHP
112 lines
2.9 KiB
PHP
<?php
|
||
|
||
namespace App\Models;
|
||
|
||
use Illuminate\Database\Eloquent\Model;
|
||
use Illuminate\Support\Facades\Redis;
|
||
|
||
class Setting extends Model
|
||
{
|
||
protected $fillable = ['group', 'key', 'value'];
|
||
protected $keyType = 'int';
|
||
public $incrementing = true;
|
||
|
||
/**
|
||
* Get a setting: Redis → DB fallback → Redis rebuild
|
||
*/
|
||
public static function get(string $name, $default = null)
|
||
{
|
||
[$group, $key] = self::split($name);
|
||
$redisKey = self::redisKey($group, $key);
|
||
|
||
// 1️⃣ Try Redis
|
||
try {
|
||
$cached = Redis::get($redisKey);
|
||
if ($cached !== null) {
|
||
$decoded = json_decode($cached, true);
|
||
return json_last_error() === JSON_ERROR_NONE ? $decoded : $cached;
|
||
}
|
||
} catch (\Throwable) {
|
||
// Redis down, fallback to DB
|
||
}
|
||
|
||
// 2️⃣ Try DB
|
||
$row = static::query()->where(compact('group', 'key'))->first();
|
||
if (!$row) return $default;
|
||
|
||
$decoded = json_decode($row->value, true);
|
||
$value = json_last_error() === JSON_ERROR_NONE ? $decoded : $row->value;
|
||
|
||
// 3️⃣ Writeback to Redis
|
||
try {
|
||
Redis::setex($redisKey, 3600, is_scalar($value) ? (string)$value : json_encode($value));
|
||
} catch (\Throwable) {}
|
||
|
||
return $value;
|
||
}
|
||
|
||
/**
|
||
* Set or update a setting: DB → Redis
|
||
*/
|
||
public static function set(string $name, $value): void
|
||
{
|
||
[$group, $key] = self::split($name);
|
||
$redisKey = self::redisKey($group, $key);
|
||
|
||
$val = is_scalar($value)
|
||
? (string)$value
|
||
: json_encode($value, JSON_UNESCAPED_SLASHES);
|
||
|
||
static::query()->updateOrCreate(compact('group', 'key'), ['value' => $val]);
|
||
|
||
try {
|
||
Redis::set($redisKey, $val);
|
||
} catch (\Throwable) {}
|
||
}
|
||
|
||
/**
|
||
* Forget a cached setting (Redis only)
|
||
*/
|
||
public static function forget(string $name): void
|
||
{
|
||
[$group, $key] = self::split($name);
|
||
try {
|
||
Redis::del(self::redisKey($group, $key));
|
||
} catch (\Throwable) {}
|
||
}
|
||
|
||
/**
|
||
* Build Redis key
|
||
*/
|
||
protected static function redisKey(string $group, string $key): string
|
||
{
|
||
return "settings:{$group}:{$key}";
|
||
}
|
||
|
||
/**
|
||
* Split "group.key" format
|
||
*/
|
||
protected static function split(string $name): array
|
||
{
|
||
if (str_contains($name, '.')) {
|
||
[$group, $key] = explode('.', $name, 2);
|
||
} else {
|
||
$group = 'system';
|
||
$key = $name;
|
||
}
|
||
return [$group, $key];
|
||
}
|
||
|
||
public static function setMany(array $pairs): void
|
||
{
|
||
foreach ($pairs as $name => $value) {
|
||
self::set($name, $value);
|
||
}
|
||
}
|
||
|
||
public static function signupAllowed(): bool
|
||
{
|
||
return (int) self::get('system.signup_enabled', 1) === 1;
|
||
}
|
||
}
|