You are here

class SolrBaseQuery in Apache Solr Search 7

Same name and namespace in other branches
  1. 8 Solr_Base_Query.php \SolrBaseQuery
  2. 6.3 Solr_Base_Query.php \SolrBaseQuery

Hierarchy

Expanded class hierarchy of SolrBaseQuery

1 string reference to 'SolrBaseQuery'
apachesolr_drupal_query in ./apachesolr.module
Factory function for query objects.

File

./Solr_Base_Query.php, line 258
This class allows you to make operations on a query that will be sent to Apache Solr. methods such as adding and removing sorts, remove and replace parameters, adding and removing filters, getters and setters for various parameters and more

View source
class SolrBaseQuery extends SolrFilterSubQuery implements DrupalSolrQueryInterface {

  /**
   * The parameters that get sent to Solr.
   */
  protected $params = array(
    'start' => 0,
    'rows' => 10,
    'fq' => array(),
  );

  /**
   * The search base path.
   */
  protected $base_path;
  protected $field_map = array();

  /**
   * DrupalApacheSolrService object
   */
  protected $solr;

  // The array keys must always be real Solr index fields.
  protected $available_sorts;

  /**
   * The query name is used to construct a searcher string. Mostly the
   * environment id
   */
  protected $name;
  protected $context = array();

  // Makes sure we always have a valid sort.
  protected $solrsort = array(
    '#name' => 'score',
    '#direction' => 'desc',
  );

  // A flag to allow the search to be aborted.
  public $abort_search = FALSE;

  // A flag to check if need to retrieve another page of the result set
  public $page = 0;

  /**
   * @param $name
   *   The search name, used for finding the correct blocks and other config.
   *   Typically "apachesolr".
   *
   * @param $solr
   *   An instantiated DrupalApacheSolrService Object.
   *   Can be instantiated from apachesolr_get_solr().
   *
   * @param $params
   *   Array of params to initialize the object (typically 'q' and 'fq').
   *
   * @param $sortstring
   *   Visible string telling solr how to sort - added to GET query params.
   *
   * @param $base_path
   *   The search base path (without the keywords) for this query, without trailing slash.
   */
  function __construct($name, $solr, array $params = array(), $sortstring = '', $base_path = '', $context = array()) {
    parent::__construct();
    $this->name = $name;
    $this->solr = $solr;
    $this
      ->addContext((array) $context);
    $this
      ->addParams((array) $params);
    $this->available_sorts = $this
      ->defaultSorts();
    $this->sortstring = trim($sortstring);
    $this
      ->parseSortString();
    $this->base_path = $base_path;
  }
  protected function defaultSorts() {
    return array(
      'score' => array(
        'title' => t('Relevancy'),
        'default' => 'desc',
      ),
      'sort_label' => array(
        'title' => t('Title'),
        'default' => 'asc',
      ),
      'bundle' => array(
        'title' => t('Type'),
        'default' => 'asc',
      ),
      'sort_name' => array(
        'title' => t('Author'),
        'default' => 'asc',
      ),
      'ds_created' => array(
        'title' => t('Date'),
        'default' => 'desc',
      ),
    );
  }

  /**
   * Get query name.
   */
  public function getName() {
    return $this->name;
  }

  /**
   * Get query searcher name (for facetapi, views, pages, etc).
   */
  public function getSearcher() {
    return $this->name . '@' . $this->solr
      ->getId();
  }

  /**
   * Get context values.
   */
  public function getContext() {
    return $this->context;
  }

  /**
   * Set context value.
   */
  public function addContext(array $context) {
    foreach ($context as $k => $v) {
      $this->context[$k] = $v;
    }

    // The env_id must match that of the actual $solr object
    $this->context['env_id'] = $this->solr
      ->getId();
    return $this->context;
  }

  /**
   * Get Single Value params for the base query.
   * @return array
   */
  protected function getSingleValueParams() {
    $single_value_params = array(
      'q' => TRUE,
      // http://wiki.apache.org/solr/SearchHandler#q
      'q.op' => TRUE,
      // http://wiki.apache.org/solr/SearchHandler#q.op
      'q.alt' => TRUE,
      // http://wiki.apache.org/solr/SearchHandler#q
      'df' => TRUE,
      'qt' => TRUE,
      'defType' => TRUE,
      'timeAllowed' => TRUE,
      'omitHeader' => TRUE,
      'debugQuery' => TRUE,
      'start' => TRUE,
      'rows' => TRUE,
      'stats' => TRUE,
      'facet' => TRUE,
      'facet.prefix' => TRUE,
      'facet.limit' => TRUE,
      'facet.offset' => TRUE,
      'facet.mincount' => TRUE,
      'facet.missing' => TRUE,
      'facet.method' => TRUE,
      'facet.enum.cache.minDf' => TRUE,
      'facet.date.start' => TRUE,
      'facet.date.end' => TRUE,
      'facet.date.gap' => TRUE,
      'facet.date.hardend' => TRUE,
      'facet.date.other' => TRUE,
      'facet.date.include' => TRUE,
      'hl' => TRUE,
      'hl.snippets' => TRUE,
      'hl.fragsize' => TRUE,
      'hl.mergeContiguous' => TRUE,
      'hl.requireFieldMatch' => TRUE,
      'hl.maxAnalyzedChars' => TRUE,
      'hl.alternateField' => TRUE,
      'hl.maxAlternateFieldLength' => TRUE,
      'hl.formatter' => TRUE,
      'hl.simple.pre/hl.simple.post' => TRUE,
      'hl.fragmenter' => TRUE,
      'hl.fragListBuilder' => TRUE,
      'hl.fragmentsBuilder' => TRUE,
      'hl.useFastVectorHighlighter' => TRUE,
      'hl.usePhraseHighlighter' => TRUE,
      'hl.highlightMultiTerm' => TRUE,
      'hl.regex.slop' => TRUE,
      'hl.regex.pattern' => TRUE,
      'hl.regex.maxAnalyzedChars' => TRUE,
      'mm' => TRUE,
      'spellcheck' => TRUE,
    );

    // Date change to Range in versions after Solr 5.
    if ($this->solr
      ->getSolrVersion() >= 6) {
      $deprecated_keys = [
        'facet.date.start',
        'facet.date.end',
        'facet.date.gap',
        'facet.date.hardend',
        'facet.date.other',
        'facet.date.include',
      ];
      $new_keys = [
        'facet.range.start',
        'facet.range.end',
        'facet.range.gap',
        'facet.range.hardend',
        'facet.range.other',
        'facet.range.include',
      ];
      $single_value_params = array_merge(array_diff_key($single_value_params, array_flip($deprecated_keys)), $new_keys);
    }
    return $single_value_params;
  }
  public function getSolrVersion() {
    return $this->solr
      ->getSolrVersion();
  }
  public function getParam($name) {
    if ($name == 'fq') {
      return $this
        ->rebuildFq();
    }
    $empty = isset($this
      ->getSingleValueParams()[$name]) ? NULL : array();
    return isset($this->params[$name]) ? $this->params[$name] : $empty;
  }
  public function getParams() {
    $params = $this->params;
    $params['fq'] = $this
      ->rebuildFq();
    return $params;
  }
  public function getSolrParams() {
    $params = $this
      ->getParams();

    // For certain fields Solr prefers a comma separated list.
    foreach (array(
      'fl',
      'hl.fl',
      'sort',
      'mlt.fl',
    ) as $name) {
      if (isset($params[$name])) {
        $params[$name] = implode(',', $params[$name]);
      }
    }
    return $params;
  }
  protected function addFq($string, $index = NULL) {
    $string = trim($string);
    $local = '';
    $exclude = FALSE;
    $name = NULL;
    $value = NULL;
    $matches = array();

    // Check if we are dealing with an exclude
    if (preg_match('/^-(.*)/', $string, $matches)) {
      $exclude = TRUE;
      $string = $matches[1];
    }

    // If {!something} is found as first character then this is a local value
    if (preg_match('/\\{!([^}]+)\\}(.*)/', $string, $matches)) {
      $local = $matches[1];
      $string = $matches[2];
    }

    // Anything that has a name and value
    // check if we have a : in the string
    if (strstr($string, ':')) {
      list($name, $value) = explode(":", $string, 2);
    }
    else {
      $value = $string;
    }
    $this
      ->addFilter($name, $value, $exclude, $local);
    return $this;
  }
  public function addParam($name, $value) {
    if (isset($this
      ->getSingleValueParams()[$name])) {
      if (is_array($value)) {
        $value = end($value);
      }
      $this->params[$name] = $this
        ->normalizeParamValue($value);
      return $this;
    }

    // We never actually populate $this->params['fq'].  Instead
    // we manage everything via the filter methods.
    if ($name == 'fq') {
      if (is_array($value)) {
        array_walk_recursive($value, array(
          $this,
          'addFq',
        ));
        return $this;
      }
      else {
        return $this
          ->addFq($value);
      }
    }
    if (!isset($this->params[$name])) {
      $this->params[$name] = array();
    }
    if (!is_array($value)) {

      // Convert to array for array_map.
      $param_values = array(
        $value,
      );
    }
    else {

      // Convert to a numerically keyed array.
      $param_values = array_values($value);
    }
    $this->params[$name] = array_merge($this->params[$name], array_map(array(
      $this,
      'normalizeParamValue',
    ), $param_values));
    return $this;
  }
  protected function normalizeParamValue($value) {

    // Convert boolean to string.
    if (is_bool($value)) {
      return $value ? 'true' : 'false';
    }

    // Convert to trimmed string.
    return trim($value);
  }
  public function addParams(array $params) {
    foreach ($params as $name => $value) {
      $this
        ->addParam($name, $value);
    }
    return $this;
  }
  public function removeParam($name) {
    unset($this->params[$name]);
    if ($name == 'fq') {
      $this->fields = array();
      $this->subqueries = array();
    }
    return $this;
  }
  public function replaceParam($name, $value) {
    $this
      ->removeParam($name);
    return $this
      ->addParam($name, $value);
  }

  /**
   * Handles aliases for field to make nicer URLs.
   *
   * @param $field_map
   *   An array keyed with real Solr index field names with the alias as value.
   *
   * @return DrupalSolrQueryInterface
   *   The called object.
   */
  public function addFieldAliases($field_map) {
    $this->field_map = array_merge($this->field_map, $field_map);

    // We have to re-parse the filters.
    $this
      ->parseSortString();
    return $this;
  }
  public function getFieldAliases() {
    return $this->field_map;
  }
  public function clearFieldAliases() {
    $this->field_map = array();

    // We have to re-parse the filters.
    $this
      ->parseSortString();
    return $this;
  }
  protected function parseSortString() {

    // Substitute any field aliases with real field names.
    $sortstring = strtr($this->sortstring, $this->field_map);

    // Score is a special case - it's the default sort for Solr.
    if ('' == $sortstring || 'score desc' == $sortstring) {
      $this->solrsort['#name'] = 'score';
      $this->solrsort['#direction'] = 'desc';
      unset($this->params['sort']);
    }
    else {

      // Validate and set sort parameter
      $fields = array_keys($this->available_sorts);

      // Loop through available sorts and escape them, to allow for function sorts like geodist() in the preg_match() below
      foreach ($fields as $key => $field) {
        $fields[$key] = preg_quote($field);
      }

      // Implode the escaped available sorts together, then preg_match() against the sort string
      $fields = implode('|', $fields);
      if (preg_match('/^(?:(' . $fields . ') (asc|desc),?)+$/', $sortstring, $matches)) {

        // We only use the last match.
        $this->solrsort['#name'] = $matches[1];
        $this->solrsort['#direction'] = $matches[2];
        $this->params['sort'] = array(
          $sortstring,
        );
      }
      else {
        return FALSE;
      }
    }
  }
  public function getAvailableSorts() {
    return $this->available_sorts;
  }
  public function setAvailableSort($name, $sort) {

    // We expect non-aliased sorts to be added.
    $this->available_sorts[$name] = $sort;

    // Re-parse the sortstring.
    $this
      ->parseSortString();
    return $this;
  }
  public function setAvailableSorts($sorts) {

    // We expect a complete array of valid sorts.
    $this->available_sorts = $sorts;
    $this
      ->parseSortString();
    return $this;
  }
  public function removeAvailableSort($name) {
    unset($this->available_sorts[$name]);

    // Re-parse the sortstring.
    $this
      ->parseSortString();
    return $this;
  }
  public function getSolrsort() {
    return $this->solrsort;
  }
  public function setSolrsort($name, $direction) {
    $this->sortstring = trim($name) . ' ' . trim($direction);
    $this
      ->parseSortString();
    return $this;
  }
  public function getPath($new_keywords = NULL) {
    if (isset($new_keywords)) {
      return $this->base_path . '/' . $new_keywords;
    }
    elseif ($this
      ->getParam('q')) {
      return $this->base_path . '/' . $this
        ->getParam('q');
    }
    else {

      // Return with empty query (the slash). The path for a facet
      // becomes $this->base_path . '//facetinfo';
      // We do this so we can have a consistent way of retrieving the query +
      // additional parameters
      return $this->base_path . '/';
    }
  }
  public function getSolrsortUrlQuery() {
    $queryvalues = array();
    $solrsort = $this->solrsort;
    if ($solrsort && $solrsort['#name'] != 'score') {
      if (isset($this->field_map[$solrsort['#name']])) {
        $solrsort['#name'] = $this->field_map[$solrsort['#name']];
      }
      $queryvalues['solrsort'] = $solrsort['#name'] . ' ' . $solrsort['#direction'];
    }
    else {

      // Return to default relevancy sort.
      unset($queryvalues['solrsort']);
    }
    return $queryvalues;
  }
  public function search($keys = NULL) {
    if ($this->abort_search) {
      return NULL;
    }
    return $this->solr
      ->search($keys, $this
      ->getSolrParams());
  }
  public function solr($method) {
    return $this->solr
      ->{$method}();
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SolrBaseQuery::$abort_search public property
SolrBaseQuery::$available_sorts protected property
SolrBaseQuery::$base_path protected property The search base path.
SolrBaseQuery::$context protected property
SolrBaseQuery::$field_map protected property
SolrBaseQuery::$name protected property The query name is used to construct a searcher string. Mostly the environment id
SolrBaseQuery::$page public property
SolrBaseQuery::$params protected property The parameters that get sent to Solr.
SolrBaseQuery::$solr protected property DrupalApacheSolrService object
SolrBaseQuery::$solrsort protected property
SolrBaseQuery::addContext public function Set context value. Overrides DrupalSolrQueryInterface::addContext
SolrBaseQuery::addFieldAliases public function Handles aliases for field to make nicer URLs. Overrides DrupalSolrQueryInterface::addFieldAliases
SolrBaseQuery::addFq protected function
SolrBaseQuery::addParam public function Adds a param to be sent when running the Solr search. Overrides DrupalSolrQueryInterface::addParam
SolrBaseQuery::addParams public function Adds multiple params to be sent when running the Solr search. Overrides DrupalSolrQueryInterface::addParams
SolrBaseQuery::clearFieldAliases public function Overrides DrupalSolrQueryInterface::clearFieldAliases
SolrBaseQuery::defaultSorts protected function
SolrBaseQuery::getAvailableSorts public function Overrides DrupalSolrQueryInterface::getAvailableSorts
SolrBaseQuery::getContext public function Get context values. Overrides DrupalSolrQueryInterface::getContext
SolrBaseQuery::getFieldAliases public function Overrides DrupalSolrQueryInterface::getFieldAliases
SolrBaseQuery::getName public function Get query name. Overrides DrupalSolrQueryInterface::getName
SolrBaseQuery::getParam public function Gets the value of a parameter. Overrides DrupalSolrQueryInterface::getParam
SolrBaseQuery::getParams public function Gets all parameters in normalized form. Overrides DrupalSolrQueryInterface::getParams
SolrBaseQuery::getPath public function Returns the search path (including the search keywords). Overrides DrupalSolrQueryInterface::getPath
SolrBaseQuery::getSearcher public function Get query searcher name (for facetapi, views, pages, etc). Overrides DrupalSolrQueryInterface::getSearcher
SolrBaseQuery::getSingleValueParams protected function Get Single Value params for the base query.
SolrBaseQuery::getSolrParams public function Gets parameters in a form suitable for use in a Solr query. Overrides DrupalSolrQueryInterface::getSolrParams
SolrBaseQuery::getSolrsort public function Gets the current sort. Overrides DrupalSolrQueryInterface::getSolrsort
SolrBaseQuery::getSolrsortUrlQuery public function Returns an array representing the URL query string for the current sort. Overrides DrupalSolrQueryInterface::getSolrsortUrlQuery
SolrBaseQuery::getSolrVersion public function Get solr version of the query. Overrides DrupalSolrQueryInterface::getSolrVersion
SolrBaseQuery::normalizeParamValue protected function
SolrBaseQuery::parseSortString protected function
SolrBaseQuery::removeAvailableSort public function Removes an available sort. Overrides DrupalSolrQueryInterface::removeAvailableSort
SolrBaseQuery::removeParam public function Removes all values for one Solr param. Overrides DrupalSolrQueryInterface::removeParam
SolrBaseQuery::replaceParam public function Replaces a param to be sent when running the Solr search. Overrides DrupalSolrQueryInterface::replaceParam
SolrBaseQuery::search public function Sends the search request to Solr, unless $query->abort_search is TRUE. Overrides DrupalSolrQueryInterface::search
SolrBaseQuery::setAvailableSort public function Adds an available sort. Overrides DrupalSolrQueryInterface::setAvailableSort
SolrBaseQuery::setAvailableSorts public function
SolrBaseQuery::setSolrsort public function Sets the sort. Overrides DrupalSolrQueryInterface::setSolrsort
SolrBaseQuery::solr public function Calls a method, without arguments, on the Solr object with which the query object was initialized. Overrides DrupalSolrQueryInterface::solr
SolrBaseQuery::__construct function Overrides SolrFilterSubQuery::__construct
SolrFilterSubQuery::$exclude public property
SolrFilterSubQuery::$fields protected property A keyed array where the key is a position integer and the value is an array with #name and #value properties. Each value is a used for filter queries, e.g. array('#name' => 'is_uid', '#value' => 0) for anonymous…
SolrFilterSubQuery::$id public property Each query/subquery will have a unique ID.
SolrFilterSubQuery::$idCount protected static property Static shared by all instances, used to increment ID numbers.
SolrFilterSubQuery::$operator public property
SolrFilterSubQuery::$subqueries protected property An array of subqueries.
SolrFilterSubQuery::addFilter public function
SolrFilterSubQuery::addFilterSubQuery public function
SolrFilterSubQuery::getFilters public function
SolrFilterSubQuery::getFilterSubQueries public function
SolrFilterSubQuery::hasFilter public function
SolrFilterSubQuery::makeFilterQuery public function
SolrFilterSubQuery::rebuildFq protected function Builds a set of filter queries from $this->fields and all subqueries.
SolrFilterSubQuery::removeFilter public function
SolrFilterSubQuery::removeFilterSubQueries public function
SolrFilterSubQuery::removeFilterSubQuery public function
SolrFilterSubQuery::unsetFilter protected function
SolrFilterSubQuery::validFilterValue public static function Make sure our query matches the pattern name:value or name:"value" Make sure that if we are ranges we use name:[ AND ] allowed inputs : a. bundle:article b. date:[1970-12-31T23:59:59Z TO NOW] Split the text in 4 different parts 1. name, eg.:…
SolrFilterSubQuery::__clone function