初始化

This commit is contained in:
2026-03-05 21:27:11 +08:00
commit 130de0fd5d
140 changed files with 21972 additions and 0 deletions

View File

@@ -0,0 +1,386 @@
---
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
<?php
declare(strict_types=1);
namespace Modules\{ModuleName};
class ConfigProvider
{
public function __invoke(): array
{
return [
'dependencies' => [
// 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
<?php
declare(strict_types=1);
namespace Modules\{ModuleName}\Http\Controller\Api;
use App\Controller\AbstractController;
use App\Support\ResponseTrait;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Modules\{ModuleName}\Service\{ModuleName}Service;
use Psr\Http\Message\ResponseInterface;
#[Controller(prefix: '/api/{module-kebab}')]
class {ModuleName}Controller extends AbstractController
{
use ResponseTrait;
#[Inject]
protected {ModuleName}Service ${moduleName}Service;
#[GetMapping(path: '')]
public function index(): ResponseInterface
{
return $this->success([]);
}
}
```
**管理端 API Controller**(放在 `Http/Controller/Admin/`
```php
<?php
declare(strict_types=1);
namespace Modules\{ModuleName}\Http\Controller\Admin;
use App\Controller\AbstractController;
use App\Middleware\JwtAuthMiddleware;
use App\Support\ResponseTrait;
use Hyperf\Di\Annotation\Inject;
use Hyperf\HttpServer\Annotation\Controller;
use Hyperf\HttpServer\Annotation\GetMapping;
use Hyperf\HttpServer\Annotation\Middleware;
use Modules\{ModuleName}\Service\{ModuleName}Service;
use Psr\Http\Message\ResponseInterface;
#[Controller(prefix: '/admin/{module-kebab}')]
#[Middleware(JwtAuthMiddleware::class)]
class {ModuleName}Controller extends AbstractController
{
use ResponseTrait;
#[Inject]
protected {ModuleName}Service ${moduleName}Service;
#[GetMapping(path: '')]
public function index(): ResponseInterface
{
return $this->success([]);
}
}
```
**关键区别**
- `Api/` 下:前缀 `/api/`,命名空间含 `\Api\`
- `Admin/` 下:前缀 `/admin/`,命名空间含 `\Admin\`,自动加 `JwtAuthMiddleware`
- **两者类名相同**(均为 `{Name}Controller`),由命名空间区分,无需加接口类型前缀
### 7. 生成 Request 模板
**用户端 Request**(放在 `Http/Request/Api/`
```php
<?php
declare(strict_types=1);
namespace Modules\{ModuleName}\Http\Request\Api;
use Hyperf\Validation\Request\FormRequest;
class {Name}Request extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
// 'field' => 'required|string|max:255',
];
}
public function messages(): array
{
return [];
}
}
```
**管理端 Request**(放在 `Http/Request/Admin/`
```php
<?php
declare(strict_types=1);
namespace Modules\{ModuleName}\Http\Request\Admin;
use Hyperf\Validation\Request\FormRequest;
class {Name}Request extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
// 'field' => '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