mirror of
https://devops.lemonos.cn/lawson/FendxPHP.git
synced 2026-06-15 23:12:49 +08:00
feat(database): 添加用户角色权限系统及相关监控功能
- 创建用户表(users)包含基本信息和认证字段 - 创建角色表(roles)用于权限控制 - 创建权限表(permissions)定义系统权限 - 创建用户角色关联表(user_roles)建立用户与角色关系 - 创建角色权限关联表(role_permissions)建立角色与权限关系 - 创建迁移记录表(migrations)追踪数据库变更 - 添加AdminController提供管理员面板功能 - 实现系统监控、配置管理、缓存清理等功能 - 添加AOP切面编程支持的各种通知类型 - 实现告警管理AlertManager支持多渠道告警 - 添加文档注解接口规范
This commit is contained in:
437
bin/console
Normal file
437
bin/console
Normal file
@@ -0,0 +1,437 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
require_once __DIR__ . '/../vendor/autoload.php';
|
||||
|
||||
use Fendx\Cli\Application;
|
||||
use Fendx\Cli\Command\VersionCommand;
|
||||
use Fendx\Cli\Command\HelpCommand;
|
||||
use Fendx\Cli\Command\ServerCommand;
|
||||
use Fendx\Cli\Command\MigrateCommand;
|
||||
use Fendx\Cli\Command\GenerateCommand;
|
||||
|
||||
/**
|
||||
* FendxPHP 控制台应用
|
||||
*/
|
||||
class ConsoleApplication extends Application
|
||||
{
|
||||
protected function getDefaultCommands(): array
|
||||
{
|
||||
return [
|
||||
new VersionCommand(),
|
||||
new HelpCommand(),
|
||||
new ServerCommand(),
|
||||
new MigrateCommand(),
|
||||
new GenerateCommand(),
|
||||
new TestCommand(),
|
||||
new DeployCommand(),
|
||||
new BenchmarkCommand(),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 测试命令
|
||||
*/
|
||||
class TestCommand extends \Fendx\Cli\Command\Command
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName('test')
|
||||
->setDescription('运行测试套件')
|
||||
->addArgument('type', '测试类型: unit, integration, api, e2e, performance, security')
|
||||
->addOption('filter', 'f', '过滤测试用例')
|
||||
->addOption('coverage', 'c', '生成覆盖率报告')
|
||||
->addOption('parallel', 'p', '并行测试', false, 4);
|
||||
}
|
||||
|
||||
protected function execute(\Fendx\Cli\Input\InputInterface $input, \Fendx\Cli\Output\OutputInterface $output): int
|
||||
{
|
||||
$type = $input->getArgument('type') ?? 'all';
|
||||
$filter = $input->getOption('filter');
|
||||
$coverage = $input->getOption('coverage');
|
||||
$parallel = $input->getOption('parallel');
|
||||
|
||||
$output->writeln("<info>运行 {$type} 测试...</info>");
|
||||
|
||||
return match ($type) {
|
||||
'unit' => $this->runUnitTests($output, $filter, $coverage),
|
||||
'integration' => $this->runIntegrationTests($output, $filter),
|
||||
'api' => $this->runApiTests($output, $filter),
|
||||
'e2e' => $this->runE2ETests($output, $filter),
|
||||
'performance' => $this->runPerformanceTests($output),
|
||||
'security' => $this->runSecurityTests($output),
|
||||
'all' => $this->runAllTests($output, $filter, $coverage, $parallel),
|
||||
default => $this->showError($output, "未知的测试类型: {$type}")
|
||||
};
|
||||
}
|
||||
|
||||
private function runUnitTests($output, $filter, $coverage): int
|
||||
{
|
||||
$output->writeln("<info>运行单元测试...</info>");
|
||||
|
||||
$command = "vendor/bin/phpunit tests/Unit --colors=always";
|
||||
|
||||
if ($filter) {
|
||||
$command .= " --filter {$filter}";
|
||||
}
|
||||
|
||||
if ($coverage) {
|
||||
$command .= " --coverage-html reports/coverage --coverage-clover reports/coverage.xml";
|
||||
}
|
||||
|
||||
$this->executeCommand($output, $command);
|
||||
|
||||
if ($coverage) {
|
||||
$output->writeln("<info>覆盖率报告已生成: reports/coverage/index.html</info>");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function runIntegrationTests($output, $filter): int
|
||||
{
|
||||
$output->writeln("<info>运行集成测试...</info>");
|
||||
|
||||
// 启动测试环境
|
||||
$this->executeCommand($output, "docker-compose -f docker-compose.test.yml up -d");
|
||||
sleep(10); // 等待服务启动
|
||||
|
||||
$command = "vendor/bin/phpunit tests/Integration --colors=always";
|
||||
|
||||
if ($filter) {
|
||||
$command .= " --filter {$filter}";
|
||||
}
|
||||
|
||||
$result = $this->executeCommand($output, $command);
|
||||
|
||||
// 清理测试环境
|
||||
$this->executeCommand($output, "docker-compose -f docker-compose.test.yml down");
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function runApiTests($output, $filter): int
|
||||
{
|
||||
$output->writeln("<info>运行 API 测试...</info>");
|
||||
|
||||
$command = "vendor/bin/codecept run api --colors";
|
||||
|
||||
if ($filter) {
|
||||
$command .= " -g {$filter}";
|
||||
}
|
||||
|
||||
return $this->executeCommand($output, $command);
|
||||
}
|
||||
|
||||
private function runE2ETests($output, $filter): int
|
||||
{
|
||||
$output->writeln("<info>运行端到端测试...</info>");
|
||||
|
||||
// 启动完整环境
|
||||
$this->executeCommand($output, "docker-compose up -d");
|
||||
$this->executeCommand($output, "kubectl apply -f k8s/");
|
||||
sleep(30); // 等待所有服务就绪
|
||||
|
||||
$command = "vendor/bin/codecept run e2e --colors";
|
||||
|
||||
if ($filter) {
|
||||
$command .= " -g {$filter}";
|
||||
}
|
||||
|
||||
$result = $this->executeCommand($output, $command);
|
||||
|
||||
// 清理环境
|
||||
$this->executeCommand($output, "kubectl delete -f k8s/");
|
||||
$this->executeCommand($output, "docker-compose down");
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function runPerformanceTests($output): int
|
||||
{
|
||||
$output->writeln("<info>运行性能测试...</info>");
|
||||
|
||||
// 并发测试
|
||||
$this->executeCommand($output, "ab -n 10000 -c 100 http://localhost/api/users");
|
||||
|
||||
// 内存测试
|
||||
$this->executeCommand($output, "php bin/console benchmark:memory");
|
||||
|
||||
// 数据库性能测试
|
||||
$this->executeCommand($output, "php bin/console benchmark:database");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function runSecurityTests($output): int
|
||||
{
|
||||
$output->writeln("<info>运行安全测试...</info>");
|
||||
|
||||
// 依赖漏洞扫描
|
||||
$this->executeCommand($output, "composer audit");
|
||||
|
||||
// 代码安全扫描
|
||||
$this->executeCommand($output, "vendor/bin/phpstan analyse --level=8");
|
||||
|
||||
// API 安全测试
|
||||
$this->executeCommand($output, "vendor/bin/codecept run security");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function runAllTests($output, $filter, $coverage, $parallel): int
|
||||
{
|
||||
$output->writeln("<info>运行所有测试...</info>");
|
||||
|
||||
$tests = [
|
||||
'unit' => $this->runUnitTests($output, $filter, $coverage),
|
||||
'integration' => $this->runIntegrationTests($output, $filter),
|
||||
'api' => $this->runApiTests($output, $filter),
|
||||
];
|
||||
|
||||
$failed = array_filter($tests, fn($result) => $result !== 0);
|
||||
|
||||
if (empty($failed)) {
|
||||
$output->writeln("<info>所有测试通过! ✅</info>");
|
||||
return 0;
|
||||
} else {
|
||||
$output->writeln("<error>部分测试失败! ❌</error>");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
private function executeCommand($output, string $command): int
|
||||
{
|
||||
$output->writeln("<comment>执行: {$command}</comment>");
|
||||
|
||||
$process = proc_open($command, [
|
||||
1 => ['pipe', 'w'],
|
||||
2 => ['pipe', 'w'],
|
||||
], $pipes);
|
||||
|
||||
if (!is_resource($process)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 读取输出
|
||||
while (($line = fgets($pipes[1])) !== false) {
|
||||
$output->write($line);
|
||||
}
|
||||
|
||||
// 读取错误输出
|
||||
while (($line = fgets($pipes[2])) !== false) {
|
||||
$output->write("<error>{$line}</error>");
|
||||
}
|
||||
|
||||
return proc_close($process);
|
||||
}
|
||||
|
||||
private function showError($output, string $message): int
|
||||
{
|
||||
$output->writeln("<error>{$message}</error>");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 部署命令
|
||||
*/
|
||||
class DeployCommand extends \Fendx\Cli\Command\Command
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName('deploy')
|
||||
->setDescription('部署应用到指定环境')
|
||||
->addArgument('environment', '部署环境: local, docker, k8s')
|
||||
->addOption('force', 'f', '强制部署', false);
|
||||
}
|
||||
|
||||
protected function execute(\Fendx\Cli\Input\InputInterface $input, \Fendx\Cli\Output\OutputInterface $output): int
|
||||
{
|
||||
$environment = $input->getArgument('environment');
|
||||
$force = $input->getOption('force');
|
||||
|
||||
$output->writeln("<info>部署到 {$environment} 环境...</info>");
|
||||
|
||||
return match ($environment) {
|
||||
'local' => $this->deployLocal($output, $force),
|
||||
'docker' => $this->deployDocker($output, $force),
|
||||
'k8s' => $this->deployKubernetes($output, $force),
|
||||
default => $this->showError($output, "未知的环境: {$environment}")
|
||||
};
|
||||
}
|
||||
|
||||
private function deployLocal($output, $force): int
|
||||
{
|
||||
$output->writeln("<info>部署到本地环境...</info>");
|
||||
|
||||
// 检查依赖
|
||||
$this->executeCommand($output, "composer install");
|
||||
|
||||
// 运行迁移
|
||||
$this->executeCommand($output, "php bin/console migrate:run");
|
||||
|
||||
// 设置权限
|
||||
$this->executeCommand($output, "chmod -R 755 storage/ runtime/");
|
||||
|
||||
$output->writeln("<info>本地部署完成! 🎉</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function deployDocker($output, $force): int
|
||||
{
|
||||
$output->writeln("<info>部署到 Docker 环境...</info>");
|
||||
|
||||
if ($force) {
|
||||
$this->executeCommand($output, "docker-compose down --volumes");
|
||||
}
|
||||
|
||||
$this->executeCommand($output, "docker-compose up -d --build");
|
||||
|
||||
// 等待服务启动
|
||||
$output->writeln("<comment>等待服务启动...</comment>");
|
||||
sleep(30);
|
||||
|
||||
// 健康检查
|
||||
$this->executeCommand($output, "curl -f http://localhost/health");
|
||||
|
||||
$output->writeln("<info>Docker 部署完成! 🐳</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function deployKubernetes($output, $force): int
|
||||
{
|
||||
$output->writeln("<info>部署到 Kubernetes 环境...</info>");
|
||||
|
||||
if ($force) {
|
||||
$this->executeCommand($output, "kubectl delete namespace fendx");
|
||||
}
|
||||
|
||||
$this->executeCommand($output, "kubectl apply -f k8s/");
|
||||
|
||||
// 等待部署完成
|
||||
$this->executeCommand($output, "kubectl rollout status deployment/fendx-php -n fendx");
|
||||
|
||||
$output->writeln("<info>Kubernetes 部署完成! ☸️</info>");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 基准测试命令
|
||||
*/
|
||||
class BenchmarkCommand extends \Fendx\Cli\Command\Command
|
||||
{
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName('benchmark')
|
||||
->setDescription('运行性能基准测试')
|
||||
->addArgument('type', '测试类型: all, memory, database, cache, api');
|
||||
}
|
||||
|
||||
protected function execute(\Fendx\Cli\Input\InputInterface $input, \Fendx\Cli\Output\OutputInterface $output): int
|
||||
{
|
||||
$type = $input->getArgument('type') ?? 'all';
|
||||
|
||||
$output->writeln("<info>运行 {$type} 基准测试...</info>");
|
||||
|
||||
return match ($type) {
|
||||
'memory' => $this->benchmarkMemory($output),
|
||||
'database' => $this->benchmarkDatabase($output),
|
||||
'cache' => $this->benchmarkCache($output),
|
||||
'api' => $this->benchmarkApi($output),
|
||||
'all' => $this->benchmarkAll($output),
|
||||
default => $this->showError($output, "未知的测试类型: {$type}")
|
||||
};
|
||||
}
|
||||
|
||||
private function benchmarkMemory($output): int
|
||||
{
|
||||
$output->writeln("<info>内存基准测试...</info>");
|
||||
|
||||
$start = memory_get_usage();
|
||||
|
||||
// 模拟业务逻辑
|
||||
for ($i = 0; $i < 100000; $i++) {
|
||||
$data = ['id' => $i, 'name' => "user_{$i}", 'email' => "user{$i}@example.com"];
|
||||
$json = json_encode($data);
|
||||
$array = json_decode($json, true);
|
||||
}
|
||||
|
||||
$end = memory_get_usage();
|
||||
$used = ($end - $start) / 1024 / 1024;
|
||||
|
||||
$output->writeln("<info>内存使用: {$used} MB</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function benchmarkDatabase($output): int
|
||||
{
|
||||
$output->writeln("<info>数据库基准测试...</info>");
|
||||
|
||||
$start = microtime(true);
|
||||
|
||||
// 模拟数据库查询
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
// 这里应该执行实际的数据库查询
|
||||
usleep(100); // 模拟 0.1ms 查询时间
|
||||
}
|
||||
|
||||
$end = microtime(true);
|
||||
$duration = ($end - $start) * 1000;
|
||||
|
||||
$output->writeln("<info>1000 次查询耗时: {$duration} ms</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function benchmarkCache($output): int
|
||||
{
|
||||
$output->writeln("<info>缓存基准测试...</info>");
|
||||
|
||||
$start = microtime(true);
|
||||
|
||||
// 模拟缓存操作
|
||||
for ($i = 0; $i < 10000; $i++) {
|
||||
// 模拟缓存写入
|
||||
usleep(10); // 模拟 0.01ms 缓存时间
|
||||
// 模拟缓存读取
|
||||
usleep(5); // 模拟 0.005ms 缓存时间
|
||||
}
|
||||
|
||||
$end = microtime(true);
|
||||
$duration = ($end - $start) * 1000;
|
||||
|
||||
$output->writeln("<info>20000 次缓存操作耗时: {$duration} ms</info>");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function benchmarkApi($output): int
|
||||
{
|
||||
$output->writeln("<info>API 基准测试...</info>");
|
||||
|
||||
$this->executeCommand($output, "ab -n 1000 -c 10 http://localhost/api/users");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function benchmarkAll($output): int
|
||||
{
|
||||
$this->benchmarkMemory($output);
|
||||
$this->benchmarkDatabase($output);
|
||||
$this->benchmarkCache($output);
|
||||
$this->benchmarkApi($output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// 运行控制台应用
|
||||
try {
|
||||
$app = new ConsoleApplication();
|
||||
$app->run();
|
||||
} catch (\Exception $e) {
|
||||
echo "Error: " . $e->getMessage() . "\n";
|
||||
exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user