534 lines
15 KiB
Markdown
534 lines
15 KiB
Markdown
# 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. **维护成本降低**:统一的代码结构和规范
|