study-api-v2/docs/CRUD代码生成模板.md

534 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Laravel CRUD 代码生成模板(优化版)
## 架构说明
### 分层架构
- **BaseModel.php**提供通用的权限控制tenant_id 自动过滤)、软删除、时间戳等基础功能
- **BaseService.php**:提供标准的 CRUD 操作,统一事务处理和异常处理
- **BaseController.php**提供统一的响应格式Success、SuccessPage、Field和参数获取方法
- **Controllers**:只负责参数验证和调用服务层,无需关心权限控制和异常处理
### 权限控制机制
- **查询时**BaseModel 的全局作用域自动过滤当前用户的 tenant_id 数据
- **创建时**BaseModel 的 creating 钩子自动设置当前用户的 tenant_id
- **更新/删除时**BaseService 在操作前验证记录的 tenant_id 权限
### 目录结构规范
```
app/
├── Models/
│ └── [模块名]/
│ └── [表名Model].php
├── Services/
│ └── [模块名]/
│ └── [表名Service].php
├── Http/
│ ├── Controllers/
│ │ └── Admin/
│ │ └── [模块名]/
│ │ └── [表名Controller].php
│ └── Requests/
│ └── Admin/
│ └── [模块名]/
│ └── [表名Request].php
└── routes/
└── admin/
└── [模块名]_route.php
```
### 模型命名规范
- **模型名必须与数据库表名保持一致的大驼峰格式**
- 例如:`system_users` 表 → `SystemUsers` 模型
- 例如:`system_role` 表 → `SystemRole` 模型
- 例如:`user_profile` 表 → `UserProfile` 模型
- **不要使用简化名称**,严格按照表名转换大驼峰
## 模板文件
### 1. 模型文件模板
**文件路径**`app/Models/[模块名]/[表名].php`
**字段类型注释说明**
- `int` - 整数字段不可为null
- `int|null` - 整数字段可为null
- `string` - 字符串字段不可为null
- `string|null` - 字符串字段可为null
- `float` - 浮点数字段不可为null
- `float|null` - 浮点数字段可为null
- `bool` - 布尔字段不可为null
- `bool|null` - 布尔字段可为null
- `\Carbon\Carbon` - 日期时间字段不可为null
- `\Carbon\Carbon|null` - 日期时间字段可为null
- `array` - 数组字段通过JSON存储
- `array|null` - 数组字段通过JSON存储可为null
**注意**根据数据库字段定义中的DEFAULT和NULL约束来确定是否需要添加`|null`
### 系统字段配置说明
BaseModel提供了两个配置选项来控制系统字段的自动维护
1. **`$enableSystemFields`** - 控制是否自动维护系统字段
- `tenant_id` - 租户ID
- `creator` - 创建者
- `create_time` - 创建时间
- `updater` - 更新者
- `update_time` - 更新时间
- `deleted` - 删除标识
2. **`$enableTenantScope`** - 控制是否启用租户隔离查询
**使用建议**
- **主要业务表**如School、User、Product等启用这两个配置
- **关联表**如StudentClass、UserRole等保持默认关闭
- **日志表**:只启用系统字段,不启用租户隔离
- **配置表**:根据实际情况决定
```php
<?php
namespace App\Models\[模块名];
use App\Models\BaseModel;
/**
* [中文名称]模型
* @package App\Models\[模块名]
* @property int $id 主键ID
* @property string $name 名称
* @property string $code 编码
* @property int $status 状态
* @property int $sort_order 排序
* @property string $remark 备注
* @property \Carbon\Carbon $created_at 创建时间
* @property \Carbon\Carbon $updated_at 更新时间
* @property \Carbon\Carbon|null $deleted_at 删除时间
* @property int $tenant_id 租户ID
*/
class [表名] extends BaseModel
{
protected $table = '[数据库表名]';
/**
* 启用系统字段自动维护
* 包括tenant_id、creator、create_time、updater、update_time、deleted
* 默认关闭主要业务表可以设置为true
*/
protected $enableSystemFields = false;
/**
* 启用租户隔离
* 默认关闭需要租户隔离的表可以设置为true
*/
protected $enableTenantScope = false;
protected $fillable = [
'[字段1]',
'[字段2]',
// ... 其他可填充字段
];
protected $casts = [
'created_at' => 'datetime',
'updated_at' => 'datetime',
];
// 如果有特殊的查询作用域,可以添加
// public function scopeActive($query)
// {
// return $query->where('status', 1);
// }
// 如果有关联关系,可以添加
// public function relatedModel()
// {
// return $this->belongsTo(RelatedModel::class);
// }
}
```
### 2. 服务文件模板
**文件路径**`app/Services/[模块名]/[表名Service].php`
```php
<?php
namespace App\Services\[模块名];
use App\Models\[模块名]\[表名];
use App\Services\BaseService;
use Illuminate\Pagination\LengthAwarePaginator;
/**
* [中文名称]服务类
*/
class [表名Service] extends BaseService
{
protected string $modelClass = [表名]::class;
/**
* 获取[中文名称]列表
*/
public function getList(array $params): LengthAwarePaginator
{
$query = [表名]::query();
// 搜索条件
if (!empty($params['keyword'])) {
$query->where(function ($q) use ($params) {
$q->where('name', 'like', '%' . $params['keyword'] . '%')
->orWhere('code', 'like', '%' . $params['keyword'] . '%');
});
}
// 状态筛选
if (isset($params['status'])) {
$query->where('status', $params['status']);
}
// 排序
$query->orderBy('sort_order', 'asc')
->orderBy('id', 'desc');
return $query->paginate($params['page_size'] ?? 15);
}
/**
* 获取简单列表(用于下拉选择等)
*/
public function getSimpleList(): array
{
return [表名]::select('id', 'name')
->where('status', 1)
->orderBy('sort_order', 'asc')
->get()
->toArray();
}
// 如果有特殊业务逻辑,可以重写父类方法
// protected function beforeCreate(array &$data): void
// {
// // 创建前的特殊处理
// }
// protected function afterCreate($model, array $data): void
// {
// // 创建后的特殊处理
// }
}
```
### 3. 控制器文件模板
**文件路径**`app/Http/Controllers/Admin/[模块名]/[表名Controller].php`
```php
<?php
namespace App\Http\Controllers\Admin\[模块名];
use App\Http\Controllers\BaseController;
use App\Http\Requests\Admin\[模块名]\[表名Request];
use App\Services\[模块名]\[表名Service];
use Illuminate\Http\JsonResponse;
/**
* [中文名称]控制器
*/
class [表名Controller] extends BaseController
{
public function __construct(
private [表名Service] $[表名变量]Service
) {}
/**
* 获取[中文名称]列表
*/
public function list([表名Request] $request): JsonResponse
{
$params = $request->validated();
$result = $this->[表名变量]Service->getList($params);
return $this->SuccessPage($result->items(), $result->total());
}
/**
* 获取简单列表
*/
public function simpleList(): JsonResponse
{
$result = $this->[表名变量]Service->getSimpleList();
return $this->Success($result);
}
/**
* 获取[中文名称]详情
*/
public function detail([表名Request] $request): JsonResponse
{
$params = $request->validated();
$result = $this->[表名变量]Service->detail($params['id']);
return $this->Success($result);
}
/**
* 创建[中文名称]
*/
public function create([表名Request] $request): JsonResponse
{
$data = $request->validated();
$result = $this->[表名变量]Service->create($data);
return $this->Success($result);
}
/**
* 更新[中文名称]
*/
public function update([表名Request] $request): JsonResponse
{
$params = $request->validated();
$result = $this->[表名变量]Service->update($params['id'], $params);
return $this->Success($result);
}
/**
* 删除[中文名称]
*/
public function delete([表名Request] $request): JsonResponse
{
$params = $request->validated();
$this->[表名变量]Service->delete($params['id']);
return $this->Success();
}
/**
* 批量删除[中文名称]
*/
public function batchDelete([表名Request] $request): JsonResponse
{
$params = $request->validated();
$this->[表名变量]Service->batchDelete($params['ids']);
return $this->Success();
}
}
```
### 4. 验证文件模板
**文件路径**`app/Http/Requests/Admin/[模块名]/[表名Request].php`
```php
<?php
namespace App\Http\Requests\Admin\[模块名];
use App\Http\Requests\BaseRequest;
/**
* [中文名称]请求验证
*/
class [表名Request] extends BaseRequest
{
/**
* 获取验证规则
*/
public function rules(): array
{
$action = $this->route()->getActionMethod();
return match($action) {
'list' => $this->listRules(),
'detail' => $this->detailRules(),
'create' => $this->createRules(),
'update' => $this->updateRules(),
'delete' => $this->deleteRules(),
'batchDelete' => $this->batchDeleteRules(),
'simpleList' => [],
default => []
};
}
/**
* 列表查询验证规则
*/
private function listRules(): array
{
return array_merge($this->getPaginationRules(), [
'keyword' => ['sometimes', 'string', 'max:50'],
'status' => ['sometimes', 'integer', 'in:0,1'],
]);
}
/**
* 详情查询验证规则
*/
private function detailRules(): array
{
return [
'id' => ['required', 'integer', 'exists:[数据库表名],id'],
];
}
/**
* 创建验证规则
*/
private function createRules(): array
{
return [
'name' => ['required', 'string', 'max:100'],
'code' => ['required', 'string', 'max:50', 'unique:[数据库表名],code'],
'status' => ['sometimes', 'integer', 'in:0,1'],
'sort_order' => ['sometimes', 'integer', 'min:0'],
'remark' => ['sometimes', 'string', 'max:200'],
];
}
/**
* 更新验证规则
*/
private function updateRules(): array
{
return [
'id' => ['required', 'integer', 'exists:[数据库表名],id'],
'name' => ['required', 'string', 'max:100'],
'code' => ['required', 'string', 'max:50', 'unique:[数据库表名],code,' . $this->input('id')],
'status' => ['sometimes', 'integer', 'in:0,1'],
'sort_order' => ['sometimes', 'integer', 'min:0'],
'remark' => ['sometimes', 'string', 'max:200'],
];
}
/**
* 删除验证规则
*/
private function deleteRules(): array
{
return [
'id' => ['required', 'integer', 'exists:[数据库表名],id'],
];
}
/**
* 批量删除验证规则
*/
private function batchDeleteRules(): array
{
return [
'ids' => ['required', 'array', 'min:1'],
'ids.*' => ['integer', 'exists:[数据库表名],id'],
];
}
/**
* 获取验证错误消息
*/
public function messages(): array
{
return [
'name.required' => '[中文名称]名称不能为空',
'name.max' => '[中文名称]名称不能超过100个字符',
'code.required' => '[中文名称]编码不能为空',
'code.unique' => '[中文名称]编码已存在',
'status.in' => '[中文名称]状态值无效',
'ids.required' => '请选择要删除的[中文名称]',
'ids.min' => '至少选择一条记录进行删除',
];
}
}
```
### 5. 路由文件模板
**文件路径**`routes/admin/[模块名]_route.php`
```php
<?php
use Illuminate\Support\Facades\Route;
/** -------------------------- [中文名称] ----------------------- */
Route::middleware("admin.auth")->group(function () {
// 获取[中文名称]详情
Route::match(['get', 'post'], "[路由前缀]/detail", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'detail']);
// 创建[中文名称]
Route::match(['get', 'post'], "[路由前缀]/create", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'create']);
// 更新[中文名称]
Route::match(['put', 'post'], "[路由前缀]/update", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'update']);
// 删除[中文名称]
Route::match(['delete', 'post'], "[路由前缀]/delete", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'delete']);
// 获取[中文名称]列表
Route::match(['get', 'post'], "[路由前缀]/list", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'list']);
// 获取简单列表
Route::match(['get', 'post'], "[路由前缀]/simple/list", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'simpleList']);
// 批量删除[中文名称]
Route::match(['delete', 'post'], "[路由前缀]/batch/delete", [App\Http\Controllers\Admin\[模块名]\[表名Controller]::class, 'batchDelete']);
});
```
## 使用示例
假设我们要为`school_class`表生成 CRUD 代码:
### 替换变量说明
- `[模块名]``Schools`
- `[表名]``SchoolClass`
- `[表名变量]``schoolClass`
- `[数据库表名]``school_class`
- `[中文名称]``班级`
- `[路由前缀]``school/class`
### 生成的文件结构
```
app/
├── Models/Schools/SchoolClass.php
├── Services/Schools/SchoolClassService.php
├── Http/
│ ├── Controllers/Admin/Schools/SchoolClassController.php
│ └── Requests/Admin/Schools/SchoolClassRequest.php
└── routes/admin/schools_route.php
```
### 控制器方法命名规范
- `list()` - 获取列表(替代 index
- `detail()` - 获取详情(替代 show
- `create()` - 创建(替代 store
- `update()` - 更新
- `delete()` - 删除(替代 destroy
- `batchDelete()` - 批量删除
- `simpleList()` - 获取简单列表
### 验证规则命名规范
验证方法根据控制器方法名自动匹配:
- `listRules()` - 列表查询验证
- `detailRules()` - 详情查询验证
- `createRules()` - 创建验证
- `updateRules()` - 更新验证
- `deleteRules()` - 删除验证
- `batchDeleteRules()` - 批量删除验证
## 核心优势
1. **代码量减少 60%以上**:通过 BaseModel、BaseService 提供通用功能
2. **权限控制自动化**tenant_id 完全由框架层自动处理
3. **异常处理统一化**:控制器无需 try-catch全局异常处理器统一处理
4. **命名更加直观**:使用功能性命名而非传统 RESTful 命名
5. **开发效率极高**:新模块只需实现特殊业务逻辑
6. **维护成本降低**:统一的代码结构和规范