This commit is contained in:
Aether
2025-09-28 15:57:07 +08:00
parent 10b58a8c6d
commit 7bccb0e9fe
3 changed files with 110 additions and 40 deletions

View File

@@ -51,6 +51,12 @@ class Campus extends AetherModel
'deleted_at' => 'datetime', 'deleted_at' => 'datetime',
]; ];
protected array $search = [
'parent_id' => '=',
];
protected array|bool|string $sortable = false;
/** /**
* 获取父级校区. * 获取父级校区.
* @return BelongsTo * @return BelongsTo

View File

@@ -63,7 +63,7 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface
* - 字符串: 排序字段(默认升序) * - 字符串: 排序字段(默认升序)
* - 数组: ['field' => '字段名', 'direction' => 'asc/desc']. * - 数组: ['field' => '字段名', 'direction' => 'asc/desc'].
*/ */
protected array|bool|string $sortable = 'sort'; // 默认按sort字段升序 protected array|bool|string $sortable = false; // 'sort'; // 默认按sort字段升序
public function __construct(array $attributes = []) public function __construct(array $attributes = [])
{ {
@@ -140,12 +140,101 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface
/** /**
* 列表查询. * 列表查询.
*/ */
// public function list(array $params = []): array
// {
// $query = $this->buildQueryFromParams($params);
// return $this->listResult($query, $params);
// }
public function list(array $params = []): array public function list(array $params = []): array
{ {
$query = $this->buildQueryFromParams($params); $query = static::query();
return $this->listResult($query, $params);
// 通过模型配置自动应用所有搜索条件
$this->applySearch($query, $params);
// 动态应用排序
if ($this->sortable) {
$sortConfig = $this->getSortConfig();
$query->orderBy($sortConfig['field'], $sortConfig['direction']);
}
$withDeleted = filter_var($params['with_deleted'] ?? false, FILTER_VALIDATE_BOOLEAN);
if ($withDeleted) {
$query->withTrashed();
}
// 存在分页参数page或size则进行分页查询
if (isset($params['page']) || isset($params['size'])) {
$page = (int) ($params['page'] ?? 1);
$size = (int) ($params['size'] ?? 10);
// 确保分页参数合法性
$page = max(1, $page);
$size = max(1, min(100, $size)); // 限制最大页大小为100
$result = $query->paginate($size, ['*'], 'page', $page);
return [
'list' => $result->items(),
'total' => $result->total(),
];
}
// 无分页参数时返回完整数据集合
$items = $query->get()->toArray();
// 若模型支持树形结构则构建树形,否则返回普通数组
if ($this instanceof TreeableInterface) {
return $this::buildTree($items, (int) ($params['parent_id'] ?? 0));
}
return $items;
} }
/**
* 根据模型的$search配置自动应用搜索条件到查询构建器.
*/
// public function applySearch(Builder $query, array $params): void
// {
// foreach ($this->search as $field => $rule) {
// // 跳过未传递的参数
// if (!isset($params[$field])) {
// continue;
// }
//
// $value = $params[$field];
// $this->applySearchRule($query, $field, $value, $rule);
// }
// }
//
// /**
// * 应用单个搜索规则
// */
// protected function applySearchRule(Builder $query, string $field, $value, $rule): void
// {
// // 处理规则格式(支持字符串简写或数组配置)
// $config = is_array($rule) ? $rule : ['type' => $rule];
// $type = $config['type'];
//
// switch ($type) {
// case '=': // 精确匹配
// $query->where($field, $value);
// break;
// case 'like': // 模糊匹配
// $query->where($field, 'like', "%{$value}%");
// break;
// case 'between': // 范围查询(支持数组或两个参数)
// $values = is_array($value) ? $value : [$value, $params[$field . '_end'] ?? $value];
// $query->whereBetween($field, $values);
// break;
// case 'callback': // 自定义回调
// if (isset($config['handler']) && is_callable($config['handler'])) {
// call_user_func($config['handler'], $query, $value);
// }
// break;
// // 可扩展其他类型in、>、< 等
// }
// }
/** /**
* 快捷创建. * 快捷创建.
*/ */
@@ -293,30 +382,6 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface
return Db::transaction($closure); return Db::transaction($closure);
} }
/**
* 根据参数构建查询.
*/
protected function buildQueryFromParams(array $params = []): Builder
{
// 创建查询构建器
$query = static::query();
// 应用搜索条件
// if (isset($params['search'])) {
// $this->applySearch($query, $params['search']);
// }
$this->applySearch($query, $params);
// 应用排序
$this->applySorting($query, $params);
// 处理软删除
if (isset($params['withTrashed']) && $params['withTrashed']) {
$query->withTrashed();
}
return $query;
}
/** /**
* 应用排序. * 应用排序.
*/ */
@@ -527,35 +592,35 @@ abstract class AetherModel extends HyperfModel implements CacheableInterface
protected function applySearch(Builder $query, array $conditions): void protected function applySearch(Builder $query, array $conditions): void
{ {
foreach ($conditions as $field => $value) { foreach ($conditions as $field => $value) {
// 跳过非字符串字段名(防止索引数组键导致的类型错误) // 基础过滤:非字符串字段名或未设置值的参数直接跳过
if (! is_string($field)) { if (! is_string($field) || ! isset($value)) {
continue; continue;
} }
// 处理嵌套关系查询(如:user.name // 核心限制:只处理$search数组中定义的字段
if (! isset($this->search[$field])) {
continue;
}
// 处理嵌套关系查询(如:user.name需在$search中配置完整键名
if (str_contains($field, '.')) { if (str_contains($field, '.')) {
[$relation, $relationField] = explode('.', $field, 2); [$relation, $relationField] = explode('.', $field, 2);
$query->whereHas($relation, function ($q) use ($relationField, $value) { $query->whereHas($relation, function ($q) use ($relationField, $value) {
// 嵌套查询默认使用精确匹配,如需特殊规则可在$search中自定义处理
$q->where($relationField, $value); $q->where($relationField, $value);
}); });
continue; continue;
} }
// 检查是否有自定义搜索器方法 // 优先使用自定义搜索器方法(仅对$search中存在的字段生效
$searchMethod = 'search' . ucfirst($field); $searchMethod = 'search' . ucfirst($field);
if (method_exists($this, $searchMethod)) { if (method_exists($this, $searchMethod)) {
$this->{$searchMethod}($query, $value); $this->{$searchMethod}($query, $value);
continue; continue;
} }
// 应用搜索规则配置 // 应用$search中定义的搜索规则如=、like等
if (isset($this->search[$field])) { $this->applySearchRule($query, $field, $value, $this->search[$field]);
$this->applySearchRule($query, $field, $value, $this->search[$field]);
continue;
}
// 默认精确匹配(仅对$search中允许的字段生效因已通过白名单过滤
$query->where($field, $value);
} }
} }

View File

@@ -16,7 +16,6 @@ class RpcExceptionHandler extends ExceptionHandler
{ {
public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface public function handle(Throwable $throwable, ResponseInterface $response): ResponseInterface
{ {
var_dump($throwable->getMessage());
try { try {
// 获取请求ID用于日志追踪 // 获取请求ID用于日志追踪
$requestId = Context::get('request_id', ''); $requestId = Context::get('request_id', '');