/** * Support method for display() -- process advanced queries. * * @param AbstractQuery $query Query to convert * @param callable $translate Callback to translate strings * @param callable $showName Callback to translate field names * * @return string */ protected static function displayAdvanced(AbstractQuery $query, $translate, $showName) { $output = ''; //There should only ever be 1 group with EDS queries. $all = []; foreach ($query->getQueries() as $search) { if ($search instanceof QueryGroup) { // Process each search group. There should only be 1 with EDS queries $groupQueries = $search->getQueries(); for ($i = 0; $i < count($groupQueries); $i++) { $group = $groupQueries[$i]; if ($group instanceof Query) { // Build this group individually as a basic search $queryOperator = $group->getOperator(); $op = null != $queryOperator && 0 != $i ? call_user_func($translate, $queryOperator) . ' ' : ''; $all[] = $op . call_user_func($showName, $group->getHandler()) . ':' . $group->getString(); } else { throw new \Exception('Unexpected ' . get_class($group)); } } } else { throw new \Exception('Unexpected ' . get_class($search)); } } $output = '(' . join(' ', $all) . ')'; return $output; }
/** * Reduce components of query group to a search string of a simple query. * * This function implements the recursive reduction of a query group. * * @param AbstractQuery $component Component * * @return string * * @see self::reduceQueryGroup() */ protected function reduceQueryGroupComponents(AbstractQuery $component) { if ($component instanceof QueryGroup) { $reduced = array_map([$this, 'reduceQueryGroupComponents'], $component->getQueries()); $searchString = $component->isNegated() ? 'NOT ' : ''; $searchString .= sprintf('(%s)', implode(" {$component->getOperator()} ", $reduced)); } else { $searchString = $this->getLuceneHelper()->normalizeSearchString($component->getString()); $searchString = $this->getLuceneHelper()->finalizeSearchString($searchString); $searchHandler = $this->getSearchHandler($component->getHandler(), $searchString); if ($searchHandler) { $searchString = $this->createSearchString($searchString, $searchHandler); } } return $searchString; }
/** * Convert a Query or QueryGroup into minified search arguments. * * @param AbstractQuery $query Query to minify * @param bool $topLevel Is this a top-level query? (Used for recursion) * * @return array */ public static function minify(AbstractQuery $query, $topLevel = true) { // Simple query: if ($query instanceof Query) { return [['l' => $query->getString(), 'i' => $query->getHandler()]]; } // Advanced query: $retVal = []; $operator = $query->isNegated() ? 'NOT' : $query->getOperator(); foreach ($query->getQueries() as $current) { if ($topLevel) { $retVal[] = ['g' => self::minify($current, false), 'j' => $operator]; } elseif ($current instanceof QueryGroup) { throw new \Exception('Not sure how to minify this query!'); } else { $currentArr = ['f' => $current->getHandler(), 'l' => $current->getString(), 'b' => $operator]; if (null !== ($op = $current->getOperator())) { $currentArr['o'] = $op; } $retVal[] = $currentArr; } } return $retVal; }
/** * Perform a search and return record collection. * * @param AbstractQuery $query Search query * @param integer $offset Search offset * @param integer $limit Search limit * @param ParamBag $params Search backend parameters * *@return \VuFindSearch\Response\RecordCollectionInterface **/ public function search(AbstractQuery $query, $offset, $limit, ParamBag $params = null) { // process EDS API communication tokens. $authenticationToken = $this->getAuthenticationToken(); $sessionToken = $this->getSessionToken(); $this->debugPrint("Authentication Token: {$authenticationToken}, SessionToken: {$sessionToken}"); // check to see if there is a parameter to only process this call as a setup if (null !== $params && true == $params->get('setuponly')) { return false; } // create query parameters from VuFind data $queryString = !empty($query) ? $query->getAllTerms() : ''; $paramsStr = implode('&', null !== $params ? $params->request() : []); $this->debugPrint("Query: {$queryString}, Limit: {$limit}, Offset: {$offset}, " . "Params: {$paramsStr}"); $baseParams = $this->getQueryBuilder()->build($query); $paramsStr = implode('&', $baseParams->request()); $this->debugPrint("BaseParams: {$paramsStr} "); if (null !== $params) { $baseParams->mergeWith($params); } $baseParams->set('resultsPerPage', $limit); $page = $limit > 0 ? floor($offset / $limit) + 1 : 1; $baseParams->set('pageNumber', $page); $searchModel = $this->paramBagToEBSCOSearchModel($baseParams); $qs = $searchModel->convertToQueryString(); $this->debugPrint("Search Model query string: {$qs}"); try { $response = $this->client->search($searchModel, $authenticationToken, $sessionToken); } catch (\EbscoEdsApiException $e) { // if the auth or session token was invalid, try once more switch ($e->getApiErrorCode()) { case 104: case 108: case 109: try { // For error 104, retry auth token; for 108/9, retry sess token: if ($e->getApiErrorCode() == 104) { $authenticationToken = $this->getAuthenticationToken(true); } else { $sessionToken = $this->getSessionToken(true); } $response = $this->client->search($searchModel, $authenticationToken, $sessionToken); } catch (Exception $e) { throw new BackendException($e->getMessage(), $e->getCode(), $e); } break; default: $response = []; break; } } catch (Exception $e) { $this->debugPrint("Exception found: " . $e->getMessage()); throw new BackendException($e->getMessage(), $e->getCode(), $e); } $collection = $this->createRecordCollection($response); $this->injectSourceIdentifier($collection); return $collection; }
/** * Should we skip the specified term? * * @param AbstractQuery $query Query for which info should be retrieved * @param string $term Term to check * @param bool $queryContains Should we skip the term if it is found * in the query (true), or should we skip the term if it is NOT found in the * query (false)? * * @return bool */ protected function shouldSkipTerm($query, $term, $queryContains) { // If term is numeric and we're in "skip numeric" mode, we should skip it: if ($this->shouldSkipNumericSpelling() && is_numeric($term)) { return true; } // We should also skip terms already contained within the query: return $queryContains == $query->containsTerm($term); }