/**
  * Retrieves the filter object associated with this search query.
  *
  * @return \Drupal\search_api\Query\FilterInterface
  *   This object's associated filter object.
  *
  * @see \Drupal\search_api\Query\QueryInterface::getFilter()
  */
 public function getFilter()
 {
     if (!$this->shouldAbort()) {
         return $this->query->getFilter();
     }
     return NULL;
 }
 /**
  * {@inheritdoc}
  */
 public function preprocessSearchQuery(QueryInterface $query)
 {
     $keys =& $query->getKeys();
     if (isset($keys)) {
         $this->processKeys($keys);
     }
     $filter = $query->getFilter();
     $filters =& $filter->getFilters();
     $this->processFilters($filters);
 }
Пример #3
0
 /**
  * Creates a database query for a search.
  *
  * Used as a helper method in search() and getAutocompleteSuggestions().
  *
  * @param \Drupal\search_api\Query\QueryInterface $query
  *   The search query for which to create the database query.
  * @param array $fields
  *   The internal field information to use.
  *
  * @return \Drupal\Core\Database\Query\SelectInterface
  *   A database query object which will return the appropriate results (except
  *   for the range and sorting) for the given search query.
  *
  * @throws \Drupal\search_api\SearchApiException
  *   Thrown if some illegal query setting (unknown field, etc.) was
  *   encountered.
  */
 protected function createDbQuery(QueryInterface $query, array $fields)
 {
     $keys =& $query->getKeys();
     $keys_set = (bool) $keys;
     $keys = $this->prepareKeys($keys);
     // Only filter by fulltext keys if there are any real keys present.
     if ($keys && (!is_array($keys) || count($keys) > 2 || !isset($keys['#negation']) && count($keys) > 1)) {
         // Special case: if the outermost $keys array has "#negation" set, we can't
         // handle it like other negated subkeys. To avoid additional complexity
         // later, we just wrap $keys so it becomes a subkey.
         if (!empty($keys['#negation'])) {
             $keys = array('#conjunction' => 'AND', $keys);
         }
         $fulltext_fields = $query->getFields();
         if ($fulltext_fields) {
             $_fulltext_fields = $fulltext_fields;
             $fulltext_fields = array();
             foreach ($_fulltext_fields as $name) {
                 if (!isset($fields[$name])) {
                     throw new SearchApiException(SafeMarkup::format('Unknown field @field specified as search target.', array('@field' => $name)));
                 }
                 if (!Utility::isTextType($fields[$name]['type'])) {
                     $types = $this->getDataTypePluginManager()->getDataTypeDefinitions();
                     $type = $types[$fields[$name]['type']]['label'];
                     throw new SearchApiException(SafeMarkup::format('Cannot perform fulltext search on field @field of type @type.', array('@field' => $name, '@type' => $type)));
                 }
                 $fulltext_fields[$name] = $fields[$name];
             }
             $db_query = $this->createKeysQuery($keys, $fulltext_fields, $fields, $query->getIndex());
         } else {
             $this->getLogger()->warning('Search keys are given but no fulltext fields are defined.');
             $msg = $this->t('Search keys are given but no fulltext fields are defined.');
             $this->warnings[$msg] = 1;
         }
     } elseif ($keys_set) {
         $msg = $this->t('No valid search keys were present in the query.');
         $this->warnings[$msg] = 1;
     }
     if (!isset($db_query)) {
         $db_query = $this->database->select($this->configuration['index_tables'][$query->getIndex()->id()], 't');
         $db_query->addField('t', 'item_id', 'item_id');
         $db_query->addExpression(':score', 'score', array(':score' => self::SCORE_MULTIPLIER));
         $db_query->distinct();
     }
     $filter = $query->getFilter();
     if ($filter->getFilters()) {
         $condition = $this->createFilterCondition($filter, $fields, $db_query, $query->getIndex());
         if ($condition) {
             $db_query->condition($condition);
         }
     }
     $db_query->addTag('search_api_db_search');
     $db_query->addMetaData('search_api_query', $query);
     $db_query->addMetaData('search_api_db_fields', $fields);
     return $db_query;
 }
Пример #4
0
 public function getAutocompleteSuggestions(QueryInterface $query, SearchApiAutocompleteSearch $search, $incomplete_key, $user_input)
 {
     $suggestions = array();
     // Reset request handler
     $this->request_handler = NULL;
     // Turn inputs to lower case, otherwise we get case sensivity problems.
     $incomp = Unicode::strtolower($incomplete_key);
     $index = $query->getIndex();
     $field_names = $this->getFieldNames($index);
     $complete = $query->getOriginalKeys();
     // Extract keys
     $keys = $query->getKeys();
     if (is_array($keys)) {
         $keys_array = array();
         while ($keys) {
             reset($keys);
             if (!element_child(key($keys))) {
                 array_shift($keys);
                 continue;
             }
             $key = array_shift($keys);
             if (is_array($key)) {
                 $keys = array_merge($keys, $key);
             } else {
                 $keys_array[$key] = $key;
             }
         }
         $keys = $this->getSolrHelper()->flattenKeys($query->getKeys());
     } else {
         $keys_array = preg_split('/[-\\s():{}\\[\\]\\\\"]+/', $keys, -1, PREG_SPLIT_NO_EMPTY);
         $keys_array = array_combine($keys_array, $keys_array);
     }
     if (!$keys) {
         $keys = NULL;
     }
     // Set searched fields
     $options = $query->getOptions();
     $search_fields = $query->getFulltextFields();
     $qf = array();
     foreach ($search_fields as $f) {
         $qf[] = $field_names[$f];
     }
     // Extract filters
     $fq = $this->createFilterQueries($query->getFilter(), $field_names, $index->getOption('fields', array()));
     $index_id = $this->getIndexId($index->id());
     $fq[] = 'index_id:' . $this->getQueryHelper()->escapePhrase($index_id);
     if ($this->configuration['site_hash']) {
         $site_hash = $this->getQueryHelper()->escapePhrase(SearchApiSolrUtility::getSiteHash());
         $fq[] = 'hash:' . $site_hash;
     }
     // Autocomplete magic
     $facet_fields = array();
     foreach ($search_fields as $f) {
         $facet_fields[] = $field_names[$f];
     }
     $limit = $query->getOption('limit', 10);
     $params = array('qf' => $qf, 'fq' => $fq, 'rows' => 0, 'facet' => 'true', 'facet.field' => $facet_fields, 'facet.prefix' => $incomp, 'facet.limit' => $limit * 5, 'facet.mincount' => 1, 'spellcheck' => !isset($this->configuration['autocorrect_spell']) || $this->configuration['autocorrect_spell'] ? 'true' : 'false', 'spellcheck.count' => 1);
     // Retrieve http method from server options.
     $http_method = !empty($this->configuration['http_method']) ? $this->configuration['http_method'] : 'AUTO';
     $call_args = array('query' => &$keys, 'params' => &$params, 'http_method' => &$http_method);
     if ($this->request_handler) {
         $this->setRequestHandler($this->request_handler, $call_args);
     }
     $second_pass = !isset($this->configuration['autocorrect_suggest_words']) || $this->configuration['autocorrect_suggest_words'];
     for ($i = 0; $i < ($second_pass ? 2 : 1); ++$i) {
         try {
             // Send search request
             $this->connect();
             $this->moduleHandler->alter('search_api_solr_query', $call_args, $query);
             $this->preQuery($call_args, $query);
             $response = $this->solr->search($keys, $params, $http_method);
             if (!empty($response->spellcheck->suggestions)) {
                 $replace = array();
                 foreach ($response->spellcheck->suggestions as $word => $data) {
                     $replace[$word] = $data->suggestion[0];
                 }
                 $corrected = str_ireplace(array_keys($replace), array_values($replace), $user_input);
                 if ($corrected != $user_input) {
                     array_unshift($suggestions, array('prefix' => $this->t('Did you mean') . ':', 'user_input' => $corrected));
                 }
             }
             $matches = array();
             if (isset($response->facet_counts->facet_fields)) {
                 foreach ($response->facet_counts->facet_fields as $terms) {
                     foreach ($terms as $term => $count) {
                         if (isset($matches[$term])) {
                             // If we just add the result counts, we can easily get over the
                             // total number of results if terms appear in multiple fields.
                             // Therefore, we just take the highest value from any field.
                             $matches[$term] = max($matches[$term], $count);
                         } else {
                             $matches[$term] = $count;
                         }
                     }
                 }
                 if ($matches) {
                     // Eliminate suggestions that are too short or already in the query.
                     foreach ($matches as $term => $count) {
                         if (strlen($term) < 3 || isset($keys_array[$term])) {
                             unset($matches[$term]);
                         }
                     }
                     // Don't suggest terms that are too frequent (by default in more
                     // than 90% of results).
                     $result_count = $response->response->numFound;
                     $max_occurrences = $result_count * $this->searchApiSolrSettings->get('autocomplete_max_occurrences');
                     if (($max_occurrences >= 1 || $i > 0) && $max_occurrences < $result_count) {
                         foreach ($matches as $match => $count) {
                             if ($count > $max_occurrences) {
                                 unset($matches[$match]);
                             }
                         }
                     }
                     // The $count in this array is actually a score. We want the
                     // highest ones first.
                     arsort($matches);
                     // Shorten the array to the right ones.
                     $additional_matches = array_slice($matches, $limit - count($suggestions), NULL, TRUE);
                     $matches = array_slice($matches, 0, $limit, TRUE);
                     // Build suggestions using returned facets
                     $incomp_length = strlen($incomp);
                     foreach ($matches as $term => $count) {
                         if (Unicode::strtolower(substr($term, 0, $incomp_length)) == $incomp) {
                             $suggestions[] = array('suggestion_suffix' => substr($term, $incomp_length), 'term' => $term, 'results' => $count);
                         } else {
                             $suggestions[] = array('suggestion_suffix' => ' ' . $term, 'term' => $term, 'results' => $count);
                         }
                     }
                 }
             }
         } catch (SearchApiException $e) {
             watchdog_exception('search_api_solr', $e, "%type during autocomplete Solr query: !message in %function (line %line of %file).", array(), WATCHDOG_WARNING);
         }
         if (count($suggestions) >= $limit) {
             break;
         }
         // Change parameters for second query.
         unset($params['facet.prefix']);
         $keys = trim($keys . ' ' . $incomplete_key);
     }
     return $suggestions;
 }