SaiAdmin 分层架构使用指南
SaiAdmin 分层架构使用指南
本文档介绍 SaiAdmin 框架的控制器、逻辑层、模型层、验证器的使用方法和开发规范。
📖 目录
架构概述
SaiAdmin 采用 MVC + Logic 分层架构:
请求 → 控制器(Controller) → 逻辑层(Logic) → 模型层(Model) → 数据库
↓
验证器(Validate)| 层级 | 职责 |
|---|---|
| Controller | 接收请求、参数校验、调用 Logic、返回响应 |
| Logic | 业务逻辑处理、数据组装、调用 Model |
| Model | 数据库操作、数据映射、搜索器定义 |
| Validate | 数据验证规则、场景定义、错误消息 |
控制器 (Controller)
继承关系
OpenController # 开放控制器,无需登录
↓
BaseController # 基础控制器,需要登录
↓
YourController # 业务控制器基类属性和方法
// BaseController 属性
protected $adminInfo; // 当前登录用户信息
protected int $adminId; // 当前登录用户 ID
protected string $adminName;// 当前登录用户名
protected $logic; // 逻辑层实例
protected $validate; // 验证器实例
// OpenController 方法
public function success($data = [], $msg = 'success'); // 成功响应
public function fail($msg = 'fail'); // 失败响应
// BaseController 方法
protected function validate(string $scene, $data); // 调用验证器控制器模板
<?php
namespace plugin\your_plugin\app\controller;
use plugin\saiadmin\basic\BaseController;
use plugin\your_plugin\app\logic\YourLogic;
use plugin\your_plugin\app\validate\YourValidate;
use plugin\saiadmin\service\Permission;
use support\Request;
use support\Response;
class YourController extends BaseController
{
public function __construct()
{
// 注入逻辑层和验证器
$this->logic = new YourLogic();
$this->validate = new YourValidate();
parent::__construct();
}
/**
* 数据列表
*/
#[Permission('数据列表', 'your:module:index')]
public function index(Request $request): Response
{
// 获取搜索参数
$where = $request->more([
['name', ''],
['status', ''],
]);
// 搜索并分页
$query = $this->logic->search($where);
$data = $this->logic->getList($query);
return $this->success($data);
}
/**
* 读取数据
*/
#[Permission('数据读取', 'your:module:read')]
public function read(Request $request): Response
{
$id = $request->input('id');
$model = $this->logic->read($id);
$data = is_array($model) ? $model : $model->toArray();
return $this->success($data);
}
/**
* 保存数据
*/
#[Permission('数据添加', 'your:module:save')]
public function save(Request $request): Response
{
$data = $request->post();
// 调用验证器的 save 场景
$this->validate('save', $data);
$result = $this->logic->add($data);
return $result ? $this->success('添加成功') : $this->fail('添加失败');
}
/**
* 更新数据
*/
#[Permission('数据修改', 'your:module:update')]
public function update(Request $request): Response
{
$data = $request->post();
// 调用验证器的 update 场景
$this->validate('update', $data);
$result = $this->logic->edit($data['id'], $data);
return $result ? $this->success('修改成功') : $this->fail('修改失败');
}
/**
* 删除数据
*/
#[Permission('数据删除', 'your:module:destroy')]
public function destroy(Request $request): Response
{
$ids = $request->post('ids');
if (empty($ids)) {
return $this->fail('请选择要删除的数据');
}
$result = $this->logic->destroy($ids);
return $result ? $this->success('删除成功') : $this->fail('删除失败');
}
}权限注解
使用 #[Permission] 注解定义接口权限:
#[Permission('权限名称', '权限标识')]逻辑层 (Logic)
继承关系
AbstractLogic # 抽象逻辑层,定义接口
↓
BaseLogic (eloquent) # Eloquent ORM 实现
BaseLogic (think) # ThinkORM 实现
↓
YourLogic # 业务逻辑层LogicInterface 接口方法
| 方法 | 说明 |
|---|---|
init($user) | 初始化用户信息 |
add(array $data) | 添加数据 |
edit($id, array $data) | 修改数据 |
read($id) | 读取单条数据 |
destroy($ids) | 删除数据 |
search(array $where) | 搜索器搜索 |
getList($query) | 分页查询 |
getAll($query) | 获取全部数据 |
transaction(callable, bool) | 事务操作 |
基类属性
protected $model; // 模型实例
protected array $adminInfo; // 管理员信息
protected string $orderField; // 排序字段
protected string $orderType; // 排序方式 (ASC/DESC)逻辑层模板
<?php
namespace plugin\your_plugin\app\logic;
use plugin\your_plugin\app\model\YourModel;
use plugin\saiadmin\basic\think\BaseLogic; // 或 eloquent\BaseLogic
class YourLogic extends BaseLogic
{
public function __construct()
{
// 注入模型
$this->model = new YourModel();
// 可选:设置默认排序
$this->orderField = 'sort';
$this->orderType = 'ASC';
}
/**
* 自定义业务方法
*/
public function customMethod(array $params): array
{
// 使用搜索器
$query = $this->search($params);
// 可以链式调用模型方法
$query->field('id, name, status');
return $this->getAll($query);
}
/**
* 事务操作示例
*/
public function batchOperation(array $data): bool
{
return $this->transaction(function () use ($data) {
foreach ($data as $item) {
$this->add($item);
}
return true;
});
}
/**
* 重写 add 方法添加额外逻辑
*/
public function add(array $data): mixed
{
// 前置处理
$data['created_by'] = $this->adminInfo['id'] ?? 0;
// 调用父类方法
return parent::add($data);
}
}模型层 (Model)
继承关系
Model (webman) # Webman 基础模型
↓
BaseModel (eloquent) # Eloquent 模型基类
BaseModel (think) # ThinkORM 模型基类
↓
YourModel # 业务模型BaseModel 特性 (Eloquent)
| 特性 | 说明 |
|---|---|
| 软删除 | 使用 SoftDeletes trait |
| 时间字段 | create_time, update_time, delete_time |
| 自动填充 | 创建/更新时自动填充 created_by/updated_by |
| 搜索器 | 支持 searchXxxAttr 方法 |
模型模板
<?php
namespace plugin\your_plugin\app\model;
use plugin\saiadmin\basic\think\BaseModel; // 或 eloquent\BaseModel
/**
* 模型
*
* @property int $id 主键
* @property string $name 名称
* @property int $status 状态
* @property string $create_time 创建时间
* @property string $update_time 更新时间
*/
class YourModel extends BaseModel
{
/**
* 数据表主键
*/
protected $pk = 'id';
/**
* 数据表名称
*/
protected $table = 'sa_your_table';
/**
* 名称搜索器
* 支持模糊搜索
*/
public function searchNameAttr($query, $value)
{
$query->where('name', 'like', '%' . $value . '%');
}
/**
* 状态搜索器
* 精确匹配
*/
public function searchStatusAttr($query, $value)
{
$query->where('status', $value);
}
/**
* 时间范围搜索器
* 传入数组 [开始时间, 结束时间]
*/
public function searchCreateTimeAttr($query, $value)
{
$query->whereBetween('create_time', $value);
}
/**
* 关联查询示例
*/
public function category()
{
return $this->belongsTo(Category::class, 'category_id', 'id');
}
}搜索器命名规则
搜索器方法名格式:search{FieldName}Attr
| 字段名 | 搜索器方法名 |
|---|---|
name | searchNameAttr |
status | searchStatusAttr |
create_time | searchCreateTimeAttr |
category_id | searchCategoryIdAttr |
验证器 (Validate)
继承关系
think\Validate # ThinkPHP 验证器
↓
BaseValidate # 基础验证器
↓
YourValidate # 业务验证器验证器模板
<?php
namespace plugin\your_plugin\app\validate;
use plugin\saiadmin\basic\BaseValidate;
class YourValidate extends BaseValidate
{
/**
* 定义验证规则
*/
protected $rule = [
'name' => 'require|max:100',
'code' => 'require|alphaDash',
'status' => 'require|in:1,2',
'email' => 'email',
'mobile' => 'mobile',
];
/**
* 定义错误信息
*/
protected $message = [
'name.require' => '名称必须填写',
'name.max' => '名称最多100个字符',
'code.require' => '标识必须填写',
'code.alphaDash' => '标识只能是字母、数字和下划线',
'status.require' => '状态必须填写',
'status.in' => '状态值不正确',
'email.email' => '邮箱格式不正确',
'mobile.mobile' => '手机号格式不正确',
];
/**
* 定义验证场景
*/
protected $scene = [
// 保存场景
'save' => ['name', 'code', 'status'],
// 更新场景
'update' => ['name', 'code', 'status'],
];
}唯一性验证
使用 BaseValidate 提供的 unique 规则:
protected $rule = [
// 格式:unique:模型类,字段名,排除ID,主键名
'code' => 'require|unique:\\plugin\\your_plugin\\app\\model\\YourModel,code',
];更新时排除当前记录:
// 在控制器中验证前添加排除ID
$data['id'] = $request->input('id');
$this->validate('update', $data);常用验证规则
| 规则 | 说明 | 示例 |
|---|---|---|
require | 必填 | 'name' => 'require' |
max | 最大长度 | 'name' => 'max:100' |
min | 最小长度 | 'name' => 'min:2' |
in | 在某个范围内 | 'status' => 'in:1,2' |
email | 邮箱格式 | 'email' => 'email' |
mobile | 手机号格式 | 'mobile' => 'mobile' |
number | 数字 | 'sort' => 'number' |
integer | 整数 | 'id' => 'integer' |
alpha | 字母 | 'code' => 'alpha' |
alphaDash | 字母、数字、下划线 | 'code' => 'alphaDash' |
url | URL 格式 | 'link' => 'url' |
dateFormat | 日期格式 | 'date' => 'dateFormat:Y-m-d' |
完整示例
以下是一个完整的 CRUD 示例(以"文章"模块为例):
1. 创建模型
// plugin/your_plugin/app/model/Article.php
<?php
namespace plugin\your_plugin\app\model;
use plugin\saiadmin\basic\think\BaseModel;
class Article extends BaseModel
{
protected $pk = 'id';
protected $table = 'sa_article';
public function searchTitleAttr($query, $value)
{
$query->where('title', 'like', '%' . $value . '%');
}
public function searchCategoryIdAttr($query, $value)
{
$query->where('category_id', $value);
}
public function searchStatusAttr($query, $value)
{
$query->where('status', $value);
}
}2. 创建验证器
// plugin/your_plugin/app/validate/ArticleValidate.php
<?php
namespace plugin\your_plugin\app\validate;
use plugin\saiadmin\basic\BaseValidate;
class ArticleValidate extends BaseValidate
{
protected $rule = [
'title' => 'require|max:200',
'category_id' => 'require|integer',
'content' => 'require',
'status' => 'require|in:1,2',
];
protected $message = [
'title.require' => '文章标题必须填写',
'title.max' => '文章标题最多200个字符',
'category_id.require' => '分类必须选择',
'content.require' => '文章内容必须填写',
'status.require' => '状态必须选择',
];
protected $scene = [
'save' => ['title', 'category_id', 'content', 'status'],
'update' => ['title', 'category_id', 'content', 'status'],
];
}3. 创建逻辑层
// plugin/your_plugin/app/logic/ArticleLogic.php
<?php
namespace plugin\your_plugin\app\logic;
use plugin\your_plugin\app\model\Article;
use plugin\saiadmin\basic\think\BaseLogic;
class ArticleLogic extends BaseLogic
{
public function __construct()
{
$this->model = new Article();
$this->orderField = 'id';
$this->orderType = 'DESC';
}
/**
* 获取分类下的文章数量
*/
public function countByCategory(int $categoryId): int
{
return $this->model->where('category_id', $categoryId)->count();
}
}4. 创建控制器
// plugin/your_plugin/app/controller/ArticleController.php
<?php
namespace plugin\your_plugin\app\controller;
use plugin\saiadmin\basic\BaseController;
use plugin\your_plugin\app\logic\ArticleLogic;
use plugin\your_plugin\app\validate\ArticleValidate;
use plugin\saiadmin\service\Permission;
use support\Request;
use support\Response;
class ArticleController extends BaseController
{
public function __construct()
{
$this->logic = new ArticleLogic();
$this->validate = new ArticleValidate();
parent::__construct();
}
#[Permission('文章列表', 'article:index')]
public function index(Request $request): Response
{
$where = $request->more([
['title', ''],
['category_id', ''],
['status', ''],
]);
$query = $this->logic->search($where);
$data = $this->logic->getList($query);
return $this->success($data);
}
#[Permission('文章详情', 'article:read')]
public function read(Request $request): Response
{
$id = $request->input('id');
$data = $this->logic->read($id)->toArray();
return $this->success($data);
}
#[Permission('文章添加', 'article:save')]
public function save(Request $request): Response
{
$data = $request->post();
$this->validate('save', $data);
$result = $this->logic->add($data);
return $result ? $this->success('添加成功') : $this->fail('添加失败');
}
#[Permission('文章修改', 'article:update')]
public function update(Request $request): Response
{
$data = $request->post();
$this->validate('update', $data);
$result = $this->logic->edit($data['id'], $data);
return $result ? $this->success('修改成功') : $this->fail('修改失败');
}
#[Permission('文章删除', 'article:destroy')]
public function destroy(Request $request): Response
{
$ids = $request->post('ids');
if (empty($ids)) {
return $this->fail('请选择要删除的数据');
}
$result = $this->logic->destroy($ids);
return $result ? $this->success('删除成功') : $this->fail('删除失败');
}
}5. 注册路由
// plugin/your_plugin/config/route.php
Route::group('/api', function () {
fastRoute('article', \plugin\your_plugin\app\controller\ArticleController::class);
});