, * 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)); } }