mirror of
https://devops.lemonos.cn/lawson/FendxPHP.git
synced 2026-06-15 15:02:49 +08:00
- 创建用户表(users)包含基本信息和认证字段 - 创建角色表(roles)用于权限控制 - 创建权限表(permissions)定义系统权限 - 创建用户角色关联表(user_roles)建立用户与角色关系 - 创建角色权限关联表(role_permissions)建立角色与权限关系 - 创建迁移记录表(migrations)追踪数据库变更 - 添加AdminController提供管理员面板功能 - 实现系统监控、配置管理、缓存清理等功能 - 添加AOP切面编程支持的各种通知类型 - 实现告警管理AlertManager支持多渠道告警 - 添加文档注解接口规范
232 lines
6.4 KiB
PHP
232 lines
6.4 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Fendx\Cache;
|
|
|
|
use Redis;
|
|
use RedisException;
|
|
use Fendx\Core\Config\Config;
|
|
use Fendx\Common\Exception\BusinessException;
|
|
|
|
final class Cache
|
|
{
|
|
private static ?Redis $redis = null;
|
|
private static array $config = [];
|
|
private static array $localCache = [];
|
|
private static bool $localCacheEnabled = false;
|
|
|
|
public static function configure(array $config): void
|
|
{
|
|
self::$config = $config;
|
|
self::$localCacheEnabled = $config['local_cache'] ?? false;
|
|
}
|
|
|
|
private static function getRedis(): Redis
|
|
{
|
|
if (self::$redis === null) {
|
|
self::$redis = self::createRedisConnection();
|
|
}
|
|
return self::$redis;
|
|
}
|
|
|
|
private static function createRedisConnection(): Redis
|
|
{
|
|
$redis = new Redis();
|
|
|
|
$host = self::$config['host'] ?? '127.0.0.1';
|
|
$port = self::$config['port'] ?? 6379;
|
|
$password = self::$config['password'] ?? null;
|
|
$database = self::$config['database'] ?? 0;
|
|
$timeout = self::$config['timeout'] ?? 3.0;
|
|
|
|
try {
|
|
$redis->connect($host, $port, $timeout);
|
|
|
|
if ($password) {
|
|
$redis->auth($password);
|
|
}
|
|
|
|
$redis->select($database);
|
|
|
|
return $redis;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'REDIS_CONNECT_FAILED', [
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function get(string $key, mixed $default = null): mixed
|
|
{
|
|
// 先检查本地缓存
|
|
if (self::$localCacheEnabled && isset(self::$localCache[$key])) {
|
|
$item = self::$localCache[$key];
|
|
if ($item['expires'] > time()) {
|
|
return $item['value'];
|
|
}
|
|
unset(self::$localCache[$key]);
|
|
}
|
|
|
|
try {
|
|
$value = self::getRedis()->get($key);
|
|
|
|
if ($value === false) {
|
|
return $default;
|
|
}
|
|
|
|
$decoded = json_decode($value, true);
|
|
$result = is_array($decoded) ? $decoded : $value;
|
|
|
|
// 更新本地缓存
|
|
if (self::$localCacheEnabled) {
|
|
$ttl = self::getRedis()->ttl($key);
|
|
if ($ttl > 0) {
|
|
self::$localCache[$key] = [
|
|
'value' => $result,
|
|
'expires' => time() + $ttl
|
|
];
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_GET_FAILED', [
|
|
'key' => $key,
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function set(string $key, mixed $value, int $ttl = 3600): bool
|
|
{
|
|
try {
|
|
$serialized = is_scalar($value) ? $value : json_encode($value);
|
|
|
|
$result = self::getRedis()->setex($key, $ttl, $serialized);
|
|
|
|
// 更新本地缓存
|
|
if (self::$localCacheEnabled && $result) {
|
|
self::$localCache[$key] = [
|
|
'value' => $value,
|
|
'expires' => time() + $ttl
|
|
];
|
|
}
|
|
|
|
return $result;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_SET_FAILED', [
|
|
'key' => $key,
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function delete(string $key): bool
|
|
{
|
|
try {
|
|
$result = self::getRedis()->del($key);
|
|
|
|
// 清除本地缓存
|
|
if (self::$localCacheEnabled) {
|
|
unset(self::$localCache[$key]);
|
|
}
|
|
|
|
return $result > 0;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_DELETE_FAILED', [
|
|
'key' => $key,
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function has(string $key): bool
|
|
{
|
|
try {
|
|
return self::getRedis()->exists($key) > 0;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_HAS_FAILED', [
|
|
'key' => $key,
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function clear(): bool
|
|
{
|
|
try {
|
|
$result = self::getRedis()->flushDB();
|
|
|
|
// 清除本地缓存
|
|
if (self::$localCacheEnabled) {
|
|
self::$localCache = [];
|
|
}
|
|
|
|
return $result;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_CLEAR_FAILED', [
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function increment(string $key, int $value = 1): int
|
|
{
|
|
try {
|
|
$result = self::getRedis()->incrBy($key, $value);
|
|
|
|
// 清除本地缓存
|
|
if (self::$localCacheEnabled) {
|
|
unset(self::$localCache[$key]);
|
|
}
|
|
|
|
return $result;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_INCREMENT_FAILED', [
|
|
'key' => $key,
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function decrement(string $key, int $value = 1): int
|
|
{
|
|
try {
|
|
$result = self::getRedis()->decrBy($key, $value);
|
|
|
|
// 清除本地缓存
|
|
if (self::$localCacheEnabled) {
|
|
unset(self::$localCache[$key]);
|
|
}
|
|
|
|
return $result;
|
|
} catch (RedisException $e) {
|
|
throw new BusinessException(500, 'CACHE_DECREMENT_FAILED', [
|
|
'key' => $key,
|
|
'message' => $e->getMessage()
|
|
]);
|
|
}
|
|
}
|
|
|
|
public static function remember(string $key, callable $callback, int $ttl = 3600): mixed
|
|
{
|
|
$value = self::get($key);
|
|
|
|
if ($value === null) {
|
|
$value = $callback();
|
|
self::set($key, $value, $ttl);
|
|
}
|
|
|
|
return $value;
|
|
}
|
|
|
|
public static function close(): void
|
|
{
|
|
if (self::$redis !== null) {
|
|
self::$redis->close();
|
|
self::$redis = null;
|
|
}
|
|
self::$localCache = [];
|
|
}
|
|
}
|