/**
  * {@inheritdoc}
  */
 public function getAutocompleteSuggestions(SearchApiQueryInterface $query, $incomplete_key, $user_input)
 {
     if ($this->configuration['fields']) {
         $query->fields($this->configuration['fields']);
     }
     return $query->getIndex()->server()->getAutocompleteSuggestions($query, $this->getSearch(), $incomplete_key, $user_input);
 }
/**
 * Preprocesses a search's database query before it is executed.
 *
 * @param SelectQueryInterface $db_query
 *   The database query to be executed for the search. Will have "item_id" and
 *   "score" columns in its result.
 * @param SearchApiQueryInterface $query
 *   The search query that is being executed.
 *
 * @see SearchApiDbService::preQuery()
 */
function hook_search_api_db_query_alter(SelectQueryInterface &$db_query, SearchApiQueryInterface $query)
{
    // If the option was set on the query, add additional SQL conditions.
    if ($custom = $query->getOption('custom_sql_conditions')) {
        foreach ($custom as $condition) {
            $db_query->condition($condition['field'], $condition['value'], $condition['operator']);
        }
    }
}
/**
 * Implements hook_search_api_query_alter().
 *
 * This example hook implementation shows how a custom module could fix the
 * problem with Views contextual filters in a specific context.
 */
function example_search_api_query_alter(SearchApiQueryInterface $query)
{
    // Check whether this is an appropriate automcomplete query.
    if ($query->getOption('search id') === 'search_api_autocomplete:example') {
        // If it is, add the necessary filters that would otherwise be added by
        // contextual filters. This is easy if the argument comes from the global
        // user or a similar global source. If the argument comes from the URL or
        // some other page-specific source, however, you would need to somehow pass
        // that information along to this function.
        global $user;
        $query->condition('group', $user->data['group']);
    }
}
/**
 * Alter the search results before they are returned.
 *
 * @param array $results
 *   The results returned by the server, which may be altered. The data
 *   structure is the same as returned by SearchApiQueryInterface::execute().
 * @param SearchApiQueryInterface $query
 *   The search query that was executed.
 */
function hook_search_api_results_alter(array &$results, SearchApiQueryInterface $query)
{
    if ($query->getOption('search id') == 'search_api_views:my_search_view:page') {
        // Log the number of results.
        $vars = array('@keys' => $query->getOriginalKeys(), '@num' => $results['result count']);
        watchdog('my_module', 'Search view with query "@keys" had @num results.', $vars, WATCHDOG_DEBUG);
    }
}
 /**
  * Executes a search on the server represented by this object.
  *
  * If the service class supports facets, it should check for an additional
  * option on the query object:
  * - search_api_facets: An array of facets to return along with the results
  *   for this query. The array is keyed by an arbitrary string which should
  *   serve as the facet's unique identifier for this search. The values are
  *   arrays with the following keys:
  *   - field: The field to construct facets for.
  *   - limit: The maximum number of facet terms to return. 0 or an empty
  *     value means no limit.
  *   - min_count: The minimum number of results a facet value has to have in
  *     order to be returned.
  *   - missing: If TRUE, a facet for all items with no value for this field
  *     should be returned (if it conforms to limit and min_count).
  *   - operator: (optional) If the service supports "OR" facets and this key
  *     contains the string "or", the returned facets should be "OR" facets. If
  *     the server doesn't support "OR" facets, this key can be ignored.
  *
  * The basic principle of facets is explained quite well in the
  * @link http://en.wikipedia.org/wiki/Faceted_search Wikipedia article on
  * "Faceted search" @endlink. Basically, you should return for each field
  * filter values which would yield some results when used with the search.
  * E.g., if you return for a field $field the term $term with $count results,
  * the given $query along with
  *   $query->condition($field, $term)
  * should yield exactly (or about) $count results.
  *
  * For "OR" facets, all existing filters on the facetted field should be
  * ignored for computing the facets.
  *
  * @param $query
  *   The SearchApiQueryInterface object to execute.
  *
  * @return array
  *   An associative array containing the search results, as required by
  *   SearchApiQueryInterface::execute().
  *   In addition, if the "search_api_facets" option is present on the query,
  *   the results should contain an array of facets in the "search_api_facets"
  *   key, as specified by the option. The facets array should be keyed by the
  *   facets' unique identifiers, and contain a numeric array of facet terms,
  *   sorted descending by result count. A term is represented by an array with
  *   the following keys:
  *   - count: Number of results for this term.
  *   - filter: The filter to apply when selecting this facet term. A filter is
  *     a string of one of the following forms:
  *     - "VALUE": Filter by the literal value VALUE (always include the
  *       quotes, not only for strings).
  *     - [VALUE1 VALUE2]: Filter for a value between VALUE1 and VALUE2. Use
  *       parantheses for excluding the border values and square brackets for
  *       including them. An asterisk (*) can be used as a wildcard. E.g.,
  *       (* 0) or [* 0) would be a filter for all negative values.
  *     - !: Filter for items without a value for this field (i.e., the
  *       "missing" facet).
  *
  * @throws SearchApiException
  *   If an error prevented the search from completing.
  */
 public function search(SearchApiQueryInterface $query)
 {
     // We assume here that we have an AI search which understands English
     // commands.
     // First, create the normal search query, without facets.
     $search = new SuperCoolAiSearch($query->getIndex());
     $search->cmd('create basic search for the following query', $query);
     $ret = $search->cmd('return search results in Search API format');
     // Then, let's see if we should return any facets.
     if ($facets = $query->getOption('search_api_facets')) {
         // For the facets, we need all results, not only those in the specified
         // range.
         $results = $search->cmd('return unlimited search results as a set');
         foreach ($facets as $id => $facet) {
             $field = $facet['field'];
             $limit = empty($facet['limit']) ? 'all' : $facet['limit'];
             $min_count = $facet['min_count'];
             $missing = $facet['missing'];
             $or = isset($facet['operator']) && $facet['operator'] == 'or';
             // If this is an "OR" facet, existing filters on the field should be
             // ignored for computing the facets.
             // You can ignore this if your service class doesn't support the
             // "search_api_facets_operator_or" feature.
             if ($or) {
                 // We have to execute another query (in the case of this hypothetical
                 // search backend, at least) to get the right result set to facet.
                 $tmp_search = new SuperCoolAiSearch($query->getIndex());
                 $tmp_search->cmd('create basic search for the following query', $query);
                 $tmp_search->cmd("remove all conditions for field {$field}");
                 $tmp_results = $tmp_search->cmd('return unlimited search results as a set');
             } else {
                 // Otherwise, we can just use the normal results.
                 $tmp_results = $results;
             }
             $filters = array();
             if ($search->cmd("{$field} is a date or numeric field")) {
                 // For date, integer or float fields, range facets are more useful.
                 $ranges = $search->cmd("list {$limit} ranges of field {$field} in the following set", $tmp_results);
                 foreach ($ranges as $range) {
                     if ($range->getCount() >= $min_count) {
                         // Get the lower and upper bound of the range. * means unlimited.
                         $lower = $range->getLowerBound();
                         $lower = $lower == SuperCoolAiSearch::RANGE_UNLIMITED ? '*' : $lower;
                         $upper = $range->getUpperBound();
                         $upper = $upper == SuperCoolAiSearch::RANGE_UNLIMITED ? '*' : $upper;
                         // Then, see whether the bounds are included in the range. These
                         // can be specified independently for the lower and upper bound.
                         // Parentheses are used for exclusive bounds, square brackets are
                         // used for inclusive bounds.
                         $lowChar = $range->isLowerBoundInclusive() ? '[' : '(';
                         $upChar = $range->isUpperBoundInclusive() ? ']' : ')';
                         // Create the filter, which separates the bounds with a single
                         // space.
                         $filter = "{$lowChar}{$lower} {$upper}{$upChar}";
                         $filters[$filter] = $range->getCount();
                     }
                 }
             } else {
                 // Otherwise, we use normal single-valued facets.
                 $terms = $search->cmd("list {$limit} values of field {$field} in the following set", $tmp_results);
                 foreach ($terms as $term) {
                     if ($term->getCount() >= $min_count) {
                         // For single-valued terms, we just need to wrap them in quotes.
                         $filter = '"' . $term->getValue() . '"';
                         $filters[$filter] = $term->getCount();
                     }
                 }
             }
             // If we should also return a "missing" facet, compute that as the
             // number of results without a value for the facet field.
             if ($missing) {
                 $count = $search->cmd("return number of results without field {$field} in the following set", $tmp_results);
                 if ($count >= $min_count) {
                     $filters['!'] = $count;
                 }
             }
             // Sort the facets descending by result count.
             arsort($filters);
             // With the "missing" facet, we might have too many facet terms (unless
             // $limit was empty and is therefore now set to "all"). If this is the
             // case, remove those with the lowest number of results.
             while (is_numeric($limit) && count($filters) > $limit) {
                 array_pop($filters);
             }
             // Now add the facet terms to the return value, as specified in the doc
             // comment for this method.
             foreach ($filters as $filter => $count) {
                 $ret['search_api_facets'][$id][] = array('count' => $count, 'filter' => $filter);
             }
         }
     }
     // Return the results, which now also includes the facet information.
     return $ret;
 }
/**
 * Lets modules alter a Solr search request before sending it.
 *
 * Apache_Solr_Service::search() is called afterwards with these parameters.
 * Please see this method for details on what should be altered where and what
 * is set afterwards.
 *
 * @param array $call_args
 *   An associative array containing all four arguments to the
 *   Apache_Solr_Service::search() call ("query", "offset", "limit" and
 *   "params") as references.
 * @param SearchApiQueryInterface $query
 *   The SearchApiQueryInterface object representing the executed search query.
 */
function hook_search_api_solr_query_alter(array &$call_args, SearchApiQueryInterface $query)
{
    if ($query->getOption('foobar')) {
        $call_args['params']['foo'] = 'bar';
    }
}
/**
 * Lets modules alter a search query before executing it.
 *
 * @param SearchApiQueryInterface $query
 *   The search query being executed.
 */
function hook_search_api_query_alter(SearchApiQueryInterface $query)
{
    // Exclude entities with ID 0. (Assume the ID field is always indexed.)
    if ($query->getIndex()->getEntityType()) {
        $info = entity_get_info($query->getIndex()->getEntityType());
        $query->condition($info['entity keys']['id'], 0, '!=');
    }
}
/**
 * Lets modules alter a search query before executing it.
 *
 * @param SearchApiQueryInterface $query
 *   The SearchApiQueryInterface object representing the search query.
 */
function hook_search_api_query_alter(SearchApiQueryInterface $query)
{
    $info = entity_get_info($index->item_type);
    $query->condition($info['entity keys']['id'], 0, '!=');
}
Exemple #9
0
function ardent_search_api_solr_query_alter(array &$call_args, SearchApiQueryInterface $query)
{
    // Fetching the facet name to change solr query on.
    $facet_item = $query->getFilter()->getFilters();
    if (!empty($facet_item)) {
        $facet_item = $facet_item[0]->getFilters();
        if (!empty($facet_item[0])) {
            if (!empty($facet_item[0][1])) {
                $facet_item = $facet_item[0][1];
                // This is my facet item I wont to change solr query on "Foo" and also add node type "Bar" to the filter.
                if ($facet_item === 'research_highlights') {
                    $call_args['params']['fq'][0] = $call_args['params']['fq'][0] . ' OR  ss_type:"people"';
                }
            }
        }
    }
}
 /**
  * Overrides SearchApiSolrService::preQuery().
  *
  * Sets the eDisMax parameters if certain conditions are met, adds the default
  * parameters that are usually set in Search API's solrconfig.xml file.
  */
 protected function preQuery(array &$call_args, SearchApiQueryInterface $query)
 {
     $params =& $call_args['params'];
     // Bails if this is a 'mlt' query or something else custom.
     if (!empty($params['qt']) || !empty($params['defType'])) {
         return;
     }
     // The Search API module adds default "fl" parameters in solrconfig.xml
     // that are not present in Acquia Search's solrconfig.xml file. Add them
     // and others here as a backwards compatible solution.
     // @see http://drupal.org/node/1619770
     $params += array('echoParams' => 'none', 'fl' => 'item_id,score', 'q.op' => 'AND', 'q.alt' => '*:*', 'spellcheck' => 'false', 'spellcheck.onlyMorePopular' => 'true', 'spellcheck.extendedResults' => 'false', 'spellcheck.count' => '1', 'hl' => 'false', 'hl.fl' => 'spell', 'hl.simple.pre' => '[HIGHLIGHT]', 'hl.simple.post' => '[/HIGHLIGHT]', 'hl.snippets' => '3', 'hl.fragsize' => '70', 'hl.mergeContiguous' => 'true');
     // Set the qt to eDisMax if we have keywords and either the configuration
     // is set to always use eDisMax or the keys contain a wildcard (* or ?).
     $keys = $query->getOriginalKeys();
     if ($keys && (($wildcard = preg_match('/\\S+[*?]/', $keys)) || $this->options['edismax'])) {
         $params['defType'] = 'edismax';
         if ($wildcard) {
             // Converts keys to lower case, reset keys in query and replaces param.
             $new_keys = preg_replace_callback('/(\\S+[*?]\\S*)/', array($this, 'toLower'), $keys);
             $query->keys($new_keys);
             $call_args['query'] = $new_keys;
         }
     }
 }