madong/swagger

Madong Swagger Documentation Module - 基于 webman-tech/swagger 的 Swagger 文档生成模块

Maintainers

Package info

gitcode.com/motion-code/swagger.git

pkg:composer/madong/swagger

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

2.0.4 2026-03-12 05:22 UTC

This package is auto-updated.

Last update: 2026-03-12 05:28:45 UTC


README

PHP >= 8.1 OpenAPI 3.0 Webman

一个功能强大、结构清晰的 Swagger/OpenAPI 文档生成模块,专为 Webman 框架设计。

📋 目录

✨ 功能特性

  • 完整的 OpenAPI 3.0 支持:基于 zircote/swagger-phpwebman-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 版本。认证类则同时存在于 attributeannotation/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): 操作类型,andor,默认为 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 的注解

所有响应注解都支持重复使用:

  • DataResponse
  • PageResponse
  • ListResponse
  • TreeResponse
  • ResultResponse
  • SimpleResponse

不支持重复的注解

以下注解不需要重复,因此不添加 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\AllowAnonymous
  • core\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: 请检查:

  1. 是否使用了正确的命名空间:

    // 正确
    use madong\swagger\annotation\response\DataResponse;
       
    // 错误(不存在)
    use madong\swagger\attribute\DataResponse;
    
  2. 是否重新生成了自动加载:

    composer dump-autoload
    
  3. 是否更新了 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

🙏 致谢

📞 联系方式

Made with ❤️ by Madong