160 lines
4.7 KiB
PHP
160 lines
4.7 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
namespace app\common\library;
|
||
|
||
use app\common\model\MallBusinessConfig;
|
||
use support\Redis as RedisSupport;
|
||
use Throwable;
|
||
|
||
/**
|
||
* PlayX 与积分商城相关的比例配置:优先读 Redis,未命中则读 mall_business_config 并回写 Redis;无表记录时回退 .env 并写入 Redis。
|
||
*/
|
||
final class MallPlayxRatios
|
||
{
|
||
public const REDIS_KEY = 'mall:business_config:playx_ratios';
|
||
|
||
/**
|
||
* @return array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float}
|
||
*/
|
||
public static function get(): array
|
||
{
|
||
$conn = self::redisConnection();
|
||
if ($conn !== null) {
|
||
$cached = self::readFromRedis($conn);
|
||
if ($cached !== null) {
|
||
return $cached;
|
||
}
|
||
}
|
||
|
||
return self::loadFromDatabaseAndWriteRedis($conn);
|
||
}
|
||
|
||
/**
|
||
* @param array{return_ratio?: mixed, unlock_ratio?: mixed, points_to_cash_ratio?: mixed} $ratios
|
||
*/
|
||
public static function syncToRedis(array $ratios): void
|
||
{
|
||
$payload = [
|
||
'return_ratio' => self::toFloat($ratios['return_ratio'] ?? 0),
|
||
'unlock_ratio' => self::toFloat($ratios['unlock_ratio'] ?? 0),
|
||
'points_to_cash_ratio' => self::toFloat($ratios['points_to_cash_ratio'] ?? 0),
|
||
];
|
||
self::writeRedis(self::redisConnection(), $payload);
|
||
}
|
||
|
||
public static function syncFromRow(MallBusinessConfig $row): void
|
||
{
|
||
self::syncToRedis([
|
||
'return_ratio' => $row->return_ratio,
|
||
'unlock_ratio' => $row->unlock_ratio,
|
||
'points_to_cash_ratio' => $row->points_to_cash_ratio,
|
||
]);
|
||
}
|
||
|
||
public static function forget(): void
|
||
{
|
||
$conn = self::redisConnection();
|
||
if ($conn === null) {
|
||
return;
|
||
}
|
||
try {
|
||
$conn->del(self::REDIS_KEY);
|
||
} catch (Throwable) {
|
||
}
|
||
}
|
||
|
||
private static function redisConnection(): ?object
|
||
{
|
||
$cfg = config('redis');
|
||
if (!is_array($cfg) || empty($cfg)) {
|
||
return null;
|
||
}
|
||
try {
|
||
return RedisSupport::connection('default');
|
||
} catch (Throwable) {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @return array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float}|null
|
||
*/
|
||
private static function readFromRedis(object $conn): ?array
|
||
{
|
||
try {
|
||
$raw = $conn->get(self::REDIS_KEY);
|
||
} catch (Throwable) {
|
||
return null;
|
||
}
|
||
if (!is_string($raw) || $raw === '') {
|
||
return null;
|
||
}
|
||
$data = json_decode($raw, true);
|
||
if (!is_array($data)) {
|
||
return null;
|
||
}
|
||
if (!isset($data['return_ratio'], $data['unlock_ratio'], $data['points_to_cash_ratio'])) {
|
||
return null;
|
||
}
|
||
|
||
return [
|
||
'return_ratio' => self::toFloat($data['return_ratio']),
|
||
'unlock_ratio' => self::toFloat($data['unlock_ratio']),
|
||
'points_to_cash_ratio' => self::toFloat($data['points_to_cash_ratio']),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* @return array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float}
|
||
*/
|
||
private static function loadFromDatabaseAndWriteRedis(?object $conn): array
|
||
{
|
||
$row = MallBusinessConfig::order('id', 'asc')->find();
|
||
if ($row) {
|
||
$out = [
|
||
'return_ratio' => self::toFloat($row->return_ratio),
|
||
'unlock_ratio' => self::toFloat($row->unlock_ratio),
|
||
'points_to_cash_ratio' => self::toFloat($row->points_to_cash_ratio),
|
||
];
|
||
self::writeRedis($conn, $out);
|
||
|
||
return $out;
|
||
}
|
||
|
||
$out = [
|
||
'return_ratio' => floatval(env('PLAYX_RETURN_RATIO', '0.1')),
|
||
'unlock_ratio' => floatval(env('PLAYX_UNLOCK_RATIO', '0.1')),
|
||
'points_to_cash_ratio' => floatval(env('PLAYX_POINTS_TO_CASH_RATIO', '0.1')),
|
||
];
|
||
self::writeRedis($conn, $out);
|
||
|
||
return $out;
|
||
}
|
||
|
||
/**
|
||
* @param array{return_ratio: float, unlock_ratio: float, points_to_cash_ratio: float} $payload
|
||
*/
|
||
private static function writeRedis(?object $conn, array $payload): void
|
||
{
|
||
if ($conn === null) {
|
||
return;
|
||
}
|
||
try {
|
||
$json = json_encode($payload, JSON_THROW_ON_ERROR);
|
||
$conn->set(self::REDIS_KEY, $json);
|
||
} catch (Throwable) {
|
||
}
|
||
}
|
||
|
||
private static function toFloat(mixed $v): float
|
||
{
|
||
if (is_numeric($v)) {
|
||
return floatval($v);
|
||
}
|
||
|
||
return 0.0;
|
||
}
|
||
}
|