<?php/***+------------------* madong*+------------------* Copyright (c) https://gitee.com/motion-code All rights reserved.*+------------------* Author: Mr. April (405784684@qq.com)*+------------------* Official Website: http://www.madong.tech*/namespace madong\query;use Illuminate\Database\Eloquent\Model;use madong\helper\DateTime;use madong\helper\Arr;/*** QuerySelect 辅助类* 提供灵活的参数解析和过滤功能*/class QuerySelectHelper{/*** 配置对象* @var QuerySelectConfig*/private QuerySelectConfig $config;/*** 数据库字段列表* @var array*/private array $dbFields = [];/*** 构造函数** @param \madong\query\QuerySelectConfig $config* @param array $dbFields*/public function __construct(QuerySelectConfig $config, array $dbFields = []){$this->config = $config;$this->dbFields = $dbFields;}/*** 处理输入参数** @param array $input* @param Model|null $model* @return array|object*/public function process(array $input, ?Model $model = null): object|array{// 获取数据库字段if ($model && empty($this->dbFields)) {$this->dbFields = $model->getFields();}// 解析基本参数$field = $this->parseField($input);$format = $this->parseFormat($input);$limit = $this->parseLimit($input);$page = $this->parsePage($input);$order = $this->parseSort($input);// 解析查询条件$where = $this->parseWhere($input);// 解析自定义字段$customFields = $this->parseCustomFields($input);// 构建结果$result = array_merge($customFields, ['where' => $where,'format' => $format,'limit' => $limit,'field' => $field,'order' => $order,'page' => $page,]);// 添加配置到结果(如果需要)if ($this->config->isDebugMode()) {$result['_config'] = $this->config->toArray();$result['_original_input'] = $input;}// 根据返回格式处理return $this->formatResult($result);}/*** 解析字段参数** @param array $input* @return string*/private function parseField(array $input): string{$field = $input['field'] ?? '*';// 检查字段是否在允许列表中if (!empty($this->config->getAllowedFields())) {$allowed = $this->config->getAllowedFields();if ($field !== '*' && !in_array($field, $allowed, true)) {return '*';}}// 检查字段是否在数据库字段中if ($field !== '*' && !empty($this->dbFields)) {if (!in_array($field, $this->dbFields, true)) {return '*';}}return $field;}/*** 解析格式参数** @param array $input* @return string*/private function parseFormat(array $input): string{return $input['format'] ?? 'normal';}/*** 解析限制参数** @param array $input* @return int*/private function parseLimit(array $input): int{$format = $input['format'] ?? 'normal';$defaultLimit = $format === 'tree' ? 10000 : $this->config->getDefaultPageSize();$limit = (int)($input['limit'] ?? $defaultLimit);$limit = max(1, $limit);$limit = min($limit, $this->config->getMaxPageSize());return $limit;}/*** 解析页码参数** @param array $input* @return int*/private function parsePage(array $input): int{$page = (int)($input['page'] ?? $this->config->getDefaultPage());return max(1, $page);}/*** 解析排序参数** @param array $input* @return string*/private function parseSort(array $input): string{$orders = [];// 获取排序字段白名单$sortFields = $this->config->getSortFields() ?? $this->dbFields;// 场景1: order=id 或 order=id descif (isset($input['order']) && !isset($input['sort']) && !isset($input['orderBy'])) {$orderValue = $input['order'];$parts = explode(' ', $orderValue, 2);$field = $parts[0];$direction = strtolower($parts[1] ?? 'desc');if (in_array($field, $sortFields)) {$orders[] = "$field$direction";}}// 场景2: sort=id:asc,create_time:desc 或 sort[]=id:asc&sort[]=create_time:descif (isset($input['sort'])) {$sortValues = is_array($input['sort']) ? $input['sort'] : explode(',', $input['sort']);foreach ($sortValues as $sortValue) {$parts = explode(':', trim($sortValue), 2);$field = $parts[0];$direction = strtolower($parts[1] ?? 'desc');if (in_array($field, $sortFields)) {$orders[] = "$field$direction";}}}// 场景3: orderBy=id&orderDirection=desc (兼容旧版)if (isset($input['orderBy']) && !isset($input['sort']) && empty($orders)) {$field = $input['orderBy'];$direction = strtolower($input['orderDirection'] ?? 'desc');if (in_array($field, $sortFields)) {$orders[] = "$field$direction";}}// 如果没有排序,使用默认排序if (empty($orders) && !empty($this->config->getDefaultSort())) {foreach ($this->config->getDefaultSort() as $field => $direction) {if (in_array($field, $sortFields)) {$orders[] = "$field$direction";}}}return implode(', ', $orders);}/*** 解析 where 条件** @param array $input* @return array*/private function parseWhere(array $input): array{$where = [];$skipFields = array_merge($this->config->getSkipFields(),['field', 'order', 'orderBy', 'orderDirection', 'sort', 'format', 'limit', 'page']);// 检查是否包含三元素数组格式$hasTripleArray = false;foreach ($input as $key => $value) {if (is_numeric($key) && is_array($value) && count($value) === 3) {$hasTripleArray = true;break;}}// 如果有三元素数组格式,直接保留原格式if ($hasTripleArray) {foreach ($input as $key => $value) {// 跳过非查询参数if (in_array($key, $skipFields, true)) {continue;}// 三元素数组直接添加if (is_numeric($key) && is_array($value) && count($value) === 3) {if ($this->isValidCondition($value)) {$where[] = $value;}continue;}// 处理大写前缀格式if (preg_match('/^([A-Z_]+)_(.+)$/', $key, $matches)) {$condition = $this->parseUppercaseFormat($matches[1], $matches[2], $value);if ($condition) {$where[] = $condition;}continue;}// 处理普通字段if ($this->isValidField($key)) {if (!$this->isSkipValue($value)) {$where[] = [$key, '=', $value];}}}} else {// 转换为标准格式$where['filters'] = [];// 处理关键词搜索if ($this->config->isEnableKeywordSearch() && !empty($input[$this->config->getKeywordParam()])) {$keyword = $input[$this->config->getKeywordParam()];$keywordFields = $this->config->getKeywordFields();if (!empty($keywordFields)) {foreach ($keywordFields as $field) {if ($this->isValidField($field)) {$where['filters'][$field] = "like:%{$keyword}%";}}}}foreach ($input as $key => $value) {// 跳过非查询参数if (in_array($key, $skipFields, true)) {continue;}// 跳过关键词参数if ($key === $this->config->getKeywordParam()) {continue;}// 处理大写前缀格式if (preg_match('/^([A-Z_]+)_(.+)$/', $key, $matches)) {$field = $matches[2];if ($this->isValidField($field)) {$operatorLower = $this->convertOperator($matches[1]);$valueString = $this->formatValue($operatorLower, $value);if ($valueString !== null) {$where['filters'][$field] = "{$operatorLower}:{$valueString}";}}continue;}// 处理普通字段if ($this->isValidField($key)) {if (!$this->isSkipValue($value)) {$where['filters'][$key] = "eq:{$value}";}}}}return $where;}/*** 解析自定义字段** @param array $input* @return array*/private function parseCustomFields(array $input): array{$customFields = [];foreach ($this->config->getCustomFields() as $key => $defaultValue) {if (isset($input[$key])) {$customFields[$key] = $input[$key];} elseif ($defaultValue !== null) {$customFields[$key] = $defaultValue;}}return $customFields;}/*** 解析大写前缀格式** @param string $operatorUpper* @param string $field* @param mixed $value* @return array|null*/private function parseUppercaseFormat(string $operatorUpper, string $field, mixed $value): ?array{if (!$this->isValidField($field)) {return null;}if ($this->isSkipValue($value, $operatorUpper)) {return null;}$operatorMap = ['IN' => 'IN','LIKE' => 'LIKE','GT' => '>','LT' => '<','GTE' => '>=','LTE' => '<=','NE' => '!=','BETWEEN' => 'BETWEEN','EQ' => '=',];$operator = $operatorMap[$operatorUpper] ?? '=';// 特殊处理 LIKE 操作符if ($operatorUpper === 'LIKE' && $this->config->isEnableLikeQuery()) {return [$field, $operator, "%{$value}%"];}// 特殊处理 IN 操作符if ($operatorUpper === 'IN') {$value = is_array($value) ? $value : Arr::normalize($value);return [$field, 'IN', $value];}// 特殊处理 BETWEEN 操作符if ($operatorUpper === 'BETWEEN' && $this->config->isEnableRangeQuery()) {if (is_array($value) && count($value) === 2) {if ($this->config->isAutoConvertDateTime()) {$start = DateTime::dateTimeStringToTimestamp($value[0]);$end = DateTime::dateTimeStringToTimestamp($value[1]);return [$field, '>', $start] + [$field, '<', $end];}return [$field, '>', $value[0]] + [$field, '<', $value[1]];}}return [$field, $operator, $value];}/*** 转换操作符** @param string $operatorUpper* @return string*/private function convertOperator(string $operatorUpper): string{$map = ['IN' => 'in','LIKE' => 'like','GT' => 'gt','LT' => 'lt','GTE' => 'gte','LTE' => 'lte','NE' => 'ne','BETWEEN' => 'between','EQ' => 'eq',];return $map[$operatorUpper] ?? 'eq';}/*** 格式化值** @param string $operator* @param mixed $value* @return string|null*/private function formatValue(string $operator, mixed $value): ?string{if ($this->isSkipValue($value)) {return null;}if ($operator === 'like' && $this->config->isEnableLikeQuery()) {return "%{$value}%";}if ($operator === 'in') {$value = is_array($value) ? $value : Arr::normalize($value);return json_encode($value);}return (string)$value;}/*** 检查字段是否有效** @param string $field* @return bool*/private function isValidField(string $field): bool{// 检查跳过字段if (in_array($field, $this->config->getSkipFields(), true)) {return false;}// 检查允许字段if (!empty($this->config->getAllowedFields())) {return in_array($field, $this->config->getAllowedFields(), true);}// 检查数据库字段if (!empty($this->dbFields)) {return in_array($field, $this->dbFields, true);}return true;}/*** 检查是否跳过值** @param mixed $value* @param string $operator* @return bool*/private function isSkipValue(mixed $value, string $operator = ''): bool{if (!$this->config->isSkipEmptyValues()) {return false;}// null 值无效if ($value === null) {return true;}// 空字符串无效if ($value === '') {return true;}// 空数组无效if (is_array($value) && empty($value)) {return true;}// 对于 BETWEEN 操作,需要检查数组元素if ($operator === 'BETWEEN' && is_array($value) && count($value) === 2) {return ($value[0] === '' || $value[0] === null) ||($value[1] === '' || $value[1] === null);}return false;}/*** 检查三元素数组条件是否有效** @param array $condition* @return bool*/private function isValidCondition(array $condition): bool{if (count($condition) !== 3) {return false;}// 检查字段是否有效if (!$this->isValidField($condition[0])) {return false;}// 检查值是否有效return !$this->isSkipValue($condition[2]);}/*** 格式化结果** @param array $result* @return array|object*/private function formatResult(array $result){$format = $this->config->getReturnFormat();switch ($format) {case 'object':return (object)$result;case 'compact':return [$result['where'],$result['format'],$result['limit'],$result['field'],$result['order'],$result['page'],];case 'array':default:return $result;}}/*** 获取配置对象** @return QuerySelectConfig*/public function getConfig(): QuerySelectConfig{return $this->config;}/*** 设置数据库字段** @param array $fields* @return self*/public function setDbFields(array $fields): self{$this->dbFields = $fields;return $this;}}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。