108 lines
3.0 KiB
PHP
108 lines
3.0 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
declare(strict_types=1);
|
||
|
|
|
||
|
|
namespace App\Command;
|
||
|
|
|
||
|
|
use App\Model\Route;
|
||
|
|
use Hyperf\Command\Annotation\Command;
|
||
|
|
use Hyperf\Command\Command as HyperfCommand;
|
||
|
|
use Hyperf\HttpServer\Router\DispatcherFactory;
|
||
|
|
use Hyperf\HttpServer\Router\Handler;
|
||
|
|
use Hyperf\HttpServer\Router\RouteCollector;
|
||
|
|
use Psr\Container\ContainerInterface;
|
||
|
|
|
||
|
|
#[Command]
|
||
|
|
class RouteSyncCommand extends HyperfCommand
|
||
|
|
{
|
||
|
|
public function __construct(protected ContainerInterface $container)
|
||
|
|
{
|
||
|
|
parent::__construct('route:sync');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function configure(): void
|
||
|
|
{
|
||
|
|
parent::configure();
|
||
|
|
$this->setDescription('同步 Hyperf 注解路由到 routes 表');
|
||
|
|
}
|
||
|
|
|
||
|
|
public function handle(): void
|
||
|
|
{
|
||
|
|
$factory = $this->container->get(DispatcherFactory::class);
|
||
|
|
$router = $factory->getRouter('http');
|
||
|
|
$routes = $this->extractRoutes($router);
|
||
|
|
|
||
|
|
$synced = 0;
|
||
|
|
foreach ($routes as $route_info) {
|
||
|
|
Route::query()->updateOrCreate(
|
||
|
|
['method' => $route_info['method'], 'path' => $route_info['path']],
|
||
|
|
['name' => $route_info['name']]
|
||
|
|
);
|
||
|
|
$synced++;
|
||
|
|
}
|
||
|
|
|
||
|
|
$this->info("Synced {$synced} routes to database.");
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 从路由收集器中提取所有 API 路由
|
||
|
|
*
|
||
|
|
* @return array<int, array{method: string, path: string, name: string|null}>
|
||
|
|
*/
|
||
|
|
protected function extractRoutes(RouteCollector $router): array
|
||
|
|
{
|
||
|
|
$routes = [];
|
||
|
|
[$staticRouters, $variableRouters] = $router->getData();
|
||
|
|
|
||
|
|
// 静态路由(无路径参数)
|
||
|
|
foreach ($staticRouters as $method => $items) {
|
||
|
|
foreach ($items as $handler) {
|
||
|
|
$this->collectRoute($routes, $method, $handler);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// 动态路由(含路径参数如 {id})
|
||
|
|
foreach ($variableRouters as $method => $items) {
|
||
|
|
foreach ($items as $item) {
|
||
|
|
if (is_array($item['routeMap'] ?? false)) {
|
||
|
|
foreach ($item['routeMap'] as $routeMap) {
|
||
|
|
$this->collectRoute($routes, $method, $routeMap[0]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return $routes;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 收集单条路由信息,仅同步 /api/ 前缀的路由
|
||
|
|
*/
|
||
|
|
protected function collectRoute(array &$routes, string $method, Handler $handler): void
|
||
|
|
{
|
||
|
|
$path = $handler->route;
|
||
|
|
|
||
|
|
// 仅同步 API 路由
|
||
|
|
if (!str_starts_with($path, '/api/')) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// 解析 action 名称
|
||
|
|
$name = null;
|
||
|
|
if (is_array($handler->callback)) {
|
||
|
|
$name = $handler->callback[0] . '::' . $handler->callback[1];
|
||
|
|
} elseif (is_string($handler->callback)) {
|
||
|
|
$name = $handler->callback;
|
||
|
|
}
|
||
|
|
|
||
|
|
$key = $method . '|' . $path;
|
||
|
|
if (!isset($routes[$key])) {
|
||
|
|
$routes[$key] = [
|
||
|
|
'method' => $method,
|
||
|
|
'path' => $path,
|
||
|
|
'name' => $name,
|
||
|
|
];
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|