注解路由

XinAdmin 实现了控制器注解路由,通过在控制器上添加 PHP Attribute 注解来定义路由、中间件和权限。

工作原理

AnnoRouteService 会扫描所有带有 #[RequestAttribute] 注解的控制器类,解析类级别和方法级别的注解,自动注册对应的路由。

核心组件

组件命名空间说明
RequestAttributeXin\AnnoRoute\RequestAttribute控制器类级别注解
GetRouteXin\AnnoRoute\Route\GetRouteGET 请求路由注解
PostRouteXin\AnnoRoute\Route\PostRoutePOST 请求路由注解
PutRouteXin\AnnoRoute\Route\PutRoutePUT 请求路由注解
DeleteRouteXin\AnnoRoute\Route\DeleteRouteDELETE 请求路由注解
QueryXin\AnnoRoute\Crud\QueryCRUD 查询列表注解
FindXin\AnnoRoute\Crud\FindCRUD 查询单个注解
CreateXin\AnnoRoute\Crud\CreateCRUD 新增注解
UpdateXin\AnnoRoute\Crud\UpdateCRUD 更新注解
DeleteXin\AnnoRoute\Crud\DeleteCRUD 删除注解

控制器类注解

在控制器类上使用 #[RequestAttribute] 注解:

<?php

namespace App\Http\Controllers\Admin;

use Xin\AnnoRoute\RequestAttribute;

#[RequestAttribute(
    routePrefix: '/admin/user',
    abilitiesPrefix: 'admin',
    middleware: ['admin.auth'],
    authGuard: 'admin'
)]
class UserController extends Controller
{
    // 控制器方法
}

参数说明:

参数类型默认值说明
routePrefixstring''路由前缀,完整路由地址由此前缀 + 方法注解的 route 拼接
abilitiesPrefixstring''权限能力前缀,最终权限由此前缀 + authorize 拼接
middlewarestring|array''控制器中间件
authGuardstring|nullnull认证守卫提供者

方法路由注解

在控制器方法上使用路由注解来定义单个路由:

GetRoute - GET 请求

use Xin\AnnoRoute\Route\GetRoute;

#[GetRoute(
    route: '/list',
    authorize: 'user.list',
    middleware: ['throttle:60,1'],
    where: ['id' => '[0-9]+']
)]
public function list(): JsonResponse
{
    // ...
}

PostRoute - POST 请求

use Xin\AnnoRoute\Route\PostRoute;

#[PostRoute(
    route: '/create',
    authorize: 'user.create',
    middleware: [],
    where: []
)]
public function create(): JsonResponse
{
    // ...
}

PutRoute - PUT 请求

use Xin\AnnoRoute\Route\PutRoute;

#[PutRoute(
    route: '/{id}',
    authorize: 'user.update',
    where: ['id' => '[0-9]+']
)]
public function update(int $id): JsonResponse
{
    // ...
}

DeleteRoute - DELETE 请求

use Xin\AnnoRoute\Route\DeleteRoute;

#[DeleteRoute(
    route: '/{id}',
    authorize: 'user.delete',
    where: ['id' => '[0-9]+']
)]
public function delete(int $id): JsonResponse
{
    // ...
}

路由注解参数说明:

参数类型默认值说明
routestring''路由地址,相对于类级别的 routePrefix
authorizestring|booltrue权限能力字符串,true 表示无需权限,false 表示无需登录
middlewarestring|array''路由中间件
wherearray[]路由参数正则约束,如 ['id' => '[0-9]+']

CRUD 注解

CRUD 注解是类级别注解,使用时会自动在控制器中查找 $service 属性作为仓储类,自动生成对应的路由处理闭包。

定义仓储服务

控制器必须定义 $service 属性:

<?php

namespace App\Http\Controllers\Admin;

use App\Repository\UserRepository;
use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Crud\Query;
use Xin\AnnoRoute\Crud\Find;
use Xin\AnnoRoute\Crud\Create;
use Xin\AnnoRoute\Crud\Update;
use Xin\AnnoRoute\Crud\Delete;

#[RequestAttribute(routePrefix: '/admin/user', abilitiesPrefix: 'admin')]
#[Query, Find, Create, Update, Delete]
class UserController extends Controller
{
    protected string $service = UserRepository::class;
}

Query - 查询列表

#[Query(
    middleware: ['throttle:60,1'],
    where: []
)]
  • HTTP 方法: GET
  • 路由地址: /
  • 默认权限: query
  • 仓储方法: query($request->query())

Find - 查询单个

#[Find(
    middleware: [],
    where: ['id' => '[0-9]+']
)]
  • HTTP 方法: GET
  • 路由地址: /{id}
  • 默认权限: find
  • 路由约束: id 必须为数字
  • 仓储方法: find($id)

Create - 新增

#[Create(
    middleware: [],
    where: []
)]
  • HTTP 方法: POST
  • 路由地址: /
  • 默认权限: create
  • 仓储方法: create($request->all())

Update - 更新

#[Update(
    middleware: [],
    where: ['id' => '[0-9]+']
)]
  • HTTP 方法: PUT
  • 路由地址: /{id}
  • 默认权限: update
  • 路由约束: id 必须为数字
  • 仓储方法: update($id, $request->all())

Delete - 删除

#[Delete(
    middleware: [],
    where: ['id' => '[0-9]+']
)]
  • HTTP 方法: DELETE
  • 路由地址: /{id}
  • 默认权限: delete
  • 路由约束: id 必须为数字
  • 仓储方法: delete($id)

完整示例

示例一:使用 CRUD 注解

<?php

namespace App\Http\Controllers\Admin;

use App\Repository\ArticleRepository;
use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Crud\Query;
use Xin\AnnoRoute\Crud\Find;
use Xin\AnnoRoute\Crud\Create;
use Xin\AnnoRoute\Crud\Update;
use Xin\AnnoRoute\Crud\Delete;

#[RequestAttribute(
    routePrefix: '/admin/article',
    abilitiesPrefix: 'admin',
    middleware: ['admin.auth']
)]
#[Query, Find, Create, Update, Delete]
class ArticleController extends Controller
{
    public function __construct(
        protected ArticleService $service
    ) {}
}

生成的路由:

方法路由权限说明
GET/admin/articleadmin.query查询文章列表
GET/admin/article/{id}admin.find查询单个文章
POST/admin/articleadmin.create新增文章
PUT/admin/article/{id}admin.update更新文章
DELETE/admin/article/{id}admin.delete删除文章

生成的路由:

方法路由权限说明
GET/admin/useradmin.query查询用户列表
GET/admin/user/{id}admin.find查询单个用户
POST/admin/user/importuser.import导入用户
GET/admin/user/exportuser.export导出用户
POST/admin/user/toggle-status/{id}user.toggle切换用户状态

示例二:无需权限控制的公开接口

<?php

namespace App\Http\Controllers\Api;

use Xin\AnnoRoute\RequestAttribute;
use Xin\AnnoRoute\Route\GetRoute;
use Xin\AnnoRoute\Route\PostRoute;

#[RequestAttribute(routePrefix: '/api/public')]
class PublicController extends Controller
{
    #[GetRoute(route: '/banner')]
    public function banner(): JsonResponse
    {
        // 需要登录...
    }

    #[PostRoute(route: '/feedback', authorize: false)]
    public function feedback(): JsonResponse
    {
        // 无需权限验证...
    }
}

authorize 参数说明:

说明
true需要登录,使用默认权限检查
false需要登录,但不检查具体权限能力
字符串需要登录,并检查指定权限能力

路由注解公共属性

所有路由注解都继承自 BaseAttribute,包含以下公共属性:

属性类型说明
routestring路由地址
middlewarestring|array中间件
httpMethodstringHTTP 请求方法
authorizestring|bool权限能力
wherearray路由参数正则约束

中间件组合

中间件可以全局设置(类级别)、局部设置(方法级别),最终会合并:

#[RequestAttribute(
    routePrefix: '/admin/user',
    middleware: ['admin.auth']  // 全局中间件
)]
class UserController extends Controller
{
    #[PostRoute(
        route: '/create',
        middleware: ['throttle:60,1']  // 额外局部中间件
    )]
    public function create(): JsonResponse
    {
        // 最终中间件: ['admin.auth', 'throttle:60,1']
    }
}

权限能力组合

权限能力由 abilitiesPrefixauthorize 拼接而成:

#[RequestAttribute(
    routePrefix: '/admin/user',
    abilitiesPrefix: 'admin'  // 能力前缀
)]
#[Create]
class UserController extends Controller
{
    // Create 注解的 authorize 默认为 'create'
    // 最终权限能力: 'admin.create'
}