Files
vibe_coding/.cursor/skills/module-scaffold/SKILL.md
2026-03-05 21:27:11 +08:00

13 KiB
Raw Blame History

name, version, description, requires
name version description requires
module-scaffold 2.1.0 生成 Hyperf 模块化业务模块脚手架ConfigProvider/Controller/Service/Model。当需要新建业务模块、创建 module、添加模块化功能时使用。基于 ModuleLoader 自动发现 + ConfigProvider 机制,无需修改 composer.json。
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.phpvendor/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.jsonrequire

执行流程

1. 确认模块规格

字段 必填 默认值 说明
模块名称 PascalCaseOrderUserCenter
模块描述 推断 一句话说明模块职责
接口类型 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

{
    "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.jsonrequire 中声明,wikimedia/composer-merge-plugin 会在下次 composer update 时合并到主项目。

5. 生成 ConfigProvider.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

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

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

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

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 操作,直接验证:

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