签入版本
This commit is contained in:
@@ -1,19 +1,19 @@
|
||||
# 10.5 代码生成引擎
|
||||
|
||||
:::tip 概述
|
||||
代码生成引擎基于模板文件,将表结构信息渲染为实际代码文件。渲染使用 PHP 原生 `include` + `extract` 机制,模板变量由 `GeneratorService::buildTemplateVars()` 统一构建。
|
||||
代码生成引擎基于模板文件,将表结构信息渲染为实际代码文件。渲染使用 PHP 原生 `include` + `extract` 机制,模板变量由 `GeneratorService::buildTemplateVars()` 统一构建,预览与生成的编排由 `GeneratorLogic` 负责。
|
||||
:::
|
||||
|
||||
## 生成文件清单
|
||||
|
||||
### 后端文件
|
||||
### 后端文件(4 个文件,输出路径见 `config/generator.php` 的 `backend_outputs`)
|
||||
|
||||
| 文件 | 模板 | 说明 |
|
||||
|------|------|------|
|
||||
| `app/controller/{Name}Controller.php` | controller.php.tpl | 控制器,含分页/列表/详情/增删改/批量删除/导入/导出 |
|
||||
| `app/logic/{Name}Logic.php` | logic.php.tpl | 业务逻辑,含属性配置、serializeMaps、导入导出方法 |
|
||||
| `app/model/{Name}.php` | model.php.tpl | 数据模型,含软删除、审计字段自动填充;树形结构额外生成 `children()` 自关联 |
|
||||
| `app/validate/{Name}Validate.php` | validate.php.tpl | 验证器,按字段分析自动生成验证规则(camelCase 字段名、require 规则、add/update 场景) |
|
||||
| `app/Http/Controllers/Api/{Name}Controller.php` | controller.php.tpl | 控制器,含分页/列表/详情/增删改/批量删除/导入/导出 |
|
||||
| `app/Services/{Name}Service.php` | service.php.tpl | 业务服务,含属性配置、serializeMaps、导入导出方法 |
|
||||
| `app/Models/{Name}.php` | model.php.tpl | 数据模型,含软删除(is_delete)、审计字段自动填充;树形结构额外生成 `children()` 自关联 |
|
||||
| `app/Http/Requests/{Name}Request.php` | request.php.tpl | FormRequest 验证器,按字段分析自动生成验证规则(camelCase 字段名、required 规则、add/update 场景) |
|
||||
|
||||
### 前端文件(ui/ 普通列表模板 — 6 个文件)
|
||||
|
||||
@@ -36,13 +36,13 @@
|
||||
| `ui/src/views/{app}/{name}/detail.vue` | detail.vue.tpl | 详情弹窗 |
|
||||
|
||||
:::info 模板选择
|
||||
表结构中包含 `parent_id` 或 `pid` 字段时自动使用 `ui2/` 树形模板,否则使用 `ui/` 普通列表模板。树形模板不生成 `columns.ts` 和 `querySchemas.ts`。
|
||||
表结构中包含 `parent_id` 或 `pid` 字段时自动切换为 `ui2/` 树形模板(`GeneratorService::buildTemplateVars()` 内检测,结果体现在 `is_tree` 变量),否则使用 `ui/` 普通列表模板。树形模板不生成 `columns.ts` 和 `querySchemas.ts`。
|
||||
:::
|
||||
|
||||
## GeneratorService 核心方法
|
||||
|
||||
```php
|
||||
// app/service/GeneratorService.php
|
||||
// app/Services/GeneratorService.php
|
||||
|
||||
/**
|
||||
* 获取可生成的表列表
|
||||
@@ -50,57 +50,46 @@
|
||||
* 读取当前数据库所有表,返回表名、注释、引擎、行数等信息。
|
||||
* 支持 MySQL / PostgreSQL / SQL Server / Oracle / SQLite。
|
||||
*/
|
||||
public function page(array $params): array { ... }
|
||||
public function getTableList(): array { ... }
|
||||
|
||||
/**
|
||||
* 解析单表结构
|
||||
*
|
||||
* 读取列信息、主键、索引与表注释,输出字段归一化结果。
|
||||
*/
|
||||
public function parseTableStructure(string $tableName): array { ... }
|
||||
|
||||
/**
|
||||
* 构建模板变量
|
||||
*
|
||||
* 解析表结构 → 字段分析 → 构建全部模板变量。
|
||||
* 是生成引擎的核心,决定模板中可用的所有变量。
|
||||
* 自动检测树形结构(parent_id / pid),切换 template_type 为 ui2。
|
||||
*/
|
||||
public function buildTemplateVars(string $tableName, string $moduleComment, string $templateType): array { ... }
|
||||
public function buildTemplateVars(string $tableName, string $moduleComment = '', string $templateType = 'ui'): array { ... }
|
||||
|
||||
/**
|
||||
* 渲染模板
|
||||
*
|
||||
* 使用 PHP extract + include 机制渲染 .tpl 文件。
|
||||
* 渲染前预检:禁止短标签 <?= 和 UTF-8 BOM 头。
|
||||
* 模板不存在或渲染抛错时,带模板文件名上下文重新抛出异常。
|
||||
*/
|
||||
public function renderTemplate(string $templatePath, array $vars): string { ... }
|
||||
|
||||
/**
|
||||
* 预览生成代码(不写入文件)
|
||||
*
|
||||
* 返回所有待生成文件的渲染结果,供前端预览。
|
||||
*/
|
||||
public function preview(array $params): array { ... }
|
||||
|
||||
/**
|
||||
* 生成代码(写入文件)
|
||||
*
|
||||
* 渲染模板 → 写入文件 → 创建菜单 → 创建字典 → 注册路由。
|
||||
*/
|
||||
public function generate(array $params): array { ... }
|
||||
|
||||
/**
|
||||
* 批量生成
|
||||
*
|
||||
* 遍历多张表,逐表调用 generate。
|
||||
*/
|
||||
public function batchGenerate(array $params): array { ... }
|
||||
|
||||
/**
|
||||
* 生成单个文件
|
||||
*
|
||||
* 检查文件是否存在(可跳过或覆盖)→ 创建目录 → 写入文件。
|
||||
* 已存在且未开启覆盖 → skipped;目录不存在自动创建(0755)。
|
||||
*/
|
||||
public function generateFile(string $path, string $content, bool $overwrite): array { ... }
|
||||
public function generateFile(string $path, string $content, bool $overwrite = false): array { ... }
|
||||
|
||||
/**
|
||||
* 创建菜单和权限节点
|
||||
*
|
||||
* 自动创建主菜单(type=0)和标准权限节点(type=1):
|
||||
* 在 GENERATOR_PARENT_MENU_ID 指定的父菜单下创建主菜单(type=0)
|
||||
* 和 9 个标准权限节点(type=1):
|
||||
* page / list / detail / add / update / delete / batchDelete / import / export。
|
||||
* path 已存在则跳过(幂等),排序值按父级 max(sort) + 5 递增。
|
||||
*/
|
||||
public function createMenu(string $moduleComment, string $moduleName): array { ... }
|
||||
|
||||
@@ -115,12 +104,40 @@ public function createDictData(string $moduleComment, string $moduleName, array
|
||||
/**
|
||||
* 注册模块路由
|
||||
*
|
||||
* 在 route/app.php 中自动插入标准 CRUD 路由组(含中间件)。
|
||||
* 在 routes/api.php 末尾的中间件组闭合 `});` 之前插入标准 CRUD 路由组。
|
||||
* 分组注释取表注释(为空时回退模块名),幂等以路由路径判断。
|
||||
* 树形结构不生成 page 路由。
|
||||
*/
|
||||
public function registerRoute(string $moduleName, bool $isTree): array { ... }
|
||||
public function registerRoute(string $moduleName, string $controllerName, bool $isTree = false, string $moduleComment = ''): array { ... }
|
||||
|
||||
/**
|
||||
* 获取生成的文件列表
|
||||
*
|
||||
* 返回后端与前端应生成的文件相对路径,供生成结果核对或展示。
|
||||
*/
|
||||
public function getGenerateFiles(string $moduleName, string $templateType = 'ui'): array { ... }
|
||||
```
|
||||
|
||||
## GeneratorLogic 编排方法
|
||||
|
||||
```php
|
||||
// app/Services/GeneratorLogic.php — 面向控制器的编排层
|
||||
|
||||
// 获取表列表(含分页参数处理)
|
||||
public function getTableList(array $params = []): array { ... }
|
||||
|
||||
// 预览生成代码(不写入文件):渲染全部模板,返回内容 + 是否已存在
|
||||
public function preview(array $params): array { ... }
|
||||
|
||||
// 生成代码(写入文件):写后端 → 写前端 → 创建菜单(可选)→ 创建字典 → 注册路由
|
||||
public function generate(array $params): array { ... }
|
||||
|
||||
// 批量生成:逐表调用 generate,单表失败不中断整体
|
||||
public function batchGenerate(array $params): array { ... }
|
||||
```
|
||||
|
||||
`generate()` 参数:`tableNames`(必填)、`templateType`(ui/ui2,可省略)、`generateMenu`(默认 true)、`overwrite`(默认 false,不覆盖已存在文件)。
|
||||
|
||||
## 字段分析流程
|
||||
|
||||
```text
|
||||
@@ -133,15 +150,16 @@ public function registerRoute(string $moduleName, bool $isTree): array { ... }
|
||||
▼
|
||||
属性分析(详见 10.4 表结构解析引擎)
|
||||
│
|
||||
├─ 图片字段 → 注释/字段名匹配 /图片|头像|logo|icon|image|avatar|photo/i 且类型为 varchar
|
||||
├─ 图片字段 → 注释/字段名匹配 /图片|封面|头像|logo|icon|image|avatar|photo/i 且类型为 varchar
|
||||
├─ 富文本 → 注释匹配 /内容|详情|正文/i 且类型为 text
|
||||
├─ 多行文本 → 注释匹配 /备注|说明|描述|介绍|简介/i 且类型为 varchar
|
||||
├─ 选项字段 → 注释中解析 "数字-文字" 格式(如 "1-启用 2-停用")
|
||||
├─ 选项字段 → 注释中解析 "数字-文字" 格式(如 "1-正常 2-停用")
|
||||
├─ 状态字段 → 字段名 status 且无选项时,自动补 0=正常 1=停用
|
||||
├─ 模糊搜索 → 字段名匹配 /名称|标题|name|title|username/i 且类型为 varchar
|
||||
├─ 唯一字段 → 字段名匹配 /编码|code|username|mobile|email/i
|
||||
├─ 外键字段 → 字段名以 _id 或 _ids 结尾
|
||||
└─ 排序字段 → 字段名为 sort
|
||||
├─ 模糊搜索 → 字段名匹配 /名称|标题|name|title|username|realname/i 且类型为 varchar
|
||||
├─ 唯一字段 → 字段名匹配 /编码|code|username|mobile|email|account/i
|
||||
├─ 排序字段 → 字段名为 sort(标记 has_sort)
|
||||
└─ 排除字段 → id / tenant_id / create_user / create_time / update_user / update_time / is_delete
|
||||
不进表单与列表
|
||||
▼
|
||||
serialize_maps 构建
|
||||
│ 有 choices 的字段自动生成映射:字段名 → "{模块名}_{字段名}"
|
||||
@@ -149,41 +167,47 @@ serialize_maps 构建
|
||||
▼
|
||||
输出分组字段列表
|
||||
│ $fields['all'] 全部字段
|
||||
│ $fields['list'] 列表展示字段
|
||||
│ $fields['form'] 表单字段
|
||||
│ $fields['list'] 列表展示字段(text 长文本默认不进列表)
|
||||
│ $fields['form'] 表单字段(全量生成规则,含 id → validate_rules / validate_rules_update)
|
||||
│ $fields['filter'] 筛选字段(含模糊搜索和精确匹配)
|
||||
│ $fields['file'] 文件/图片字段
|
||||
│ $fields['file'] 单文件/图片字段
|
||||
│ $fields['multi'] 多文件字段(逗号分隔的多条路径,如图集)
|
||||
│ $fields['content'] 富文本字段
|
||||
│ $fields['like'] 模糊搜索字段
|
||||
│ $fields['eq'] 精确匹配字段(含选项字段)
|
||||
│ $fields['unique'] 唯一字段
|
||||
│ $fields['serialize_maps'] 枚举映射(字段 → 字典编码)
|
||||
│ $fields['foreign_keys'] 外键字段
|
||||
│ $fields['serialize_maps'] 枚举映射(字段 → 字典编码)
|
||||
│ $fields['field_labels'] / casts / hidden 字段中文名 / 类型转换 / 敏感字段
|
||||
│ $fields['validate_rules'] / validate_rules_update / validate_messages / validate_fields FormRequest 规则
|
||||
```
|
||||
|
||||
## 渲染机制
|
||||
|
||||
```php
|
||||
// 渲染原理(简化)
|
||||
// 渲染原理(简化,见 GeneratorService::renderTemplate)
|
||||
public function renderTemplate(string $templatePath, array $vars): string
|
||||
{
|
||||
// 预检:禁止短标签和 BOM
|
||||
$tplContent = file_get_contents($templatePath);
|
||||
if (preg_match('/<\?=(?!.*<\?php echo)/s', $tplContent)) {
|
||||
throw new \Exception('模板包含短标签 <?= ,请改为 <?php echo');
|
||||
if (! file_exists($templatePath)) {
|
||||
throw new \Exception('模板文件不存在: '.$templatePath);
|
||||
}
|
||||
|
||||
extract($vars); // 将变量注入当前作用域
|
||||
ob_start(); // 开启输出缓冲
|
||||
include $templatePath; // 执行模板文件
|
||||
try {
|
||||
include $templatePath; // 执行模板文件
|
||||
} catch (\Throwable $e) {
|
||||
ob_end_clean(); // 丢弃半成品输出
|
||||
throw new \Exception('模板渲染失败 ['.basename($templatePath).'] '.$e->getMessage());
|
||||
}
|
||||
return ob_get_clean(); // 返回渲染结果
|
||||
}
|
||||
```
|
||||
|
||||
:::warning 模板编写规范
|
||||
- 必须使用 `<?php echo ?>` 输出变量,不能使用短标签 `<?= ?>`
|
||||
- 使用 `<?php echo ?>` 输出变量,与 `resources/templates/` 现有模板保持一致(现有模板均不含短标签)
|
||||
- 文件编码必须为 UTF-8 无 BOM
|
||||
- 控制结构(foreach/if)使用完整的 `<?php ?>` 标签
|
||||
- 模板渲染异常会带文件名抛出,便于定位是哪张模板出错
|
||||
:::
|
||||
|
||||
## 生成后自动操作
|
||||
@@ -192,10 +216,15 @@ public function renderTemplate(string $templatePath, array $vars): string
|
||||
|
||||
| 操作 | 说明 | 幂等性 |
|
||||
|------|------|--------|
|
||||
| 写入文件 | 生成 Controller / Logic / Model / Validate / API / Vue 文件 | 文件已存在则跳过 |
|
||||
| 创建菜单 | 在指定父菜单下创建主菜单和权限节点 | 路径已存在则跳过 |
|
||||
| 写入文件 | 生成 Controller / Service / Model / Request / API / Vue 文件 | 文件已存在则跳过(除非 `overwrite=true`) |
|
||||
| 创建菜单 | 在 `GENERATOR_PARENT_MENU_ID` 父菜单下创建主菜单和 9 个权限节点 | path 已存在则跳过 |
|
||||
| 创建字典 | 为带选项的字段自动创建字典和字典项 | 字典编码已存在则跳过 |
|
||||
| 注册路由 | 在 route/app.php 中插入 CRUD 路由组 | 路由组已存在则跳过 |
|
||||
| 注册路由 | 在 `routes/api.php` 插入 CRUD 路由组(分组注释取表注释,如 `// --- 案例演示 ---`) | 同模块路由已存在则跳过 |
|
||||
|
||||
:::warning 生成后需手动生效
|
||||
- 路由写入 `routes/api.php` 后,若生产环境执行过 `php artisan route:cache`,需重新执行 `php artisan route:cache`
|
||||
- 菜单与权限写入数据库后,需重新登录或刷新前端动态菜单才能看到新菜单
|
||||
:::
|
||||
|
||||
## 相关文档
|
||||
|
||||
|
||||
Reference in New Issue
Block a user