You are here

class SearchApiAcquiaSearchService in Acquia Search for Search API 7.2

Same name and namespace in other branches
  1. 7 includes/SearchApiAcquiaSearchService.php \SearchApiAcquiaSearchService

Search API service class for Acquia Search.

Hierarchy

Expanded class hierarchy of SearchApiAcquiaSearchService

1 string reference to 'SearchApiAcquiaSearchService'
search_api_acquia_search_api_service_info in ./search_api_acquia.module
Implements hook_search_api_service_info().

File

includes/SearchApiAcquiaSearchService.php, line 12
Contains SearchApiAcquiaSearchService.

View source
class SearchApiAcquiaSearchService extends SearchApiSolrService {
  const ACQUIA_SEARCH_API_V2 = '2';
  const ACQUIA_SEARCH_API_V3 = '3';

  /**
   * The connection class used by this service.
   *
   * Must implement SearchApiSolrConnectionInterface.
   *
   * @var string
   */
  protected $connection_class = 'SearchApiAcquiaSearchConnection';

  /**
   * Create a connection to the Solr server as configured in $this->options.
   */
  protected function connect() {
    $this
      ->setConnectionOptions();
    if (!$this->solr) {
      if (!class_exists($this->connection_class)) {
        throw new SearchApiException(t('Invalid class @class set as Solr connection class.', array(
          '@class' => $this->connection_class,
        )));
      }
      $options = $this->options + array(
        'server' => $this->server->machine_name,
      );
      $this->solr = new $this->connection_class($options);
      if (!$this->solr instanceof SearchApiSolrConnectionInterface) {
        $this->solr = NULL;
        throw new SearchApiException(t('Invalid class @class set as Solr connection class.', array(
          '@class' => $this->connection_class,
        )));
      }
    }

    // allow the connection to override the derived key
    if (isset($this->options['derived_key']) && method_exists($this->solr, 'setDerivedKey')) {
      $this->solr
        ->setDerivedKey($this->options['derived_key']);
    }
  }

  /**
   * View this server's settings.
   */
  public function viewSettings() {
    $output = '';

    // Set our special overrides if applicable
    $this
      ->setConnectionOptions();
    $options = $this->options;
    $url = $options['scheme'] . '://' . $options['host'] . ':' . $options['port'] . $options['path'];
    $output .= "<dl>\n  <dt>";
    $output .= t('Acquia Search Server');
    $output .= "</dt>\n  <dd>";
    $output .= $url;
    $output .= '</dd>';
    if ($options['http_user']) {
      $output .= "\n  <dt>";
      $output .= t('Basic HTTP authentication');
      $output .= "</dt>\n  <dd>";
      $output .= t('Username: @user', array(
        '@user' => $options['http_user'],
      ));
      $output .= "</dd>\n  <dd>";
      $output .= t('Password: @pass', array(
        '@pass' => str_repeat('*', strlen($options['http_pass'])),
      ));
      $output .= '</dd>';
    }
    $output .= "\n</dl>";
    return $output;
  }

  /**
   * {@inheritdoc}
   */
  public function getExtraInformation() {
    $extra = parent::getExtraInformation();
    $extra[] = array(
      'info' => search_api_acquia_get_search_status_message($this->server),
      'label' => t('Acquia Search status'),
    );
    return $extra;
  }

  /**
   * Set some special overrides for Acquia Search
   */
  public function setConnectionOptions() {
    $this
      ->setConnectionClass($this
      ->isV3() ? SearchApiAcquiaSearchConnectionV3::class : SearchApiAcquiaSearchConnection::class);

    // Modify connection details live on every connect so we do not need to
    // resave the server details if we make modifications in settings.php.
    $identifier = acquia_agent_settings('acquia_identifier');
    $subscription = acquia_agent_settings('acquia_subscription_data');

    // Get our override if we have one. Otherwise use the default.
    $search_host = variable_get('acquia_search_host', 'search.acquia.com');
    if (!empty($subscription['heartbeat_data']['search_service_colony'])) {
      $search_host = $subscription['heartbeat_data']['search_service_colony'];
    }

    // Get our solr path
    $search_path = variable_get('acquia_search_path', '/solr/' . $identifier);
    $this->options['host'] = $search_host;
    $this->options['path'] = $search_path;
    $this->options['derived_key'] = search_api_acquia_get_derived_key_for_core($identifier);

    // We can also have overrides per server setting.
    // Apply the overrides in the "search_api_acquia_overrides" variable.
    $name = $this->server->machine_name;
    $overrides = variable_get('search_api_acquia_overrides', array());
    if (isset($overrides[$name]) && is_array($overrides[$name])) {
      $this->options = array_merge($this->options, $overrides[$name]);
    }
  }

  /**
   * Overrides SearchApiSolrService::configurationForm().
   *
   * Populates the Solr configs with Acquia Search Information.
   */
  public function configurationForm(array $form, array &$form_state) {
    $form = parent::configurationForm($form, $form_state);

    // Set our special overrides if applicable
    $this
      ->setConnectionOptions();
    $options = $this->options += array(
      'edismax' => 0,
      'modify_acquia_connection' => FALSE,
      'scheme' => 'https',
      'acquia_search_api_version' => self::ACQUIA_SEARCH_API_V2,
    );

    // HTTP authentication is not needed since Acquia Search uses an HMAC
    // authentication mechanism.
    $form['http']['#access'] = FALSE;

    // Port should always force 443.
    $form['scheme'] = array(
      '#type' => 'value',
      '#value' => '443',
    );

    // Scheme should always force https.
    $form['scheme'] = array(
      '#type' => 'value',
      '#value' => 'https',
    );

    // Hiding to not make this form too confusing.
    $form['advanced']['solr_version']['#access'] = FALSE;
    $form['edismax'] = array(
      '#type' => 'checkbox',
      '#title' => t('Always allow advanced syntax for Acquia Search'),
      '#default_value' => $options['edismax'],
      '#description' => t('If enabled, all Acquia Search keyword searches may use advanced <a href="@url">Lucene syntax</a> such as wildcard searches, fuzzy searches, proximity searches, boolean operators and more via the Extended Dismax parser. If not enabled, this syntax wll only be used when needed to enable wildcard searches.', array(
        '@url' => 'http://lucene.apache.org/java/2_9_3/queryparsersyntax.html',
      )),
      '#weight' => -30,
    );
    $form['modify_acquia_connection'] = array(
      '#type' => 'checkbox',
      '#title' => 'Modify Acquia Search Connection Parameters',
      '#default_value' => $options['modify_acquia_connection'],
      '#description' => t('Only check this box if you are absolutely certain about what you are doing. Any misconfigurations will most likely break your site\'s connection to Acquia Search.'),
      '#weight' => -20,
    );
    $form['acquia_search_api_version'] = array(
      '#type' => 'select',
      '#options' => array(
        self::ACQUIA_SEARCH_API_V2 => 'Solr 6 and below',
        self::ACQUIA_SEARCH_API_V3 => 'Solr 7 and above',
      ),
      '#title' => 'Acquia Search Solr version',
      '#default_value' => $options['acquia_search_api_version'],
      '#description' => t('Only change this if you are absolutely certain about what you are doing. Any misconfigurations will most likely break your site\'s connection to Acquia Search.'),
      '#weight' => -10,
    );
    $form['clean_ids_form']['#weight'] = 10;

    // Re-sets defaults with Acquia information.
    $form['host']['#default_value'] = $options['host'];
    $form['path']['#default_value'] = $options['path'];

    // Only display fields if we are modifying the connection parameters to the
    // Acquia Search service.
    $states = array(
      'visible' => array(
        ':input[name="options[form][modify_acquia_connection]"]' => array(
          'checked' => TRUE,
        ),
      ),
    );
    $form['host']['#states'] = $states;
    $form['path']['#states'] = $states;
    $form['port']['#states'] = $states;

    // We cannot connect directly to the Solr instance, so don't make it a link.
    if (isset($form['server_description'])) {
      $status_message = search_api_acquia_get_search_status_message($this->server);
      $form['server_description'] = array(
        '#type' => 'item',
        '#title' => t('Acquia Search status for this connection'),
        '#description' => $status_message,
        '#weight' => -40,
      );
    }
    return $form;
  }

  /**
   * Overrides SearchApiSolrService::configurationFormValidate().
   *
   * Forces defaults if the override option is unchecked.
   *
   * @see http://drupal.org/node/1852692
   */
  public function configurationFormValidate(array $form, array &$values, array &$form_state) {
    $modified = !empty($form_state['values']['options']['form']['modify_acquia_connection']);
    if (!$modified) {

      // Set our special overrides if applicable
      $this
        ->setConnectionOptions();
      form_set_value($form['host'], $this->options['host'], $form_state);
      form_set_value($form['port'], isset($this->options['port']) ? $this->options['port'] : 443, $form_state);
      form_set_value($form['path'], $this->options['path'], $form_state);
    }
    parent::configurationFormValidate($form, $values, $form_state);
  }

  /**
   * 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();
    $edismax = isset($this->options['edismax']) ? $this->options['edismax'] : '';
    if ($keys && is_scalar($keys) && (($wildcard = preg_match('/\\S+[*?]/', $keys)) || $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;
      }
    }
  }

  /**
   * Convert to lower-case any keywords containing a wildcard.
   *
   * @see _acquia_search_lower()
   */
  public function toLower($matches) {
    return drupal_strtolower($matches[1]);
  }

  /**
   * Returns the current API version.
   */
  public function getAcquiaSearchApiVersion() {
    return $this->options['acquia_search_api_version'] ?? self::ACQUIA_SEARCH_API_V2;
  }

  /**
   * Checks if API version is V3.
   */
  private function isV3() {
    return $this
      ->getAcquiaSearchApiVersion() === self::ACQUIA_SEARCH_API_V3;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SearchApiAbstractService::$options protected property Direct reference to the server's $options property.
SearchApiAbstractService::$server protected property
SearchApiAbstractService::postCreate public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::postCreate
SearchApiAbstractService::postUpdate public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::postUpdate
SearchApiAbstractService::preDelete public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::preDelete 1
SearchApiAbstractService::query public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::query
SearchApiAbstractService::__construct public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiServiceInterface::__construct
SearchApiAcquiaSearchService::$connection_class protected property The connection class used by this service. Overrides SearchApiSolrService::$connection_class
SearchApiAcquiaSearchService::ACQUIA_SEARCH_API_V2 constant
SearchApiAcquiaSearchService::ACQUIA_SEARCH_API_V3 constant
SearchApiAcquiaSearchService::configurationForm public function Overrides SearchApiSolrService::configurationForm(). Overrides SearchApiSolrService::configurationForm
SearchApiAcquiaSearchService::configurationFormValidate public function Overrides SearchApiSolrService::configurationFormValidate(). Overrides SearchApiSolrService::configurationFormValidate
SearchApiAcquiaSearchService::connect protected function Create a connection to the Solr server as configured in $this->options. Overrides SearchApiSolrService::connect
SearchApiAcquiaSearchService::getAcquiaSearchApiVersion public function Returns the current API version.
SearchApiAcquiaSearchService::getExtraInformation public function Returns additional, service-specific information about this server. Overrides SearchApiSolrService::getExtraInformation
SearchApiAcquiaSearchService::isV3 private function Checks if API version is V3.
SearchApiAcquiaSearchService::preQuery protected function Overrides SearchApiSolrService::preQuery(). Overrides SearchApiSolrService::preQuery
SearchApiAcquiaSearchService::setConnectionOptions public function Set some special overrides for Acquia Search
SearchApiAcquiaSearchService::toLower public function Convert to lower-case any keywords containing a wildcard.
SearchApiAcquiaSearchService::viewSettings public function View this server's settings. Overrides SearchApiSolrService::viewSettings
SearchApiSolrService::$commitScheduled protected property Saves whether a commit operation was already scheduled for this server.
SearchApiSolrService::$fieldNames protected property Static cache for getFieldNames().
SearchApiSolrService::$fields protected property Metadata describing fields on the Solr/Lucene index.
SearchApiSolrService::$request_handler protected property Request handler to use for this search query.
SearchApiSolrService::$solr protected property A connection to the Solr server.
SearchApiSolrService::addIndex public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiAbstractService::addIndex
SearchApiSolrService::addIndexField protected function Helper method for indexing.
SearchApiSolrService::alterSolrDocuments protected function Applies custom modifications to indexed Solr documents.
SearchApiSolrService::commit public function Sends a commit command to the Solr server.
SearchApiSolrService::configurationFormSubmit public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiAbstractService::configurationFormSubmit
SearchApiSolrService::createFilterQueries protected function Transforms a query filter into a flat array of Solr filter queries, using the field names in $fields.
SearchApiSolrService::createFilterQuery protected function Create a single search query string according to the given field, value and operator.
SearchApiSolrService::createId public function Creates an ID used as the unique identifier at the Solr server.
SearchApiSolrService::deleteItems public function Implements SearchApiServiceInterface::deleteItems(). Overrides SearchApiServiceInterface::deleteItems
SearchApiSolrService::extractFacets protected function Extract facets from a Solr response.
SearchApiSolrService::extractHighlightingSnippets protected function Extracts short snippets with highlighting from highlighted field values.
SearchApiSolrService::extractResults protected function Extract results from a Solr response.
SearchApiSolrService::fieldsUpdated public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiAbstractService::fieldsUpdated
SearchApiSolrService::flattenKeys protected function Flatten a keys array into a single search string.
SearchApiSolrService::formatFilterValue protected function Format a value for filtering on a field of a specific type.
SearchApiSolrService::formatHighlighting protected function Changes highlighting tags from our custom, HTML-safe ones to HTML.
SearchApiSolrService::getAutocompleteSuggestions public function
SearchApiSolrService::getConnectionClass public function Gets the Solr connection class used by this service.
SearchApiSolrService::getExcerpt protected function Extract and format highlighting information for a specific item from a Solr response.
SearchApiSolrService::getFacetParams protected function Helper method for creating the facet field parameters.
SearchApiSolrService::getFieldNames public function Create a list of all indexed field names mapped to their Solr field names.
SearchApiSolrService::getFields public function Get metadata about fields in the Solr/Lucene index.
SearchApiSolrService::getFile public function Retrieves a config file or file list from the Solr server.
SearchApiSolrService::getHighlightingPrefixSuffix protected function Returns the prefix and suffix for highlighting matches in the excerpt.
SearchApiSolrService::getHighlightParams protected function Helper method for creating the highlighting parameters.
SearchApiSolrService::getIndexId protected function Prefixes an index ID as configured.
SearchApiSolrService::getQueryFields protected function Retrieves the effective fulltext fields from the query.
SearchApiSolrService::getServerLink public function Returns a link to the Solr server, if the necessary options are set.
SearchApiSolrService::getSolrConnection public function Gets the currently used Solr connection object.
SearchApiSolrService::indexItems public function Indexes the specified items. Overrides SearchApiServiceInterface::indexItems
SearchApiSolrService::ping public function Ping the Solr server to tell whether it can be accessed.
SearchApiSolrService::postQuery protected function Empty method to allow subclasses to apply custom changes before search results are returned.
SearchApiSolrService::queryMultiple public function Implements SearchApiMultiServiceInterface::queryMultiple().
SearchApiSolrService::removeIndex public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiAbstractService::removeIndex
SearchApiSolrService::sanitizeAndFormatExcerptSnippet protected function
SearchApiSolrService::sanitizeHighlightValue protected function Sanitizes a highlighted field value.
SearchApiSolrService::scheduleCommit public function Schedules a commit operation for this server.
SearchApiSolrService::search public function Executes a search on the server represented by this object. Overrides SearchApiServiceInterface::search
SearchApiSolrService::searchMultiple public function Implements SearchApiMultiServiceInterface::searchMultiple().
SearchApiSolrService::setConnectionClass public function Sets the Solr connection class used by this service.
SearchApiSolrService::setRequestHandler protected function Sets the request handler.
SearchApiSolrService::SOLR_DATE_FORMAT constant The date format that Solr uses, in PHP date() syntax.
SearchApiSolrService::supportsFeature public function Implements SearchApiServiceInterface::__construct(). Overrides SearchApiAbstractService::supportsFeature