Merge branch 'develop'
This commit is contained in:
@@ -1,47 +1,51 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\traits;
|
||||
|
||||
use Illuminate\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
/**
|
||||
* 数据转换器 Trait
|
||||
* 用于将原始数据(如模型、集合、分页等)统一转换为数组格式,
|
||||
* 并支持字段级与结果级的灵活后置加工。
|
||||
*/
|
||||
trait DataTransformer
|
||||
{
|
||||
/**
|
||||
* 核心方法:对任意数据进行转换并返回数组
|
||||
* 核心转换方法
|
||||
*
|
||||
* @param mixed $rawData 原始数据,可为 Paginator / Model / Collection / array 等
|
||||
* @param callable|null $postProcessor 可选的后置处理回调,接受处理完的数组再返回新的数组
|
||||
* @param callable|null $fieldFormatter 可选的字段命名转换回调,如 snake_case
|
||||
* @param mixed $rawData 原始数据:Model、Collection、Paginator、数组等
|
||||
* @param array $opts 可选配置:
|
||||
* - 'fieldFormatter' => callable 字段名格式化回调,如 fn($f)=>snake_case($f)
|
||||
* - 'postFormatter' => callable 结果级加工回调,接收整个数组并返回
|
||||
*
|
||||
* @return array
|
||||
* @return array 转换并加工后的纯 PHP 数组
|
||||
*/
|
||||
protected function transformData(
|
||||
mixed $rawData,
|
||||
?callable $postProcessor = null,
|
||||
?callable $postFormatter = null,
|
||||
?callable $fieldFormatter = null
|
||||
): array {
|
||||
try {
|
||||
$fieldFormatter = $fieldFormatter ?: fn($field) => $field;
|
||||
|
||||
if ($rawData instanceof LengthAwarePaginator) {
|
||||
$formatted = $this->formatPaginated($rawData, $postProcessor, $fieldFormatter);
|
||||
$arr = $this->formatPaginated($rawData, $postFormatter, $fieldFormatter);
|
||||
} elseif ($rawData instanceof Model) {
|
||||
$formatted = $this->formatModel($rawData, $fieldFormatter);
|
||||
$arr = $this->formatModel($rawData, $fieldFormatter);
|
||||
} elseif ($rawData instanceof Collection) {
|
||||
$formatted = $this->formatCollection($rawData, $fieldFormatter);
|
||||
$arr = $this->formatCollection($rawData, $fieldFormatter);
|
||||
} elseif (is_array($rawData)) {
|
||||
$formatted = $this->formatArray($rawData, $fieldFormatter);
|
||||
$arr = $this->formatArray($rawData, $fieldFormatter);
|
||||
} else {
|
||||
$formatted = (array) $rawData;
|
||||
$arr = (array)$rawData;
|
||||
}
|
||||
|
||||
if (is_callable($postProcessor)) {
|
||||
$formatted = $postProcessor($formatted);
|
||||
if (is_callable($postFormatter)) {
|
||||
$arr = $postFormatter($arr);
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
return $arr;
|
||||
} catch (\Throwable $e) {
|
||||
return [
|
||||
'error' => true,
|
||||
@@ -52,84 +56,96 @@ trait DataTransformer
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化分页数据:将每条记录也进行 transformData 递归处理
|
||||
* 格式化分页数据:转换每条记录
|
||||
*
|
||||
* @param LengthAwarePaginator $paginator
|
||||
* @param callable|null $postProcessor
|
||||
* @param callable $fieldFormatter
|
||||
* @return array
|
||||
* @param LengthAwarePaginator $p
|
||||
* @param callable $fmt
|
||||
* @return array{records: array, total: int, current: int, size: int}
|
||||
*/
|
||||
protected function formatPaginated(
|
||||
LengthAwarePaginator $paginator,
|
||||
?callable $postProcessor,
|
||||
callable $fieldFormatter
|
||||
LengthAwarePaginator $p,
|
||||
?callable $postFormatter,
|
||||
callable $fmt
|
||||
): array {
|
||||
$list = $paginator->getCollection()->map(function ($item) use ($postProcessor, $fieldFormatter) {
|
||||
return $this->transformData($item, $postProcessor, $fieldFormatter);
|
||||
})->toArray();
|
||||
$records = $p->getCollection()
|
||||
->map(fn($item) => $this->transformData($item, $postFormatter, $fmt))
|
||||
->toArray();
|
||||
|
||||
return [
|
||||
'records' => $list,
|
||||
'total' => $paginator->total(),
|
||||
'current' => $paginator->currentPage(),
|
||||
'size' => $paginator->perPage()
|
||||
'records' => $records,
|
||||
'total' => $p->total(),
|
||||
'current' => $p->currentPage(),
|
||||
'size' => $p->perPage(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化 Eloquent 模型:递归嵌套关联
|
||||
* 格式化 Eloquent 模型:主表属性 + 关联递归
|
||||
*
|
||||
* @param Model $model
|
||||
* @param callable $fieldFormatter
|
||||
* @param callable $fmt
|
||||
* @return array
|
||||
*/
|
||||
protected function formatModel(Model $model, callable $fieldFormatter): array
|
||||
{
|
||||
$formatted = [];
|
||||
|
||||
// 主表字段
|
||||
protected function formatModel(
|
||||
Model $model,
|
||||
callable $fmt
|
||||
): array {
|
||||
$out = [];
|
||||
// 1) 主表字段
|
||||
foreach ($model->getAttributes() as $key => $value) {
|
||||
$formatted[$fieldFormatter($key)] = $value;
|
||||
$out[$fmt($key)] = $value;
|
||||
}
|
||||
|
||||
// 关联数据,递归嵌套
|
||||
foreach ($model->getRelations() as $relation => $relationData) {
|
||||
if ($relationData instanceof Model) {
|
||||
// 单个关联模型
|
||||
$formatted[$relation] = $this->formatModel($relationData, $fieldFormatter);
|
||||
} elseif ($relationData instanceof Collection) {
|
||||
// 关联集合
|
||||
$formatted[$relation] = $relationData
|
||||
->map(fn($item) => $this->transformData($item, null, $fieldFormatter))
|
||||
// 2) 关联递归
|
||||
foreach ($model->getRelations() as $rel => $relData) {
|
||||
if ($relData instanceof Model) {
|
||||
$out[$rel] = $this->formatModel($relData, $fmt);
|
||||
} elseif ($relData instanceof Collection) {
|
||||
$out[$rel] = $relData
|
||||
->map(fn($item) => $this->transformData($item, null, $fmt))
|
||||
->toArray();
|
||||
} else {
|
||||
$out[$rel] = $relData;
|
||||
}
|
||||
}
|
||||
|
||||
return $formatted;
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化集合
|
||||
* 格式化集合数据:对每个元素递归调用 transformData
|
||||
*
|
||||
* @param Collection $collection
|
||||
* @param callable $fieldFormatter
|
||||
* @param Collection $c
|
||||
* @param callable $fmt
|
||||
* @return array
|
||||
*/
|
||||
protected function formatCollection(Collection $collection, callable $fieldFormatter): array
|
||||
{
|
||||
return $collection->map(fn($item) => $this->transformData($item, null, $fieldFormatter))
|
||||
->toArray();
|
||||
protected function formatCollection(
|
||||
Collection $c,
|
||||
callable $fmt
|
||||
): array {
|
||||
return $c
|
||||
->map(fn($item) => $this->transformData($item, null, $fmt))
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化普通数组
|
||||
* 格式化普通数组:递归处理可能出现的模型或集合
|
||||
*
|
||||
* @param array $array
|
||||
* @param callable $fieldFormatter
|
||||
* @param array $arr
|
||||
* @param callable $fmt
|
||||
* @return array
|
||||
*/
|
||||
protected function formatArray(array $array, callable $fieldFormatter): array
|
||||
{
|
||||
return array_map(fn($item) => $this->transformData($item, null, $fieldFormatter), $array);
|
||||
protected function formatArray(
|
||||
array $arr,
|
||||
callable $fmt
|
||||
): array {
|
||||
return array_map(function($item) use ($fmt) {
|
||||
if (is_array($item)
|
||||
|| $item instanceof Model
|
||||
|| $item instanceof Collection
|
||||
|| $item instanceof LengthAwarePaginator
|
||||
) {
|
||||
return $this->transformData($item, null, $fmt);
|
||||
}
|
||||
return $item;
|
||||
}, $arr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
namespace app\common\traits;
|
||||
|
||||
use support\Request;
|
||||
|
||||
trait FormatKvTrait
|
||||
{
|
||||
/**
|
||||
* 主入口:一行把前端扁平化参数变成完整的查询配置
|
||||
*
|
||||
* @param Request $request
|
||||
* @param string $modelClass Eloquent 模型类名
|
||||
* @return array{
|
||||
* model: string,
|
||||
* where: array,
|
||||
* order: array<string,string>,
|
||||
* fields: string[],
|
||||
* include: string[]
|
||||
* }
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $modelClass): array
|
||||
{
|
||||
$all = $request->all();
|
||||
|
||||
return [
|
||||
'model' => $modelClass,
|
||||
'where' => $this->parseFilters($all),
|
||||
'order' => $this->parseSort($all['sort'] ?? ''),
|
||||
'fields' => $this->parseCsv($all['fields'] ?? ''),
|
||||
'include' => $this->parseCsv($all['include'] ?? ''),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* 把除 sort/fields/include/page/limit 以外的所有参数
|
||||
* 智能转换为 where 条件
|
||||
*
|
||||
* 支持:
|
||||
* - 等值:foo=bar
|
||||
* - NOT:foo=!bar 或 foo=!bar1,bar2
|
||||
* - 范围:foo=2025-07-01,2025-07-15 → between
|
||||
* - 列表:foo=a,b,c → in
|
||||
* - NULL:foo=null
|
||||
* - NOT NULL:foo=!null
|
||||
* - 通配符:foo=xia* → like 'xia%'
|
||||
*
|
||||
* 关联字段直接写 relation.field=xxx
|
||||
*/
|
||||
protected function parseFilters(array $params): array
|
||||
{
|
||||
$where = [];
|
||||
$reserved = ['sort','fields','include','page','limit'];
|
||||
|
||||
foreach ($params as $key => $val) {
|
||||
if (in_array($key, $reserved, true)) {
|
||||
continue;
|
||||
}
|
||||
// NULL / NOT NULL
|
||||
if ($val === 'null') {
|
||||
$where[$key] = ['is null'];
|
||||
continue;
|
||||
}
|
||||
if ($val === '!null') {
|
||||
$where[$key] = ['is not null'];
|
||||
continue;
|
||||
}
|
||||
// NOT equal or NOT IN
|
||||
if (str_starts_with($val, '!')) {
|
||||
$v = substr($val, 1);
|
||||
if (str_contains($v, ',')) {
|
||||
$list = array_map('trim', explode(',', $v));
|
||||
$where[$key] = ['not in', $list];
|
||||
} else {
|
||||
$where[$key] = ['<>', $this->cast($v)];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// BETWEEN or IN
|
||||
if (str_contains($val, ',')) {
|
||||
$parts = array_map('trim', explode(',', $val));
|
||||
if (count($parts) === 2 && $this->isRangeValue($parts[0], $parts[1])) {
|
||||
$where[$key] = ['between', $parts];
|
||||
} else {
|
||||
$where[$key] = ['in', $this->castArray($parts)];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// LIKE
|
||||
if (str_contains($val, '*') || str_contains($val, '%')) {
|
||||
$pattern = str_replace('*', '%', $val);
|
||||
$where[$key] = ['like', $pattern];
|
||||
continue;
|
||||
}
|
||||
// 默认 EQ
|
||||
$where[$key] = $this->cast($val);
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 sort=id,-created_at → ['id'=>'asc','created_at'=>'desc']
|
||||
*/
|
||||
protected function parseSort(string $sort): array
|
||||
{
|
||||
$order = [];
|
||||
foreach (explode(',', $sort) as $piece) {
|
||||
$f = trim($piece);
|
||||
if ($f === '') {
|
||||
continue;
|
||||
}
|
||||
if ($f[0] === '-') {
|
||||
$order[substr($f, 1)] = 'desc';
|
||||
} else {
|
||||
$order[$f] = 'asc';
|
||||
}
|
||||
}
|
||||
return $order;
|
||||
}
|
||||
|
||||
/**
|
||||
* 逗号分割成数组
|
||||
*/
|
||||
protected function parseCsv(string $csv): array
|
||||
{
|
||||
if ($csv === '') {
|
||||
return [];
|
||||
}
|
||||
return array_filter(array_map('trim', explode(',', $csv)));
|
||||
}
|
||||
|
||||
/** 简单类型转换:全数字→int/float,其余保留原字符串 */
|
||||
protected function cast(string $v): mixed
|
||||
{
|
||||
if (is_numeric($v)) {
|
||||
return strpos($v, '.') !== false ? (float)$v : (int)$v;
|
||||
}
|
||||
return $v;
|
||||
}
|
||||
|
||||
/** 批量类型转换 */
|
||||
protected function castArray(array $arr): array
|
||||
{
|
||||
return array_map(fn($v) => $this->cast($v), $arr);
|
||||
}
|
||||
|
||||
/** 判断两端是否可做 BETWEEN(数字或 YYYY-MM-DD 日期) */
|
||||
protected function isRangeValue(string $a, string $b): bool
|
||||
{
|
||||
return (is_numeric($a) && is_numeric($b))
|
||||
|| (preg_match('/^\d{4}-\d{2}-\d{2}$/', $a)
|
||||
&& preg_match('/^\d{4}-\d{2}-\d{2}$/', $b));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\traits;
|
||||
|
||||
use think\Validate;
|
||||
use support\Request;
|
||||
use support\exception\BusinessException;
|
||||
|
||||
trait RequestTrait
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* 验证数据
|
||||
*
|
||||
* @param Validate $validator 验证器实例
|
||||
* @param array $data 待验证的数据
|
||||
* @param string $scene 验证场景
|
||||
* @return array 验证后的数据
|
||||
* @throws BusinessException 验证失败时抛出业务异常
|
||||
*/
|
||||
public function validate(Validate $validator, array $data, string $scene = ''): array
|
||||
{
|
||||
// 如果指定了验证场景,并且验证器支持场景方法,则设置验证场景
|
||||
if ($scene && method_exists($validator, 'scene')) {
|
||||
$validator->scene($scene);
|
||||
}
|
||||
// 执行数据验证
|
||||
if (!$validator->check($data)) {
|
||||
// 验证失败,抛出业务异常,异常信息为验证器返回的错误信息
|
||||
throw new BusinessException($validator->getError());
|
||||
}
|
||||
// 验证成功,返回原始数据
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
namespace app\common\traits\crud;
|
||||
|
||||
use support\Request;
|
||||
|
||||
/**
|
||||
* CRUD 操作控制器 Trait
|
||||
* 提供通用的增删改查控制器方法,通过调用 service 层实现业务逻辑解耦。
|
||||
*/
|
||||
trait CrudControllerTrait
|
||||
{
|
||||
/**
|
||||
* 获取列表
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回分页数据及总数
|
||||
*/
|
||||
public function index(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceList($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'indexFormat')
|
||||
? [$this, 'indexFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取详情
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @param int|string $id 资源 ID
|
||||
* @return mixed 返回资源详情数据
|
||||
*/
|
||||
public function show(Request $request)
|
||||
{
|
||||
try {
|
||||
$raw = $this->service->serviceShow($request);
|
||||
$data = $this->transformData($raw, method_exists($this, 'showFormat')
|
||||
? [$this, 'showFormat']
|
||||
: null);
|
||||
return $this->success($data);
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回创建成功的数据或信息
|
||||
*/
|
||||
public function store(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $this->validate($this->service->getValidator(), $request->post(), 'store');
|
||||
$res = $this->service->serviceStore($request, $data);
|
||||
return $this->success($res, '创建成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回更新成功的数据或信息
|
||||
*/
|
||||
public function update(Request $request)
|
||||
{
|
||||
try {
|
||||
$data = $this->validate($this->service->getValidator(), $request->post(), 'update');
|
||||
$res = $this->service->serviceUpdate($request, $data);
|
||||
return $this->success([], '更新成功');
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除
|
||||
*
|
||||
* @param Request $request 请求对象
|
||||
* @return mixed 返回删除操作结果
|
||||
*/
|
||||
public function destroy(Request $request)
|
||||
{
|
||||
try {
|
||||
$count = $this->service->serviceDestroy($request);
|
||||
return $this->success([], "成功删除了 {$count} 条");
|
||||
} catch (\Throwable $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// 以下三个钩子方法,**在使用此 Trait 的 Controller** 中实现
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* 字段名格式化:例如全部下划线
|
||||
*
|
||||
* @param string $field
|
||||
* @return string
|
||||
*/
|
||||
// protected function fieldFormatter(string $field): string
|
||||
// {
|
||||
// return snake_case($field);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 字段级后置加工规则
|
||||
*
|
||||
* @return array<string,callable>
|
||||
* 键为 “点号嵌套”或 “通配符” 字段路径,
|
||||
* 值为 fn($value, $row)=>mixed
|
||||
*/
|
||||
// protected function getFieldTransforms(): array
|
||||
// {
|
||||
// return [
|
||||
// 'name' => fn($v,$row)=>strtoupper($v),
|
||||
// 'orders.*.total' => fn($v,$row)=>number_format($v,2),
|
||||
// ];
|
||||
// }
|
||||
|
||||
/**
|
||||
* 结果级后置加工:接收整个数组,可任意增删改
|
||||
*
|
||||
* @param array $data
|
||||
* @return array
|
||||
*/
|
||||
// protected function postFormat(array $data): array
|
||||
// {
|
||||
// // 例如重命名 records 为 items
|
||||
// if (isset($data['records'])) {
|
||||
// $data['items'] = $data['records'];
|
||||
// unset($data['records']);
|
||||
// }
|
||||
// return $data;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
namespace app\common\traits\crud;
|
||||
|
||||
use app\common\utils\CrudUtil;
|
||||
|
||||
/**
|
||||
* Trait CrudLogicTrait
|
||||
*
|
||||
* 提供最基础的 CRUD 和复杂查询方法,基于 CrudUtil。
|
||||
* 使用此 Trait 的类,须定义:
|
||||
* protected string $modelClass = \App\common\model\YourModel::class;
|
||||
*/
|
||||
trait CrudLogicTrait
|
||||
{
|
||||
/**
|
||||
* 分页列表
|
||||
*/
|
||||
public function logicList(array $config, int $limit, int $page)
|
||||
{
|
||||
$config['model'] = $this->modelClass;
|
||||
return CrudUtil::paginate(CrudUtil::buildQuery($config), $limit, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* 全量列表
|
||||
*/
|
||||
public function logicListAll(array $config)
|
||||
{
|
||||
$config['model'] = $this->modelClass;
|
||||
return CrudUtil::getAll(CrudUtil::buildQuery($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询单条
|
||||
*/
|
||||
public function logicShow(array $config)
|
||||
{
|
||||
return CrudUtil::findOneBy(CrudUtil::buildQuery($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建(可带 dataLimit)
|
||||
*/
|
||||
public function logicCreate(array $data, array $dataLimit = [])
|
||||
{
|
||||
return CrudUtil::create($this->modelClass, $data, $dataLimit);
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意条件更新(可带 dataLimit)
|
||||
*/
|
||||
public function logicUpdateBy(array $config, array $data)
|
||||
{
|
||||
return CrudUtil::updateBy(CrudUtil::buildQuery($config), $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 任意条件删除(可带 dataLimit)
|
||||
*/
|
||||
public function logicDeleteBy(array $config)
|
||||
{
|
||||
return CrudUtil::deleteBy(CrudUtil::buildQuery($config));
|
||||
}
|
||||
|
||||
/**
|
||||
* 复杂查询回调
|
||||
*/
|
||||
public function logicComplex(callable $callback)
|
||||
{
|
||||
return CrudUtil::executeComplex($this->modelClass, $callback);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主键查询
|
||||
*/
|
||||
public function findByPk(int $id, array $with = [])
|
||||
{
|
||||
return CrudUtil::findByPk($this->modelClass, $id, $with);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,193 @@
|
||||
<?php
|
||||
namespace app\common\traits\crud;
|
||||
|
||||
use support\Request;
|
||||
|
||||
/**
|
||||
* Trait CrudServiceTrait
|
||||
*
|
||||
* 提供标准的增删改查 Service 接口,依赖 CrudLogicTrait。
|
||||
* 使用此 Trait 的 Service 类,须:
|
||||
* use CrudLogicTrait, CrudServiceTrait;
|
||||
* protected string $modelClass = \App\common\model\YourModel::class;
|
||||
*/
|
||||
trait CrudServiceTrait
|
||||
{
|
||||
use CrudLogicTrait;
|
||||
|
||||
/** 具体 Service 里定义:protected string $modelClass = YourModel::class; */
|
||||
|
||||
/**
|
||||
* 获取验证器
|
||||
*/
|
||||
public function getValidator()
|
||||
{
|
||||
return $this->validator;
|
||||
}
|
||||
|
||||
/** 分页列表 */
|
||||
public function serviceList(Request $request)
|
||||
{
|
||||
if (method_exists($this, 'complexQuery')) {
|
||||
$result = $this->complexQuery($request->get());
|
||||
} else {
|
||||
$config = $this->buildQueryConfig($request, 'index');
|
||||
$limit = (int)$request->get('size', 15);
|
||||
$page = (int)$request->get('current', 1);
|
||||
$result = $this->logicList($config, $limit, $page);
|
||||
}
|
||||
return $this->postProcess('List', $result);
|
||||
}
|
||||
|
||||
/** 全量列表 */
|
||||
public function serviceListAll(Request $request)
|
||||
{
|
||||
if (method_exists($this, 'complexQuery')) {
|
||||
$result = $this->complexQuery($request->get());
|
||||
} else {
|
||||
$config = $this->buildQueryConfig($request, 'default');
|
||||
$result = $this->logicListAll($config);
|
||||
}
|
||||
return $this->postProcess('List', $result);
|
||||
}
|
||||
|
||||
/** 查看单条 */
|
||||
public function serviceShow(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'show');
|
||||
$item = $this->logicShow($config);
|
||||
return $this->postProcess('Show', $item);
|
||||
}
|
||||
|
||||
/** 创建 */
|
||||
public function serviceStore(Request $request, array $data = [])
|
||||
{
|
||||
$data = $this->preProcess('Store', $data, $request);
|
||||
$dl = $this->getDataLimitFromRequest($request);
|
||||
$created = $this->logicCreate($data, $dl);
|
||||
return $this->postProcess('Store', $created);
|
||||
}
|
||||
|
||||
/** 更新 */
|
||||
public function serviceUpdate(Request $request, array $data = [])
|
||||
{
|
||||
$data = $this->preProcess('Update', $data, $request);
|
||||
$config = $this->buildQueryConfig($request, 'update');
|
||||
$updated = $this->logicUpdateBy($config, $data);
|
||||
return $this->postProcess('Update', $updated);
|
||||
}
|
||||
|
||||
/** 删除 */
|
||||
public function serviceDestroy(Request $request)
|
||||
{
|
||||
$config = $this->buildQueryConfig($request, 'destroy');
|
||||
$deleted = $this->logicDeleteBy($config);
|
||||
return $this->postProcess('Destroy', $deleted);
|
||||
}
|
||||
|
||||
/** ----------------- 公共辅助方法 ----------------- */
|
||||
|
||||
/**
|
||||
* 构造 CrudUtil 查询配置
|
||||
*/
|
||||
protected function buildQueryConfig(Request $request, string $scene = 'default'): array
|
||||
{
|
||||
$p = $request->all();
|
||||
|
||||
$config = [];
|
||||
$config['model'] = $this->modelClass;
|
||||
switch ($scene) {
|
||||
case 'default':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'index':
|
||||
$config['where']['status'] = 1;
|
||||
$config['order']['sort'] = 'desc';
|
||||
$config['order']['id'] = 'desc';
|
||||
break;
|
||||
case 'show':
|
||||
$config['where']['id'] = $p['id'];
|
||||
$config['where']['status'] = 1;
|
||||
break;
|
||||
case 'store':
|
||||
break;
|
||||
case 'update':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
case 'destroy':
|
||||
$config['where']['id'] = $p['id'];
|
||||
break;
|
||||
}
|
||||
|
||||
return $config;
|
||||
}
|
||||
|
||||
/** 解析 withFields 字符串 "rel:field,field;..." */
|
||||
protected function parseWithFields(string $str): array
|
||||
{
|
||||
if (!$str) {
|
||||
return [];
|
||||
}
|
||||
$out = [];
|
||||
foreach (explode(';', $str) as $pair) {
|
||||
[$rel, $flds] = explode(':', $pair);
|
||||
$out[$rel] = explode(',', $flds);
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
/** 从请求读取 dataLimitType, dataLimitField */
|
||||
protected function getDataLimitFromRequest(Request $req): array
|
||||
{
|
||||
$type = $req->get('dataLimitType');
|
||||
if (!$type) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
'type' => $type,
|
||||
'field' => $req->get('dataLimitField', 'admin_id'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* $data 前置处理
|
||||
*
|
||||
* @param array $data
|
||||
* @param Request $request
|
||||
* @return array
|
||||
*/
|
||||
protected function preProcess(string $op, mixed $data, Request $request): mixed
|
||||
{
|
||||
$hook = "beforeService{$op}";
|
||||
return method_exists($this, $hook)
|
||||
? $this->{$hook}($data, $request)
|
||||
: $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据操作类型,调用对应的后置钩子
|
||||
*
|
||||
* @param string $op 操作:List, Show, Store, Update, Destroy
|
||||
* @param mixed $data 原始返回值
|
||||
* @return mixed 处理后的返回值
|
||||
*/
|
||||
protected function postProcess(string $op, mixed $data): mixed
|
||||
{
|
||||
$hook = "afterService{$op}";
|
||||
return method_exists($this, $hook)
|
||||
? $this->{$hook}($data)
|
||||
: $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 处理复杂查询
|
||||
* 覆盖此方法,实现复杂查询逻辑
|
||||
*/
|
||||
// protected function complexQuery(array $params): array
|
||||
// {
|
||||
// throw new \LogicException('请在子类实现 complexQuery');
|
||||
// }
|
||||
}
|
||||
Reference in New Issue
Block a user