madong / swagger
Madong Swagger Documentation Module - 基于 webman-tech/swagger 的 Swagger 文档生成模块
Requires
- php: >=8.1
- webman-tech/dto: ^1.0
- webman-tech/swagger: ^2.1
- zircote/swagger-php: ^5.0
Requires (Dev)
- phpunit/phpunit: ^10.0
README
一个功能强大、结构清晰的 Swagger/OpenAPI 文档生成模块,专为 Webman 框架设计。
📋 目录
✨ 功能特性
- 完整的 OpenAPI 3.0 支持:基于
zircote/swagger-php和webman-tech/swagger - 清晰的注解分类:认证、操作、响应三类注解,职责分明
- 强大的响应注解:支持 6 种响应类型(Data、Page、List、Tree、Result、Simple)
- 权限注解集成:内置 AllowAnonymous 和 Permission 注解,支持权限中间件
- AnnotationHelper 工具:便捷获取控制器和方法的注解信息
- IS_REPEATABLE 支持:响应注解支持在同一个方法上重复使用
- 向后兼容:提供
core\attribute别名类,兼容旧代码 - 灵活的示例数据:支持多种数据格式(类、对象、JSON、数组)
📁 目录结构
packages/swagger/src/
├── attribute/ # 认证门面类(简化使用)
│ ├── AllowAnonymous.php # 跳过认证注解
│ ├── Permission.php # 权限注解
│ └── ValidationRule.php # 验证规则注解
│
├── annotation/ # 完整注解分类(实际实现)
│ ├── auth/ # 认证注解
│ │ ├── AllowAnonymous.php
│ │ ├── Permission.php
│ │ └── ValidationRule.php
│ │
│ ├── operation/ # 操作注解
│ │ ├── ApiOperation.php
│ │ ├── ApiParameter.php
│ │ └── ApiRequestBody.php
│ │
│ └── response/ # 响应注解(支持 IS_REPEATABLE)
│ ├── AbstractResponse.php
│ ├── DataResponse.php
│ ├── PageResponse.php
│ ├── ListResponse.php
│ ├── TreeResponse.php
│ ├── ResultResponse.php
│ ├── SimpleResponse.php
│ └── ResponseSchema.php
│
├── schema/ # Schema 基类
│ └── SchemaBase.php
│
└── helper/ # 辅助工具类
├── AnnotationHelper.php # 注解查询工具
├── ResponseHelper.php # 响应注解创建工具
├── ExampleHelper.php # 示例数据生成工具
└── SchemaHelper.php # Schema 辅助工具
命名空间规范
| 注解类型 | 命名空间 | 说明 |
|---|---|---|
| 响应注解 | madong\swagger\annotation\response\* | 只在 annotation 中,支持 IS_REPEATABLE |
| 认证注解 | madong\swagger\attribute\* | 推荐使用的门面类 |
| 认证注解 | madong\swagger\annotation\auth\* | 实际实现(可用但不推荐) |
| 操作注解 | madong\swagger\annotation\operation\* | 只在 annotation 中 |
| Schema 注解 | madong\swagger\annotation\schema\* | 只在 annotation 中 |
重要:响应类(DataResponse、PageResponse 等)只在 annotation/response 中存在,没有对应的 attribute 版本。认证类则同时存在于 attribute 和 annotation/auth 中。
🚀 快速开始
1. 安装
cd server/packages/swagger
composer install
2. 配置路由
在 app/adminapi/config/route.php 中注册 Swagger:
use Webman\Route;
use WebmanTech\Swagger\Swagger;
use OpenApi\Annotations as OA;
Route::group('/adminapi', function () {
// Swagger 文档路由配置
Swagger::create()->registerRoute([
'route_prefix' => '/openapi',
'register_route' => true,
'openapi_doc' => [
'scan_path' => [
base_path('app/adminapi'),
base_path('app/schema'), // Schema 目录
],
'exclude' => [
// 排除不需要扫描的文件
],
'modify' => function (OA\OpenApi $openapi) {
$openapi->info->title = config('app.name') . ' API';
$openapi->info->version = '1.0.0';
$openapi->servers = [
new OA\Server([
'url' => '/adminapi',
'description' => request()->host(),
]),
];
// 配置安全认证
if (!$openapi->components instanceof OA\Components) {
$openapi->components = new OA\Components([]);
}
$openapi->components->securitySchemes = [
new OA\SecurityScheme([
'securityScheme' => 'api_key',
'type' => 'apiKey',
'name' => config('madong.jwt.app.token_name', 'Authorization'),
'in' => 'header',
]),
];
},
],
]);
});
3. 创建 Schema
<?php
namespace app\schema;
use madong\swagger\annotation\schema\ApiProperty;
/**
* 用户 Schema
*/
class UserSchema
{
#[ApiProperty(property: 'id', type: 'integer', description: '用户ID')]
public int $id;
#[ApiProperty(property: 'username', type: 'string', description: '用户名')]
public string $username;
#[ApiProperty(property: 'email', type: 'string', description: '邮箱')]
public string $email;
#[ApiProperty(property: 'created_at', type: 'string', format: 'date-time', description: '创建时间')]
public string $created_at;
}
4. 在控制器中使用
<?php
namespace app\adminapi\controller;
use madong\swagger\annotation\response\DataResponse;
use madong\swagger\attribute\AllowAnonymous;
use OpenApi\Attributes as OA;
use support\Request;
class UserController
{
#[OA\Get(
path: '/user/{id}',
summary: '获取用户信息',
tags: ['用户管理']
)]
#[DataResponse(
response: 200,
schema: UserSchema::class,
description: '成功获取用户信息'
)]
#[DataResponse(
response: 404,
example: ['error' => '用户不存在'],
description: '用户未找到'
)]
#[AllowAnonymous]
public function getUser(Request $request, int $id)
{
// ...
}
}
5. 访问文档
启动服务后,访问:http://localhost:8787/adminapi/openapi
📚 注解分类详解
一、认证注解(attribute/ 或 annotation/auth/)
1. AllowAnonymous - 跳过认证
用于标记需要跳过 Token 验证或权限验证的接口。
推荐使用 attribute 命名空间:
use madong\swagger\attribute\AllowAnonymous;
class UserController
{
// 跳过所有认证
#[AllowAnonymous(requireToken: true, requirePermission: true)]
public function login()
{
// ...
}
// 仅跳过 Token 验证(需要权限验证)
#[AllowAnonymous(requireToken: true, requirePermission: false)]
public function getPublicInfo()
{
// ...
}
// 仅跳过权限验证(需要 Token 获取用户信息)
#[AllowAnonymous(requireToken: false, requirePermission: true)]
public function getCurrentUser()
{
// ...
}
// 使用便捷静态方法
#[AllowAnonymous::all('跳过所有认证')]
public function register()
{
// ...
}
#[AllowAnonymous::token('仅跳过 Token 验证')]
public function checkPermission()
{
// ...
}
#[AllowAnonymous::permission('仅跳过权限验证')]
public function getUserInfo()
{
// ...
}
}
属性说明:
$requireToken(bool): 是否跳过 Token 验证,默认为false$requirePermission(bool): 是否跳过权限验证,默认为false$description(?string): 描述,用于文档生成
2. Permission - 权限注解
用于标记控制器或方法需要的权限。
use madong\swagger\attribute\Permission;
class UserController
{
// 单个权限
#[Permission('user:list')]
public function getUserList()
{
// ...
}
// 多个权限(AND 关系,需全部满足)
#[Permission(['user:view', 'user:detail'])]
public function getUserDetail()
{
// ...
}
// 多个权限(OR 关系,任一满足即可)
#[Permission(['user:admin', 'user:super'], operation: 'or')]
public function deleteUser()
{
// ...
}
// 使用便捷静态方法
#[Permission::create('user:create')]
public function createUser()
{
// ...
}
#[Permission::all(['user:view', 'user:export'])]
public function exportUsers()
{
// ...
}
#[Permission::any(['user:admin', 'user:manager', 'user:super'])]
public function manageUser()
{
// ...
}
}
属性说明:
$code(string|array): 权限码,可以是字符串或数组$operation(string): 操作类型,and或or,默认为and$description(?string): 权限描述,用于文档
方法说明:
create(string $code): 创建单个权限all(array $codes): 创建 AND 关系的多个权限any(array $codes): 创建 OR 关系的多个权限getCodes(): array: 获取权限码列表getOperation(): string: 获取操作类型isAnd(): bool: 检查是否为 AND 操作isOr(): bool: 检查是否为 OR 操作
3. ValidationRule - 验证规则注解
用于在 Request 类的属性上定义验证规则,并可在 API 文档中展示验证信息。
namespace app\request;
use madong\swagger\attribute\ValidationRule;
class UserRequest
{
#[ValidationRule(
rules: 'required|string|max:50',
messages: ['required' => '用户名不能为空'],
description: '用户名'
)]
public string $username;
#[ValidationRule(
rules: ['required', 'email', 'max:100'],
description: '邮箱地址'
)]
public string $email;
#[ValidationRule(
rules: 'required|min:6|confirmed',
attributes: ['confirmed' => '密码确认'],
description: '密码'
)]
public string $password;
#[ValidationRule(
rules: 'nullable|integer|min:0|max:120',
example: 25,
description: '年龄'
)]
public ?int $age;
}
属性说明:
$rules(string|array): 验证规则$messages(array): 自定义错误消息$attributes(array): 字段名称映射$description(?string): 字段描述$example(mixed): 示例值
方法说明:
getRulesString(): string: 获取验证规则字符串getRulesArray(): array: 获取验证规则数组hasRule(string $rule): bool: 检查是否包含指定规则getRulesDescription(): string: 获取规则描述(用于文档展示)
二、响应注解(annotation/response/)
所有响应注解都支持 IS_REPEATABLE,可以在同一个方法上重复使用,用于定义不同状态码的响应。
1. DataResponse - 数据对象响应
返回单个数据对象的响应模板。
use madong\swagger\annotation\response\DataResponse;
use app\schema\UserSchema;
class UserController
{
#[DataResponse(
response: 200,
schema: UserSchema::class,
description: '成功获取用户信息'
)]
#[DataResponse(
response: 404,
example: ['error' => '用户不存在'],
description: '用户未找到'
)]
public function getUser(int $id)
{
// ...
}
}
参数说明:
$schema(mixed): Schema 类名、类对象或 JSON 字符串$example(mixed): 示例值(JSON 字符串、数组或对象)$description(string): 响应描述$response(int): HTTP 状态码,默认为 200$headers(array): 响应头
响应格式:
{
"code": 0,
"message": "success",
"data": { "id": 1, "name": "admin" }
}
2. PageResponse - 分页响应
返回分页数据的响应模板。
use madong\swagger\annotation\response\PageResponse;
use app\schema\UserListSchema;
class UserController
{
#[PageResponse(
response: 200,
schema: UserListSchema::class,
description: '成功获取用户列表'
)]
public function getUserList()
{
// ...
}
}
响应格式:
{
"code": 0,
"message": "success",
"data": {
"total": 100,
"page": 1,
"limit": 10,
"list": [
{ "id": 1, "name": "admin" },
{ "id": 2, "name": "user" }
]
}
}
3. ListResponse - 列表响应
返回列表数据的响应模板。
use madong\swagger\annotation\response\ListResponse;
class UserController
{
#[ListResponse(
response: 200,
schema: UserListSchema::class,
description: '成功获取用户列表'
)]
public function getAllUsers()
{
// ...
}
}
响应格式:
{
"code": 0,
"message": "success",
"data": {
"list": [
{ "id": 1, "name": "admin" },
{ "id": 2, "name": "user" }
]
}
}
4. TreeResponse - 树形数据响应
返回树形数据的响应模板。
use madong\swagger\annotation\response\TreeResponse;
use app\schema\MenuSchema;
class MenuController
{
#[TreeResponse(
response: 200,
schema: MenuSchema::class,
description: '成功获取菜单树'
)]
public function getMenuTree()
{
// ...
}
}
响应格式:
{
"code": 0,
"message": "success",
"data": [
{
"id": 1,
"name": "系统管理",
"children": [
{ "id": 2, "name": "用户管理", "children": [] }
]
}
]
}
5. ResultResponse - 通用结果响应
返回通用结果的响应模板。
use madong\swagger\annotation\response\ResultResponse;
class AuthController
{
#[ResultResponse(
response: 200,
jsonExample: '{"code": 0, "message": "操作成功"}',
description: '操作成功'
)]
#[ResultResponse(
response: 401,
jsonExample: '{"code": 401, "message": "未授权"}',
description: '认证失败'
)]
public function login()
{
// ...
}
}
参数说明:
$jsonExample(?string): JSON 字符串示例$schema(?string): Schema 类名(可选)$dataExample(mixed): 数据示例(可选)$description(string): 响应描述$response(int): HTTP 状态码,默认为 200$headers(array): 响应头
6. SimpleResponse - 简单响应
返回简单成功消息的响应模板。
use madong\swagger\annotation\response\SimpleResponse;
class UserController
{
#[SimpleResponse(
response: 200,
example: ['flag' => true],
description: '操作成功'
)]
#[SimpleResponse(
response: 422,
example: ['error' => '验证失败'],
description: '验证错误'
)]
public function updateStatus()
{
// ...
}
}
响应格式:
{
"code": 0,
"message": "success",
"data": null // 或使用 example 指定的值
}
三、操作注解(annotation/operation/)
1. ApiOperation - 操作信息
use madong\swagger\annotation\operation\ApiOperation;
#[ApiOperation(
summary: '创建用户',
description: '创建一个新的用户账号,需要管理员权限',
tags: ['用户管理']
)]
public function createUser()
{
// ...
}
2. ApiParameter - 参数定义
use madong\swagger\annotation\operation\ApiParameter;
#[ApiParameter(
name: 'id',
in: 'path',
description: '用户ID',
required: true,
type: 'integer'
)]
public function getUser(int $id)
{
// ...
}
3. ApiRequestBody - 请求体
use madong\swagger\annotation\operation\ApiRequestBody;
use app\request\UserRequest;
#[ApiRequestBody(
description: '用户信息',
required: true,
schema: UserRequest::class
)]
public function createUser()
{
// ...
}
🔧 AnnotationHelper 使用
AnnotationHelper 提供了一组便捷方法来获取控制器和方法的注解信息,主要用于中间件和文档生成。
基本用法
use madong\swagger\helper\AnnotationHelper;
use madong\swagger\attribute\AllowAnonymous;
use madong\swagger\attribute\Permission;
// 获取方法上的 AllowAnonymous 注解
$AllowAnonymous = AnnotationHelper::getMethodAnnotation(
'app\adminapi\controller\UserController',
'login',
AllowAnonymous::class
);
if ($AllowAnonymous && $AllowAnonymous->shouldrequirePermission()) {
// 跳过权限验证
}
// 检查方法是否存在 Permission 注解
$hasPermission = AnnotationHelper::hasMethodAnnotation(
$controllerClass,
$action,
Permission::class
);
// 获取方法上的所有 OA 注解
$oaAnnotations = AnnotationHelper::getMethodOaAnnotations(
$controllerClass,
$action
);
完整 API
获取注解
// 获取方法上的指定注解实例
AnnotationHelper::getMethodAnnotation(
string $controllerClass, // 控制器完整类名
string $methodName, // 方法名
string $annotationClass // 注解类名
): ?object
// 获取类上的指定注解实例
AnnotationHelper::getClassAnnotation(
string $controllerClass,
string $annotationClass
): ?object
// 获取方法上的所有 OA 注解实例
AnnotationHelper::getMethodOaAnnotations(
string $controllerClass,
string $methodName
): array
// 获取类上的所有 OA 注解实例
AnnotationHelper::getClassOaAnnotations(
string $controllerClass
): array
// 获取方法上的所有注解实例
AnnotationHelper::getAllMethodAnnotations(
string $controllerClass,
string $methodName
): array
// 获取类上的所有注解实例
AnnotationHelper::getAllClassAnnotations(
string $controllerClass
): array
检查注解
// 检查方法是否存在指定注解
AnnotationHelper::hasMethodAnnotation(
string $controllerClass,
string $methodName,
string $annotationClass
): bool
// 检查类是否存在指定注解
AnnotationHelper::hasClassAnnotation(
string $controllerClass,
string $annotationClass
): bool
实际应用场景
场景 1:权限中间件
namespace app\adminapi\middleware;
use madong\swagger\helper\AnnotationHelper;
use madong\swagger\attribute\AllowAnonymous;
use madong\swagger\attribute\Permission;
use Webman\Http\Request;
use Webman\Http\Response;
use Webman\MiddlewareInterface;
class PermissionMiddleware implements MiddlewareInterface
{
public function process(Request $request, callable $handler): Response
{
$controllerClass = $request->controller;
$action = $request->action;
// 检查是否跳过认证
$AllowAnonymous = AnnotationHelper::getMethodAnnotation(
$controllerClass,
$action,
AllowAnonymous::class
);
if ($AllowAnonymous && $AllowAnonymous->shouldrequirePermission()) {
return $handler($request);
}
// 获取权限注解
$permission = AnnotationHelper::getMethodAnnotation(
$controllerClass,
$action,
Permission::class
);
if ($permission) {
// 执行权限验证逻辑
$this->validatePermission($permission, $request);
}
return $handler($request);
}
private function validatePermission(Permission $permission, Request $request): void
{
$codes = $permission->getCodes();
$operation = $permission->getOperation();
// 执行 Casbin 或其他权限验证逻辑
// ...
}
}
场景 2:文档生成
use madong\swagger\helper\AnnotationHelper;
use OpenApi\Attributes as OA;
class DocGenerator
{
public function generatePath(string $controllerClass, string $methodName): array
{
$paths = [];
// 获取所有 OA 注解
$oaAnnotations = AnnotationHelper::getMethodOaAnnotations(
$controllerClass,
$methodName
);
foreach ($oaAnnotations as $annotation) {
if ($annotation instanceof OA\Get) {
$paths['get'] = $this->generateGetDoc($annotation);
} elseif ($annotation instanceof OA\Post) {
$paths['post'] = $this->generatePostDoc($annotation);
}
// ... 其他 HTTP 方法
}
return $paths;
}
}
场景 3:API 元数据收集
use madong\swagger\helper\AnnotationHelper;
use madong\swagger\attribute\Permission;
use madong\swagger\annotation\operation\ApiOperation;
class ApiMetadataCollector
{
public function collect(string $controllerClass, string $methodName): array
{
$metadata = [];
// 获取 API 操作信息
$apiOperation = AnnotationHelper::getMethodAnnotation(
$controllerClass,
$methodName,
ApiOperation::class
);
if ($apiOperation) {
$metadata['summary'] = $apiOperation->summary;
$metadata['description'] = $apiOperation->description;
}
// 获取认证信息
$AllowAnonymous = AnnotationHelper::getMethodAnnotation(
$controllerClass,
$methodName,
AllowAnonymous::class
);
$metadata['requiresAuth'] = $AllowAnonymous === null || !$AllowAnonymous->shouldrequireToken();
// 获取权限信息
$permission = AnnotationHelper::getMethodAnnotation(
$controllerClass,
$methodName,
Permission::class
);
if ($permission) {
$metadata['permissions'] = $permission->getCodes();
$metadata['permissionOperation'] = $permission->getOperation();
}
return $metadata;
}
}
🔄 IS_REPEATABLE 支持
问题描述
在 PHP 8 中,属性默认不允许在同一个目标上重复使用。如果需要在同一个方法上定义多个响应(例如不同状态码的响应),会出现以下错误:
Error: Attribute "madong\swagger\annotation\response\DataResponse" must not be repeated
解决方案
本模块已为所有响应注解添加了 Attribute::IS_REPEATABLE 标志,支持在同一个方法上重复使用。
使用示例
use madong\swagger\annotation\response\DataResponse;
use app\schema\UserSchema;
#[DataResponse(
response: 200,
schema: UserSchema::class,
description: '成功获取用户信息'
)]
#[DataResponse(
response: 404,
example: ['error' => '用户不存在'],
description: '用户未找到'
)]
#[DataResponse(
response: 403,
example: ['error' => '无权访问该用户'],
description: '权限不足'
)]
public function getUser(int $id): Response
{
// ...
}
支持 IS_REPEATABLE 的注解
所有响应注解都支持重复使用:
DataResponsePageResponseListResponseTreeResponseResultResponseSimpleResponse
不支持重复的注解
以下注解不需要重复,因此不添加 IS_REPEATABLE 标志:
AllowAnonymous- 跳过认证(一个方法只需要一个)Permission- 权限(一个方法只需要一个)ValidationRule- 验证规则(用于属性)ApiOperation- 操作信息(一个方法只需要一个)
💡 最佳实践
1. 统一命名空间使用
推荐做法:
- 响应注解使用
madong\swagger\annotation\response\* - 认证注解使用
madong\swagger\attribute\*
use madong\swagger\annotation\response\DataResponse;
use madong\swagger\attribute\AllowAnonymous;
use madong\swagger\attribute\Permission;
不推荐做法:
// 避免混用
use madong\swagger\attribute\DataResponse; // 错误:attribute 中没有 DataResponse
use madong\swagger\annotation\auth\AllowAnonymous; // 可用但不推荐
2. 合理使用响应注解重复
虽然支持重复,但建议根据实际业务需求合理使用:
推荐(2-3 个响应):
#[DataResponse(response: 200, schema: UserSchema::class)]
#[DataResponse(response: 404, example: ['error' => '用户不存在'])]
#[DataResponse(response: 403, example: ['error' => '无权访问'])]
不推荐(过多响应):
// 避免定义过多不常用的响应
#[DataResponse(response: 200, schema: UserSchema::class)]
#[DataResponse(response: 400, example: ['error' => 'Bad Request'])]
#[DataResponse(response: 401, example: ['error' => 'Unauthorized'])]
#[DataResponse(response: 403, example: ['error' => 'Forbidden'])]
#[DataResponse(response: 404, example: ['error' => 'Not Found'])]
#[DataResponse(response: 500, example: ['error' => 'Server Error'])]
3. 使用 ResponseHelper 简化代码
use madong\swagger\helper\ResponseHelper;
// 推荐:使用 ResponseHelper
#[ResponseHelper::data(UserSchema::class, [
'description' => '成功',
'response' => 200
])]
// 不推荐:直接实例化
#[new DataResponse(
schema: UserSchema::class,
description: '成功',
response: 200
)]
4. 权限注解的层级使用
类级别权限(作用于所有方法):
use madong\swagger\attribute\Permission;
#[Permission('user:manage')]
class UserController
{
// 所有方法都需要 user:manage 权限
}
方法级别权限(覆盖或补充类级别):
class UserController
{
#[Permission('user:view')]
public function getUser()
{
// 只需要 user:view 权限
}
#[Permission('user:delete')]
public function deleteUser()
{
// 需要 user:delete 权限
}
}
5. 使用 ExampleHelper 生成示例数据
use madong\swagger\helper\ExampleHelper;
// 分页示例
#[PageResponse(
response: 200,
schema: UserSchema::class,
listExample: ExampleHelper::page([
['id' => 1, 'name' => 'admin'],
['id' => 2, 'name' => 'user']
], 100, 1, 10)
)]
// 树形示例
#[TreeResponse(
response: 200,
schema: MenuSchema::class,
dataExample: ExampleHelper::tree([
['id' => 1, 'name' => '系统', 'parent_id' => 0],
['id' => 2, 'name' => '用户', 'parent_id' => 1]
])
)]
🔄 向后兼容
为了向后兼容,项目保留了 core\attribute 命名空间下的别名类:
core\attribute\AllowAnonymous- 继承自madong\swagger\attribute\AllowAnonymouscore\attribute\Permission- 继承自madong\swagger\annotation\auth\Permission
兼容性说明
旧代码(继续有效):
use core\attribute\AllowAnonymous;
use core\attribute\Permission;
class UserController
{
#[AllowAnonymous]
public function login()
{
// ...
}
#[Permission('user:list')]
public function getUserList()
{
// ...
}
}
新代码(推荐):
use madong\swagger\attribute\AllowAnonymous;
use madong\swagger\attribute\Permission;
class UserController
{
#[AllowAnonymous]
public function login()
{
// ...
}
#[Permission('user:list')]
public function getUserList()
{
// ...
}
}
注意: 响应类(DataResponse、PageResponse 等)没有 core\attribute 别名,因为它们主要在控制器中使用,不需要被中间件频繁查询。
❓ 常见问题
Q1: 为什么响应类只在 annotation/response 中,没有 attribute 版本?
A: 响应类主要用于控制器文档注解,不需要被中间件频繁查询。认证类(AllowAnonymous/Permission)需要被中间件频繁查询,因此提供 attribute 门面简化使用。
Q2: 使用 attribute 和 annotation/auth 有什么区别?
A: 没有区别,attribute\* 类继承自 annotation\auth\* 类,两者完全等价。推荐使用 attribute 命名空间,更简洁。
Q3: AnnotationHelper 获取注解时应该用哪个类?
A: 推荐统一使用 attribute\* 类:
// 推荐
AnnotationHelper::getMethodAnnotation($class, $method, AllowAnonymous::class);
// 等价(但不推荐混用)
AnnotationHelper::getMethodAnnotation($class, $method, \madong\...\auth\AllowAnonymous::class);
Q4: 为什么我的响应注解还是提示不能重复?
A: 请检查:
是否使用了正确的命名空间:
// 正确 use madong\swagger\annotation\response\DataResponse; // 错误(不存在) use madong\swagger\attribute\DataResponse;是否重新生成了自动加载:
composer dump-autoload是否更新了 vendor 目录:
# 确保 packages/swagger/src 同步到 vendor/madong/swagger/src composer install
Q5: 如何在中间件中获取注解?
A: 使用 AnnotationHelper:
use madong\swagger\helper\AnnotationHelper;
use madong\swagger\attribute\AllowAnonymous;
class PermissionMiddleware
{
public function process(Request $request, callable $handler): Response
{
$controller = $request->controller;
$action = $request->action;
$AllowAnonymous = AnnotationHelper::getMethodAnnotation(
$controller,
$action,
AllowAnonymous::class
);
if ($AllowAnonymous && $AllowAnonymous->shouldrequirePermission()) {
return $handler($request);
}
// ...
}
}
Q6: 如何排除测试控制器不生成文档?
A: 在路由配置中排除:
Swagger::create()->registerRoute([
'openapi_doc' => [
'scan_path' => [
base_path('app/adminapi'),
],
'exclude' => [
base_path('app/adminapi/controller/test'), // 排除测试目录
],
],
]);
📄 更新日志
v1.0.0 (2026-03-11)
新增功能
- ✅ 完整的 OpenAPI 3.0 支持
- ✅ 6 种响应注解(Data、Page、List、Tree、Result、Simple)
- ✅ 3 种认证注解(AllowAnonymous、Permission、ValidationRule)
- ✅ 3 种操作注解(ApiOperation、ApiParameter、ApiRequestBody)
- ✅ AnnotationHelper 注解查询工具
- ✅ ResponseHelper 响应注解创建工具
- ✅ ExampleHelper 示例数据生成工具
- ✅ SchemaHelper Schema 辅助工具
优化改进
- ✅ 优化目录结构:attribute(门面)+ annotation(实现)
- ✅ 添加 IS_REPEATABLE 支持,响应注解可重复使用
- ✅ 修复命名空间大小写问题
- ✅ 修复访问级别错误(private → protected)
- ✅ 添加向后兼容别名(core\attribute)
文档完善
- ✅ 完整的 README.md
- ✅ 命名空间规范指南
- ✅ IS_REPEATABLE 修复说明
- ✅ AnnotationHelper 使用示例
- ✅ 最佳实践指南
🤝 贡献
欢迎提交 Issue 和 Pull Request!
📄 许可证
MIT License
🙏 致谢
- Webman - 高性能 HTTP 框架
- Swagger PHP - OpenAPI 注解库
- Webman Swagger - Webman Swagger 集成
📞 联系方式
- 作者:Mr. April
- 邮箱:405784684@qq.com
- 官方网站:http://www.madong.tech
- Gitee:https://gitee.com/motion-code
Made with ❤️ by Madong