数据仓库
概述
数据仓库(Repository)层是 XinAdmin 后端架构中负责数据访问的重要组成部分,它位于服务层(Service)和模型层(Model)之间。数据仓库的主要职责包括:
- 数据访问抽象:封装底层数据库操作,提供统一的访问接口
- 业务逻辑隔离:将数据操作逻辑与业务逻辑分离
- 查询构建:提供灵活的查询条件构建机制
- 验证处理:统一的数据验证和错误处理
- 模型关系管理:处理模型间的关联关系
XinAdmin 的数据仓库遵循 Repository 模式,所有仓库类都继承自 BaseRepository 并实现 RepositoryInterface,确保了统一的接口和一致的行为。
BaseRepository
BaseRepository 是所有仓库类的基类,提供了一套完整的通用方法来简化数据操作。它实现了 RepositoryInterface 接口,并提供了丰富的功能支持。
CRUD 方法
BaseRepository 提供了标准的 CRUD(创建、读取、更新、删除)操作方法:
-
创建(Create)
- 方法:
create(array $data): bool
- 功能:新增数据记录
- 流程:数据验证 → 创建记录 → 返回结果
- 示例:
public function create(array $data): bool
{
$data = $this->validation($data); // 数据验证
if(empty($data)) {
throw new RepositoryException('Validation failed: empty data');
}
$model = $this->model()->create($data); // 创建记录
return !!$model; // 返回布尔结果
}
-
读取(Read)
- 单条查询:
find(int $id): array
- 列表查询:
list(array $params): array
- 功能:根据ID获取单条记录或根据条件获取多条记录
- 示例:
public function find(int $id): array
{
$model = $this->model()->find($id);
if (empty($model)) {
throw new RepositoryException("Model not found");
}
return $model->toArray();
}
-
更新(Update)
- 方法:
update(int $id, array $data): bool
- 功能:更新指定ID的记录
- 流程:数据验证 → 查找记录 → 更新 → 返回结果
- 示例:
public function update(int $id, array $data): bool
{
$validated = $this->validation($data); // 数据验证
$model = $this->model()->find($id); // 查找记录
if (empty($model)) {
throw new RepositoryException('Model not found');
}
return $model->update($validated); // 更新记录
}
-
删除(Delete)
- 方法:
delete(int $id): bool
- 功能:删除指定ID的记录
- 示例:
public function delete(int $id): bool
{
$model = $this->model()->find($id);
if (empty($model)) {
throw new RepositoryException('Model not found');
}
return $model->delete(); // 删除记录
}
查询方法
BaseRepository 提供了强大的查询构建功能,支持多种查询方式:
-
基础列表查询:
public function list(array $params): array
{
$pageSize = $params['pageSize'] ?? 10; // 默认每页10条
$query = $this->model();
return $this->buildSearch($params, $query) // 构建查询条件
->paginate($pageSize) // 分页
->toArray();
}
-
条件查询构建:
- 支持多种比较操作符(=, <>, <, >, <=, >=)
- 支持模糊查询(like, afterLike, beforeLike)
- 支持日期查询(date, betweenDate)
- 支持快速搜索(任意字段匹配)
-
验证方法:
validation(array $data):根据规则验证数据
rules():定义验证规则
messages():定义验证错误消息
关联查询
数据仓库支持模型间的关联查询,可以在子类中通过模型关系实现复杂的数据检索。例如,在用户仓库中可以关联角色信息:
// 在 SysUserRepository 中
$model = $this->model()->with('roles')->find($id);
// 或者在查询时添加关联
public function listWithRoles(array $params): array
{
$pageSize = $params['pageSize'] ?? 10;
$query = $this->model()->with('roles');
return $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
}
RepositoryInterface
RepositoryInterface 定义了数据仓库的标准接口,确保所有仓库类具有一致的方法签名。接口包含以下方法:
find(int $id): array - 根据ID查找单条记录
list(array $params): array - 列表查询
create(array $data): bool - 创建记录
update(int $id, array $data): bool - 更新记录
delete(int $id): bool - 删除记录
所有仓库类都必须实现这些方法,保证了统一的 API 接口。
创建仓库
创建新的数据仓库需要遵循以下步骤:
-
确定仓库名称:根据业务实体命名,如用户仓库命名为 SysUserRepository
-
创建仓库文件:仓库文件应放置在 app/Repositories/ 目录下,对于系统相关仓库则放在 app/Repositories/Sys/ 目录
-
继承 BaseRepository:新仓库类必须继承 BaseRepository
<?php
namespace App\Repositories\Sys;
use App\Repositories\BaseRepository;
use App\Models\Sys\YourModel;
use Illuminate\Database\Eloquent\Builder;
class YourRepository extends BaseRepository
{
// 仓库实现
}
-
实现模型方法:必须实现 model() 抽象方法,返回对应的查询构建器
protected function model(): Builder
{
return YourModel::query();
}
-
配置搜索字段:设置 $searchField 和 $quickSearchField 属性
protected array $searchField = [
'id' => '=',
'name' => 'like',
'status' => '=',
'created_at' => 'date',
];
protected array $quickSearchField = ['name', 'description', 'id'];
-
定义验证规则:根据需要重写 rules() 和 messages() 方法
protected function rules(): array
{
return [
'name' => 'required|unique:your_table,name',
'status' => 'required|in:0,1',
];
}
protected function messages(): array
{
return [
'name.required' => '名称不能为空',
'name.unique' => '名称已存在',
];
}
-
自定义业务方法:根据业务需求添加特定的数据操作方法
public function findByStatus(int $status): array
{
return $this->model()
->where('status', $status)
->get()
->toArray();
}
查询构建
数据仓库提供了灵活的查询构建机制,支持多种查询方式和参数处理。
条件查询
条件查询支持以下操作符:
=:精确匹配
<>:不等于
<, >:小于、大于
<=, >=:小于等于、大于等于
like:模糊匹配(前后包含)
afterLike:后缀匹配
beforeLike:前缀匹配
date:日期匹配
betweenDate:日期范围匹配
示例配置:
protected array $searchField = [
'id' => '=',
'name' => 'like',
'status' => '=',
'created_at' => 'betweenDate',
];
排序
支持动态排序功能,通过 sorter 参数控制:
// 参数示例
$params = [
'sorter' => '{"name":"ascend"}' // 或者 ['name' => 'ascend']
];
// 排序处理逻辑
if (isset($params['sorter']) && $params['sorter']) {
if(is_array($params['sorter'])) {
$sorter = $params['sorter'];
} else {
$sorter = json_decode($params['sorter'], true);
}
if (count($sorter) > 0) {
$column = array_keys($sorter)[0];
$direction = $sorter[$column] == 'ascend' ? 'asc' : 'desc';
$model->orderBy($column, $direction);
}
}
分页
内置分页功能,默认每页10条记录,可通过 pageSize 参数调整:
public function list(array $params): array
{
$pageSize = $params['pageSize'] ?? 10;
$query = $this->model();
return $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
}
关联加载
支持通过 with() 方法进行关联加载,减少 N+1 查询问题:
// 在仓库中添加关联查询方法
public function listWithRelations(array $params): array
{
$pageSize = $params['pageSize'] ?? 10;
$query = $this->model()->with(['relation1', 'relation2']);
return $this->buildSearch($params, $query)
->paginate($pageSize)
->toArray();
}
最佳实践
-
统一命名:仓库类名应与对应模型保持一致,如 UserModel 对应 UserRepository
-
职责分离:仓库层应专注于数据访问逻辑,不应包含业务逻辑
-
验证前置:所有数据操作前应进行适当的验证
-
异常处理:使用 RepositoryException 进行错误处理
-
资源清理:确保及时释放数据库连接等资源
-
性能优化:合理使用索引、分页和关联查询,避免大数据量查询
-
安全考虑:防止 SQL 注入,验证所有输入参数
-
代码复用:充分利用 BaseRepository 提供的通用方法,避免重复造轮子
-
文档注释:为公共方法添加详细的 PHPDoc 注释
-
测试覆盖:为仓库方法编写单元测试,确保数据操作的正确性
遵循这些最佳实践可以确保数据仓库层的健壮性、可维护性和高性能。