路由分组
路由分组允许将一组具有相同前缀、中间件或其他公共属性的路由组织在一起,避免重复声明。通过 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'];
});