fetchRaw($request) ); } /** * @return array * @throws BadRequest * @throws Forbidden */ private function fetchRaw(Request $request): array { $params = $request->hasQueryParam('searchParams') ? $this->fetchRawJsonSearchParams($request): $this->fetchRawMultipleParams($request); $this->handleRawParams($params, $request); return $params; } /** * @return array * @throws BadRequest */ private function fetchRawJsonSearchParams(Request $request): array { try { return Json::decode($request->getQueryParam('searchParams') ?? '', true); } catch (JsonException) { throw new BadRequest("Invalid search params JSON."); } } /** * @return array */ private function fetchRawMultipleParams(Request $request): array { $params = []; $params['where'] = $request->getQueryParams()['where'] ?? null; if ($params['where'] !== null && !is_array($params['where'])) { $params['where'] = null; } $params['maxSize'] = $request->getQueryParam('maxSize'); $params['offset'] = $request->getQueryParam('offset'); if ($params['maxSize'] === '') { $params['maxSize'] = null; } if ($params['offset'] === '') { $params['offset'] = null; } if ($params['maxSize'] !== null) { $params['maxSize'] = intval($params['maxSize']); } if ($params['offset'] !== null) { $params['offset'] = intval($params['offset']); } if ($request->getQueryParam('orderBy')) { $params['orderBy'] = $request->getQueryParam('orderBy'); } else if ($request->getQueryParam('sortBy')) { // legacy $params['orderBy'] = $request->getQueryParam('sortBy'); } if ($request->getQueryParam('order')) { $params['order'] = strtoupper($request->getQueryParam('order')); } else if ($request->getQueryParam('asc')) { // legacy $params['order'] = $request->getQueryParam('asc') === 'true' ? SearchParams::ORDER_ASC : SearchParams::ORDER_DESC; } if ($request->getQueryParam('q')) { $params['q'] = trim($request->getQueryParam('q')); } if ($request->getQueryParam('textFilter')) { $params['textFilter'] = $request->getQueryParam('textFilter'); } if ($request->getQueryParam('primaryFilter')) { $params['primaryFilter'] = $request->getQueryParam('primaryFilter'); } if ($request->getQueryParams()['boolFilterList'] ?? null) { $params['boolFilterList'] = (array) $request->getQueryParams()['boolFilterList']; } if ($request->getQueryParams()['filterList'] ?? null) { $params['filterList'] = (array) $request->getQueryParams()['filterList']; } if ($request->getQueryParam('select')) { $params['select'] = explode(',', $request->getQueryParam('select')); } return $params; } /** * @param array $params * @throws BadRequest * @throws Forbidden */ private function handleRawParams(array &$params, Request $request): void { if (isset($params['maxSize']) && !is_int($params['maxSize'])) { throw new BadRequest('maxSize must be integer.'); } /** @var ?string $q */ $q = $params['q'] ?? null; if ( $q !== null && !str_contains($q, '*') && !str_contains($q, '"') && !str_contains($q, '+') && !str_contains($q, '-') && $this->hasFullTextSearch($request) ) { $params['q'] = $q . '*'; } $this->handleMaxSize($params); } private function hasFullTextSearch(Request $request): bool { $scope = $request->getRouteParam('controller'); if (!$scope) { return false; } if ($request->getRouteParam('action') !== 'index') { return false; } return $this->textMetadataProvider->hasFullTextSearch($scope); } /** * @param array $params * @throws Forbidden */ private function handleMaxSize(array &$params): void { $value = $params['maxSize'] ?? null; $limit = $this->config->get('recordListMaxSizeLimit') ?? self::MAX_SIZE_LIMIT; if ($value === null) { $params['maxSize'] = $limit; } if ($value > $limit) { throw new Forbidden("Max size should not exceed {$limit}. Use offset and limit."); } } }