feat(database): 添加用户角色权限系统及相关监控功能

- 创建用户表(users)包含基本信息和认证字段
- 创建角色表(roles)用于权限控制
- 创建权限表(permissions)定义系统权限
- 创建用户角色关联表(user_roles)建立用户与角色关系
- 创建角色权限关联表(role_permissions)建立角色与权限关系
- 创建迁移记录表(migrations)追踪数据库变更
- 添加AdminController提供管理员面板功能
- 实现系统监控、配置管理、缓存清理等功能
- 添加AOP切面编程支持的各种通知类型
- 实现告警管理AlertManager支持多渠道告警
- 添加文档注解接口规范
This commit is contained in:
Lawson
2026-04-08 17:00:28 +08:00
commit 2782d765fb
270 changed files with 107192 additions and 0 deletions

View File

@@ -0,0 +1,231 @@
<?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 = [];
}
}