--- name: module-scaffold version: 2.1.0 description: "生成 Hyperf 模块化业务模块脚手架(ConfigProvider/Controller/Service/Model)。当需要新建业务模块、创建 module、添加模块化功能时使用。基于 ModuleLoader 自动发现 + ConfigProvider 机制,无需修改 composer.json。" requires: [hyperf-service] --- > ⚠️ 核心执行流程已在 `.cursor/rules/skill-module-scaffold.mdc` 中由 Cursor 自动注入。 > 本文件提供完整模板、代码示例和边缘场景处理,供 Agent 按需深入 Read。 # Hyperf Module Scaffold ## 触发条件 用户要求创建新的业务模块、在 `modules/` 下新建功能模块、或提到"模块化"、"新模块"、"module"。 ## 前置条件 项目已完成模块化架构初始化: - `Case-Database-Backend/modules/` 目录存在 - `app/Support/ModuleLoader.php` 已存在并注册到 `composer.json` `autoload.files` - `config/autoload/annotations.php` 已包含 `BASE_PATH . '/modules'` 扫描路径 若未初始化,先引导用户完成架构搭建。 ## 工作原理 `ModuleLoader.php` 在 `vendor/autoload.php` 加载时(Hyperf DI 容器初始化之前)自动执行: 1. 扫描 `modules/*/composer.json` 2. 读取每个模块的 `extra.hyperf.config` 3. 通过反射注入 `Hyperf\Support\Composer::$extra` 4. 同时注册模块的 PSR-4 命名空间到 Composer ClassLoader 这使得 `ProviderConfig::load()` 能发现所有模块的 ConfigProvider,**无需将模块添加到主项目 `composer.json` 的 `require` 中**。 ## 执行流程 ### 1. 确认模块规格 | 字段 | 必填 | 默认值 | 说明 | |------|------|--------|------| | 模块名称 | ✅ | — | PascalCase,如 `Order`、`UserCenter` | | 模块描述 | ❌ | 推断 | 一句话说明模块职责 | | 接口类型 | ❌ | `api` | `api`(用户端)/ `admin`(管理端)/ `both`(两者都有) | | 需要 Service? | ❌ | true | 业务逻辑层 | | 需要 Model? | ❌ | false | 数据模型 | | 需要 Repository? | ❌ | false | 复杂查询时 | | 需要 Middleware? | ❌ | false | 模块级中间件 | | 需要 Request? | ❌ | false | 表单验证 | | 路由前缀 | ❌ | 见下方规则 | 自动推断,也可手动指定 | ### 2. Controller 与 Request 目录结构规则(核心) 根据接口类型,Controller 和 Request **均放入对应子目录**,命名空间随之变更: | 接口类型 | 路由前缀 | Controller 目录 | Request 目录 | PHP 命名空间(Controller) | |----------|----------|-----------------|--------------|--------------------------| | 用户端 API(`/api/*`) | `/api/{module-kebab}` | `Http/Controller/Api/` | `Http/Request/Api/` | `Modules\{Name}\Http\Controller\Api` | | 管理端 API(`/admin/*`) | `/admin/{module-kebab}` | `Http/Controller/Admin/` | `Http/Request/Admin/` | `Modules\{Name}\Http\Controller\Admin` | | 两者都有(`both`) | 各自前缀 | 两个 Controller 子目录 | 两个 Request 子目录 | 各自命名空间 | **判断规则**: - 路由前缀包含 `/api/` → Controller 放 `Controller/Api/`,Request 放 `Request/Api/` - 路由前缀包含 `/admin/` → Controller 放 `Controller/Admin/`,Request 放 `Request/Admin/` - 用户未指定接口类型时,优先询问,或根据模块职责推断 - 若模块同时有用户端和管理端接口,两组子目录都创建 - **类名不需要加接口类型前缀**,子目录本身已区分,类名保持简洁 ### 3. 生成目录结构 **仅有用户端 API(最常见)**: ``` modules/{ModuleName}/ ├── composer.json └── src/ ├── ConfigProvider.php ├── Http/ │ ├── Controller/ │ │ └── Api/ # 用户端控制器 │ │ └── {Name}Controller.php │ ├── Request/ │ │ └── Api/ # 用户端请求验证 │ │ └── {Name}Request.php │ └── Middleware/ # 模块中间件(按需) ├── Service/ ├── Model/ # 按需 ├── Repository/ # 按需 ├── Event/ # 按需 ├── Listener/ # 按需 └── Constants/ # 按需 ``` **仅有管理端 API**: ``` modules/{ModuleName}/ └── src/ ├── Http/ │ ├── Controller/ │ │ └── Admin/ # 管理端控制器 │ │ └── {Name}Controller.php │ ├── Request/ │ │ └── Admin/ # 管理端请求验证 │ │ └── {Name}Request.php ... ``` **同时有用户端 + 管理端(both)**: ``` modules/{ModuleName}/ └── src/ ├── Http/ │ ├── Controller/ │ │ ├── Api/ # 用户端控制器 │ │ │ └── {Name}Controller.php │ │ └── Admin/ # 管理端控制器 │ │ └── {Name}Controller.php │ ├── Request/ │ │ ├── Api/ # 用户端请求验证 │ │ │ └── {Name}Request.php │ │ └── Admin/ # 管理端请求验证 │ │ └── {Name}Request.php ... ``` ### 4. 生成 composer.json ```json { "name": "modules/{module-kebab}", "description": "{模块描述}", "type": "library", "autoload": { "psr-4": { "Modules\\{ModuleName}\\": "src/" } }, "extra": { "hyperf": { "config": "Modules\\{ModuleName}\\ConfigProvider" } } } ``` **命名规则**: - Composer 包名:`modules/{kebab-case}`,如 `modules/user-center` - PHP 命名空间:`Modules\{PascalCase}`,如 `Modules\UserCenter` 如模块有独立的第三方依赖,可在模块 `composer.json` 的 `require` 中声明,`wikimedia/composer-merge-plugin` 会在下次 `composer update` 时合并到主项目。 ### 5. 生成 ConfigProvider.php ```php [ // Interface::class => Implementation::class, ], 'annotations' => [ 'scan' => [ 'paths' => [ __DIR__, ], ], ], 'publish' => [], ]; } } ``` **ConfigProvider 职责**: - `dependencies`:注册模块的 DI 绑定(接口 → 实现) - `annotations.scan.paths`:注册注解扫描路径(`__DIR__` 指向 `src/`) - `publish`:可发布的配置文件(可选) ### 6. 生成 Controller 模板 **用户端 API Controller**(放在 `Http/Controller/Api/`): ```php success([]); } } ``` **管理端 API Controller**(放在 `Http/Controller/Admin/`): ```php success([]); } } ``` **关键区别**: - `Api/` 下:前缀 `/api/`,命名空间含 `\Api\` - `Admin/` 下:前缀 `/admin/`,命名空间含 `\Admin\`,自动加 `JwtAuthMiddleware` - **两者类名相同**(均为 `{Name}Controller`),由命名空间区分,无需加接口类型前缀 ### 7. 生成 Request 模板 **用户端 Request**(放在 `Http/Request/Api/`): ```php 'required|string|max:255', ]; } public function messages(): array { return []; } } ``` **管理端 Request**(放在 `Http/Request/Admin/`): ```php 'required|string|max:255', ]; } public function messages(): array { return []; } } ``` **关键区别**: - `Api/` 下:命名空间含 `\Request\Api\`,类名 `{Name}Request` - `Admin/` 下:命名空间含 `\Request\Admin\`,类名 `{Name}Request` - **两者类名相同**,由命名空间区分,无需加接口类型前缀 - Controller 中 `use` 路径需对应各自子命名空间 ### 8. 验证模块自动发现 创建文件后**无需任何 composer 操作**,直接验证: ```bash docker exec hyperf-skeleton php -r " define('BASE_PATH', '/opt/www'); require '/opt/www/vendor/autoload.php'; \$extra = Hyperf\Support\Composer::getMergedExtra('hyperf'); echo in_array('Modules\\{ModuleName}\\ConfigProvider', \$extra['config'] ?? []) ? 'OK' : 'FAIL'; " ``` ## 模块间依赖 若模块 A 依赖模块 B 的类: - 通过 DI 注入模块 B 的 Service(不直接依赖 Controller/Model) - 遵循依赖方向:上层模块 → 下层模块,禁止循环依赖 - ModuleLoader 的 glob 扫描天然支持多模块并存,无需额外配置 ## 已有模块示例参考 当前项目 `modules/Auth/` 的实际结构(**参考标准**): ``` modules/Auth/src/Http/Controller/ ├── Api/ # 用户端接口(推荐新规范) │ ├── AuthController.php # prefix: /api/auth │ ├── CaptchaController.php # prefix: /api/auth/captcha │ └── SmsController.php # prefix: /api/auth/sms └── Admin/ # 管理端接口(推荐新规范) └── AdminAuthController.php # prefix: /admin/auth ``` > 注:当前 Auth 模块尚未按此规范重构(所有 Controller 平铺在 `Controller/` 下),新模块应从一开始遵循子目录规范。 ## 验证 1. [ ] 模块目录结构完整(composer.json + src/ConfigProvider.php + Http/Controller/) 2. [ ] **Controller 按接口类型放入正确子目录**:`/api/*` → `Controller/Api/`,`/admin/*` → `Controller/Admin/` 3. [ ] Controller 命名空间包含正确子层级:`...\Http\Controller\Api\` 或 `...\Http\Controller\Admin\` 4. [ ] `Admin/` 下的 Controller 自动添加 `JwtAuthMiddleware`;类名与 `Api/` 下保持一致,无需加前缀 5. [ ] **Request 按接口类型放入正确子目录**:`/api/*` → `Request/Api/`,`/admin/*` → `Request/Admin/` 6. [ ] Request 命名空间包含正确子层级:`...\Http\Request\Api\` 或 `...\Http\Request\Admin\` 7. [ ] Controller 中 `use` 的 Request 路径与子目录一致 8. [ ] composer.json 的 `name` 使用 `modules/{kebab-case}` 格式 9. [ ] namespace 使用 `Modules\{PascalCase}` 格式 10. [ ] ConfigProvider 注册了 `__DIR__` 注解扫描路径 11. [ ] `extra.hyperf.config` 指向正确的 ConfigProvider 类 12. [ ] 无需修改主项目 `composer.json`,模块被 ModuleLoader 自动发现 13. [ ] `ProviderConfig::load()` 能发现模块 ConfigProvider 14. [ ] `php -l` 所有 PHP 文件语法正确 15. [ ] Controller 路由前缀遵循 RESTful 命名(kebab-case)