路由分组

路由分组允许将一组具有相同前缀、中间件或其他公共属性的路由组织在一起,避免重复声明。通过 Router::group() 实现。

注意Router::group() 第三个参数 $id 为必填项,用于唯一标识一个分组。

基本分组

前缀分组

最常见的用途是为一批路由添加统一的前缀路径:

php
use Viswoole\Router\Facade\Router;

Router::group('/api/v1', function () {
    Router::get('/user/info', [UserController::class, 'info']);
    Router::post('/user/create', [UserController::class, 'create']);
    Router::put('/user/update', [UserController::class, 'update']);
    Router::delete('/user/delete', [UserController::class, 'delete']);
}, 'api.v1');

// 实际路由:
// GET    /api/v1/user/info
// POST   /api/v1/user/create
// PUT    /api/v1/user/update
// DELETE /api/v1/user/delete

分组中间件

为整个分组的所有路由统一添加中间件:

php
Router::group('/api/v1', function () {
    Router::get('/order/list', [OrderController::class, 'list']);
    Router::get('/order/{id}', [OrderController::class, 'detail']);
}, 'api.v1.order')->setMiddlewares([AuthMiddleware::class, RateLimitMiddleware::class]);

域名分组

将一组路由限定在特定域名下:

php
Router::group('/api', function () {
    Router::get('/version', [ApiController::class, 'version']);
    Router::get('/status', [ApiController::class, 'status']);
}, 'api')->setDomain('api.example.com');

// 仅在 api.example.com 域名下生效

嵌套分组

分组支持多层嵌套,内层继承外层的所有属性:

php
Router::group('/api', function () {

    Router::group('/v1', function () {

        Router::group('/user', function () {
            Router::get('/info', [UserController::class, 'info']);
            Router::post('/create', [UserController::class, 'create']);
        }, 'api.v1.user')->setMiddlewares([UserMiddleware::class]);

        Router::group('/order', function () {
            Router::get('/list', [OrderController::class, 'list']);
            Router::post('/create', [OrderController::class, 'create']);
        }, 'api.v1.order')->setMiddlewares([OrderMiddleware::class]);

    }, 'api.v1')->setMiddlewares([ApiMiddleware::class, AuthMiddleware::class]);

}, 'api')->setDomain('api.example.com');

嵌套结果:

  • GET /api/v1/user/info — 中间件: [ApiMiddleware, AuthMiddleware, UserMiddleware]
  • POST /api/v1/order/create — 中间件: [ApiMiddleware, AuthMiddleware, OrderMiddleware]

分组属性汇总

Router::group() 返回的路由分组对象支持链式调用以下方法:

方法说明示例
setMiddlewares(array)添加中间件->setMiddlewares([Auth::class])
setDomain(string)限制域名->setDomain('api.example.com')
setSuffix(string)后缀要求->setSuffix('html')
patterns(array)参数正则约束->patterns(['id' => '\d+'])

与注解分组对应

配置文件的 Router::group() 与注解的 #[Controller] 是同一概念的两种表达方式:

php
// 方式一:配置文件分组
Router::group('/api/v1', function () {
    Router::get('/user/info', [UserController::class, 'info']);
}, 'api.v1')->setMiddlewares([AuthMiddleware::class]);

// 方式二:注解分组(效果等价)
#[Controller(prefix: '/api/v1', middlewares: [AuthMiddleware::class])]
class UserController
{
    #[RouteMapping(paths: ['/user/info'], method: ['GET'])]
    public function info(): array {}
}

选择建议:

  • 配置文件:跨控制器聚合、全局兜底路由
  • 注解:单控制器内部路由、与代码同位置维护

实际项目示例

php
<?php
// config/route/route.php
use App\Controller\Api\V1\{
    UserController,
    OrderController,
    ProductController,
};
use App\Controller\Admin\DashboardController;
use App\Middleware\{
    AuthMiddleware,
    AdminMiddleware,
    CorsMiddleware,
    RateLimitMiddleware,
};
use Viswoole\Router\Facade\Router;

/* ========== API 路由组 ========== */
Router::group('/api/v1', function () {

    // 用户模块
    Router::group('/user', function () {
        Router::get('/info', [UserController::class, 'info']);
        Router::post('/login', [UserController::class, 'login']); // 无需认证
        Router::put('/password', [UserController::class, 'updatePassword']);
    }, 'api.v1.user');

    // 订单模块(需认证)
    Router::group('/order', function () {
        Router::get('/list', [OrderController::class, 'list']);
        Router::get('/{id}', [OrderController::class, 'detail'])
            ->patterns(['id' => '\d+']);
        Router::post('/create', [OrderController::class, 'create']);
    }, 'api.v1.order')->setMiddlewares([AuthMiddleware::class]);

    // 商品模块(需认证 + 限流)
    Router::group('/product', function () {
        Router::get('/list', [ProductController::class, 'list']);
        Router::get('/{id}', [ProductController::class, 'detail'])
            ->patterns(['id' => '\d+']);
    }, 'api.v1.product')->setMiddlewares([AuthMiddleware::class, RateLimitMiddleware::class]);

}, 'api.v1')->setMiddlewares([CorsMiddleware::class]);

/* ========== 后台管理路由组 ========== */
Router::group('/admin', function () {
    Router::get('/dashboard', [DashboardController::class, 'index']);
    Router::get('/settings', [DashboardController::class, 'settings']);
}, 'admin')->setMiddlewares([AdminMiddleware::class])->setDomain('admin.example.com');

/* ========== 兜底路由 ========== */
Router::miss(function () {
    return ['code' => 404, 'message' => 'Not Found'];
});