updated search_api, search_api_solr_override, imce
This commit is contained in:
		@@ -4,9 +4,9 @@ core = "7.x"
 | 
			
		||||
package = "Media"
 | 
			
		||||
configure = "admin/config/media/imce"
 | 
			
		||||
 | 
			
		||||
; Information added by Drupal.org packaging script on 2016-03-30
 | 
			
		||||
version = "7.x-1.10"
 | 
			
		||||
; Information added by Drupal.org packaging script on 2017-05-27
 | 
			
		||||
version = "7.x-1.11"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "imce"
 | 
			
		||||
datestamp = "1459346870"
 | 
			
		||||
datestamp = "1495890787"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -25,6 +25,7 @@ function imce_uninstall() {
 | 
			
		||||
  variable_del('imce_settings_replace');
 | 
			
		||||
  variable_del('imce_settings_thumb_method');
 | 
			
		||||
  variable_del('imce_settings_disable_private');
 | 
			
		||||
  variable_del('imce_settings_admin_theme');
 | 
			
		||||
  variable_del('imce_custom_content');
 | 
			
		||||
  variable_del('imce_custom_process');
 | 
			
		||||
  variable_del('imce_custom_init');
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,20 @@ function imce_menu() {
 | 
			
		||||
  return $items;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_admin_paths().
 | 
			
		||||
 */
 | 
			
		||||
function imce_admin_paths() {
 | 
			
		||||
  if (variable_get('imce_settings_admin_theme', FALSE)) {
 | 
			
		||||
    return array(
 | 
			
		||||
      'imce' => TRUE,
 | 
			
		||||
      'imce/*' => TRUE,
 | 
			
		||||
      'file/imce/*' => TRUE,
 | 
			
		||||
      'imce-filefield/*' => TRUE,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_permission().
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -109,6 +109,12 @@ function imce_admin_form($form, &$form_state) {
 | 
			
		||||
    '#default_value' => variable_get('imce_settings_disable_private', 1),
 | 
			
		||||
    '#description' => t('IMCE serves all files under private files directory without applying any access restrictions. This allows anonymous access to any file(/system/files/filename) unless there is a module restricting access to the files. Here you can disable this feature.'),
 | 
			
		||||
  );
 | 
			
		||||
  $form['common']['admin_theme'] = array(
 | 
			
		||||
    '#type' => 'checkbox',
 | 
			
		||||
    '#title' => t('Use admin theme for IMCE paths'),
 | 
			
		||||
    '#default_value' => variable_get('imce_settings_admin_theme', FALSE),
 | 
			
		||||
    '#description' => t('If you have user interface issues with the active theme you may consider switching to admin theme.'),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  $form['submit'] = array('#type' => 'submit', '#value' => t('Save configuration'));
 | 
			
		||||
  $form['#theme'] = 'imce_admin';
 | 
			
		||||
@@ -183,6 +189,7 @@ function imce_admin_submit($form, &$form_state) {
 | 
			
		||||
  variable_set('imce_settings_replace', $form_state['values']['replace']);
 | 
			
		||||
  variable_set('imce_settings_thumb_method', $form_state['values']['thumb_method']);
 | 
			
		||||
  variable_set('imce_settings_disable_private', $form_state['values']['disable_private']);
 | 
			
		||||
  variable_set('imce_settings_admin_theme', $form_state['values']['admin_theme']);
 | 
			
		||||
  drupal_set_message(t('Changes have been saved.'));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -801,12 +801,17 @@ updateUI: function() {
 | 
			
		||||
  if (furl.charAt(furl.length - 1) != '/') {
 | 
			
		||||
    furl = imce.conf.furl = furl + '/';
 | 
			
		||||
  }
 | 
			
		||||
  imce.conf.modfix = imce.conf.clean && furl.indexOf(host + '/system/') > -1;
 | 
			
		||||
  imce.conf.modfix = imce.conf.clean && furl.split('/')[3] === 'system';
 | 
			
		||||
  if (absurls && !isabs) {
 | 
			
		||||
    imce.conf.furl = baseurl + furl;
 | 
			
		||||
  }
 | 
			
		||||
  else if (!absurls && isabs && furl.indexOf(baseurl) == 0) {
 | 
			
		||||
    imce.conf.furl = furl.substr(baseurl.length);
 | 
			
		||||
    furl = furl.substr(baseurl.length);
 | 
			
		||||
    // Server base url is defined with a port which is missing in current page url.
 | 
			
		||||
    if (furl.charAt(0) === ':') {
 | 
			
		||||
      furl = furl.replace(/^:\d*/, '');
 | 
			
		||||
    }
 | 
			
		||||
    imce.conf.furl = furl;
 | 
			
		||||
  }
 | 
			
		||||
  //convert button elements to input elements.
 | 
			
		||||
  imce.convertButtons(imce.FW);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,3 +1,83 @@
 | 
			
		||||
Search API 1.26 (2019-03-11):
 | 
			
		||||
-----------------------------
 | 
			
		||||
- #2324023 by drumm, drunken monkey: Changed Views field definition for to
 | 
			
		||||
  float.
 | 
			
		||||
- #3008849 by pamatt, drunken monkey: Fixed non-exposed numeric and date
 | 
			
		||||
  filters in Views.
 | 
			
		||||
- #3009744 by evgeny.chernyavskiy, drunken monkey: Fixed wrong "continue" in
 | 
			
		||||
  search_api_server_tasks_check().
 | 
			
		||||
- #3003742 by Jelle_S, drunken monkey: Fixed problems with Views date filters.
 | 
			
		||||
- #3002043 by alonaoneill, drunken monkey: Fixed module name capitalization and
 | 
			
		||||
  dependency namespacing in .info files.
 | 
			
		||||
- #2990940 by drunken monkey: Fixed multi-byte handling of Highlight processor.
 | 
			
		||||
- #3001424 by drunken monkey: Fixed notice when configuring the More Like This
 | 
			
		||||
  contextual filter.
 | 
			
		||||
 | 
			
		||||
Search API 1.25 (2018-09-17):
 | 
			
		||||
-----------------------------
 | 
			
		||||
- #2408727 by swim, drunken monkey: Added a batch operation for executing
 | 
			
		||||
  pending tasks.
 | 
			
		||||
- #2325917 by guillaumev, drunken monkey: Added a Views cache plugin based on
 | 
			
		||||
  Views Content Cache.
 | 
			
		||||
- #2989578 by KarlShea, drunken monkey: Fixed Views exposed form fields for
 | 
			
		||||
  "not between" operator.
 | 
			
		||||
- #2982167 by osopolar, drunken monkey: Added a Drush command for re-indexing
 | 
			
		||||
  specific entities.
 | 
			
		||||
- #1783746 by das-peter, sammys, SpadXIII, drunken monkey, ruloweb, KarlShea,
 | 
			
		||||
  heshanlk, Anas_maw, pinkonomy, Damien Tournoud, rudiedirkx: Added support
 | 
			
		||||
  for the "(not) between" operator.
 | 
			
		||||
- #2408727 by drunken monkey, OliverColeman: Fixed out-of-memory errors when
 | 
			
		||||
  executing pending tasks.
 | 
			
		||||
-  Issue #2948820 by capysara, drunken monkey: Added a link to the "need to
 | 
			
		||||
  reindex" message on the Filters tab.
 | 
			
		||||
- #2828883 by JorgenSandstrom, drunken monkey: Fixed property type for
 | 
			
		||||
  string-typed aggregated fields.
 | 
			
		||||
- #2949899 by drunken monkey, DamienMcKenna: Added a warning against using
 | 
			
		||||
  particular processors with Solr servers to the "Workflow" tab.
 | 
			
		||||
 | 
			
		||||
Search API 1.24 (2018-04-05):
 | 
			
		||||
-----------------------------
 | 
			
		||||
- #2958201 by jcnventura, drunken monkey: Reverted issue #2566529: Added
 | 
			
		||||
  support for the "Content access" processor for "Multiple types" indexes.
 | 
			
		||||
 | 
			
		||||
Search API 1.23 (2018-03-31):
 | 
			
		||||
-----------------------------
 | 
			
		||||
- #2949562 by DamienMcKenna, drunken monkey: Fixed stemming of multi-word
 | 
			
		||||
  tokens.
 | 
			
		||||
- #1903004 by AndyF, joseph.olstad, drunken monkey: Fixed errors at feature
 | 
			
		||||
  module installation in certain edge cases.
 | 
			
		||||
- #2889989 by kevineinarsson, drunken monkey, kristofferwiklund: Fixed
 | 
			
		||||
  highlighting for text with multi-byte characters.
 | 
			
		||||
- #1393064 by xlyz, drunken monkey, jannis: Fixed handling of empty facet
 | 
			
		||||
  filters.
 | 
			
		||||
- #2927692 by drunken monkey, Kristi Wachter: Fixed exposed grouped Views
 | 
			
		||||
  options filters.
 | 
			
		||||
- #2928769 by jannis, drunken monkey: Fixed Views cache not being cleared when
 | 
			
		||||
  enabling indexes.
 | 
			
		||||
- #2566529 by Dylan Donkersgoed, drunken monkey, joachim, swirt: Added support
 | 
			
		||||
  for the "Content access" processor for "Multiple types" indexes.
 | 
			
		||||
- #2905445 by ciss, drunken monkey: Fixed error handling in Views term filter
 | 
			
		||||
  handler.
 | 
			
		||||
- #2904268 by pobster, drunken monkey: Added support for language hierarchy in
 | 
			
		||||
  Views.
 | 
			
		||||
 | 
			
		||||
Search API 1.22 (2017-07-18):
 | 
			
		||||
-----------------------------
 | 
			
		||||
- #1710212 by drunken monkey: Added a data alteration for indexing a user's
 | 
			
		||||
  content.
 | 
			
		||||
- #2879892 by blacklabel_tom, drunken monkey: Fixed link in description of
 | 
			
		||||
  "Stemmer" processor.
 | 
			
		||||
- #2788593 by drunken monkey: Fixed error in Views query settings for specific
 | 
			
		||||
  setups.
 | 
			
		||||
- #2749963 by drunken monkey: Fixed "Index hierarchy" not having values
 | 
			
		||||
  numerically indexed.
 | 
			
		||||
- #2875793 by drunken monkey: Fixed buggy error handling in Views.
 | 
			
		||||
- #2860624 by drunken monkey: Fixed problem with empty words in Views fulltext
 | 
			
		||||
  filter.
 | 
			
		||||
- #2855447 by mparker17, drunken monkey: Added "Separator" option for
 | 
			
		||||
  aggregated fields of type "Fulltext".
 | 
			
		||||
- #2863445 by dbjpanda, drunken monkey: Fixed phrasing in README.txt.
 | 
			
		||||
 | 
			
		||||
Search API 1.21 (2017-02-23):
 | 
			
		||||
-----------------------------
 | 
			
		||||
- #2780341 by Berdir: Fixed passing of custom ranges to date facets.
 | 
			
		||||
 
 | 
			
		||||
@@ -31,9 +31,9 @@ Terms as used in this module.
 | 
			
		||||
  Sphinx or any other professional or simple indexing mechanism. Takes care of
 | 
			
		||||
  the details of all operations, especially indexing or searching content.
 | 
			
		||||
- Server:
 | 
			
		||||
  One specific place for indexing data, using a set service class. Can
 | 
			
		||||
  e.g. be some tables in a database, a connection to a Solr server or other
 | 
			
		||||
  external services, etc.
 | 
			
		||||
  One specific place for indexing data, using a specific service class. For
 | 
			
		||||
  example this could be some tables in a database, a connection to a Solr server
 | 
			
		||||
  or other external services, etc.
 | 
			
		||||
- Index:
 | 
			
		||||
  A configuration object for indexing data of a specific type. What and how data
 | 
			
		||||
  is indexed is determined by its settings. Also keeps track of which items
 | 
			
		||||
 
 | 
			
		||||
@@ -115,7 +115,7 @@ class SearchApiFacetapiTerm extends FacetapiQueryType implements FacetapiQueryTy
 | 
			
		||||
    if ($filter == '!') {
 | 
			
		||||
      $query_filter->condition($field, NULL, $exclude ? '<>' : '=');
 | 
			
		||||
    }
 | 
			
		||||
    elseif ($filter[0] == '[' && $filter[strlen($filter) - 1] == ']' && ($pos = strpos($filter, ' TO '))) {
 | 
			
		||||
    elseif ($filter && $filter[0] == '[' && $filter[strlen($filter) - 1] == ']' && ($pos = strpos($filter, ' TO '))) {
 | 
			
		||||
      $lower = trim(substr($filter, 1, $pos));
 | 
			
		||||
      $upper = trim(substr($filter, $pos + 4, -1));
 | 
			
		||||
      if ($lower == '*' && $upper == '*') {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
name = Search facets
 | 
			
		||||
name = Search Facets
 | 
			
		||||
description = "Integrate the Search API with the Facet API to provide facetted searches."
 | 
			
		||||
dependencies[] = search_api
 | 
			
		||||
dependencies[] = facetapi
 | 
			
		||||
dependencies[] = search_api:search_api
 | 
			
		||||
dependencies[] = facetapi:facetapi
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Search
 | 
			
		||||
 | 
			
		||||
@@ -9,9 +9,8 @@ files[] = plugins/facetapi/adapter.inc
 | 
			
		||||
files[] = plugins/facetapi/query_type_term.inc
 | 
			
		||||
files[] = plugins/facetapi/query_type_date.inc
 | 
			
		||||
 | 
			
		||||
; Information added by Drupal.org packaging script on 2017-02-23
 | 
			
		||||
version = "7.x-1.21"
 | 
			
		||||
; Information added by Drupal.org packaging script on 2019-03-11
 | 
			
		||||
version = "7.x-1.26"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "search_api"
 | 
			
		||||
datestamp = "1487844493"
 | 
			
		||||
 | 
			
		||||
datestamp = "1552334832"
 | 
			
		||||
 
 | 
			
		||||
@@ -40,6 +40,21 @@ in that position. If the query is sorted in this way, then the
 | 
			
		||||
random sort, as an associative array with any of the following keys:
 | 
			
		||||
- seed: A numeric seed value to use for the random sort.
 | 
			
		||||
 | 
			
		||||
"BETWEEN operator" feature
 | 
			
		||||
--------------------------
 | 
			
		||||
This module defines the "BETWEEN operator" feature (feature key:
 | 
			
		||||
"search_api_between") that adds the "BETWEEN" and "NOT BETWEEN" filter
 | 
			
		||||
operators to search queries. If your search server supports this feature, you
 | 
			
		||||
can use the "Is between" and "Is not between" operators when adding Views
 | 
			
		||||
filters for numeric, string or date types.
 | 
			
		||||
 | 
			
		||||
For developers:
 | 
			
		||||
A service class that wants to support this feature has to accept "BETWEEN" and
 | 
			
		||||
"NOT BETWEEN" as additional $operator values in query conditions. The value in
 | 
			
		||||
both cases is an array with the keys 0 and 1, with the value under key 0 being
 | 
			
		||||
the lower and the value under key 1 being the upper bound for the range in which
 | 
			
		||||
the field's value should ("BETWEEN") or should not ("NOT BETWEEN") be.
 | 
			
		||||
 | 
			
		||||
"Facets block" display
 | 
			
		||||
----------------------
 | 
			
		||||
Most features should be clear to users of Views. However, the module also
 | 
			
		||||
 
 | 
			
		||||
@@ -79,8 +79,8 @@ class SearchApiViewsHandlerArgument extends views_handler_argument {
 | 
			
		||||
  public function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
 | 
			
		||||
    $options['break_phrase'] = array('default' => FALSE);
 | 
			
		||||
    $options['not'] = array('default' => FALSE);
 | 
			
		||||
    $options['break_phrase'] = array('default' => FALSE, 'bool' => TRUE);
 | 
			
		||||
    $options['not'] = array('default' => FALSE, 'bool' => TRUE);
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,6 @@ class SearchApiViewsHandlerArgumentMoreLikeThis extends SearchApiViewsHandlerArg
 | 
			
		||||
   */
 | 
			
		||||
  public function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
    unset($options['break_phrase']);
 | 
			
		||||
    unset($options['not']);
 | 
			
		||||
    $options['entity_type'] = array('default' => FALSE);
 | 
			
		||||
    $options['fields'] = array('default' => array());
 | 
			
		||||
    return $options;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,9 +6,9 @@
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Views filter handler base class for handling all "normal" cases.
 | 
			
		||||
 * Views filter handler base class for handling date fields.
 | 
			
		||||
 */
 | 
			
		||||
class SearchApiViewsHandlerFilterDate extends SearchApiViewsHandlerFilter {
 | 
			
		||||
class SearchApiViewsHandlerFilterDate extends SearchApiViewsHandlerFilterNumeric {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Add a "widget type" option.
 | 
			
		||||
@@ -88,9 +88,22 @@ class SearchApiViewsHandlerFilterDate extends SearchApiViewsHandlerFilter {
 | 
			
		||||
  public function value_form(&$form, &$form_state) {
 | 
			
		||||
    parent::value_form($form, $form_state);
 | 
			
		||||
 | 
			
		||||
    $is_date_popup = ($this->options['widget_type'] == 'date_popup' && module_exists('date_popup'));
 | 
			
		||||
 | 
			
		||||
    // If the operator is between
 | 
			
		||||
    if ($this->operator == 'between') {
 | 
			
		||||
      if ($is_date_popup) {
 | 
			
		||||
        $form['value']['min']['#type'] = 'date_popup';
 | 
			
		||||
        $form['value']['min']['#date_format'] =  $this->options['date_popup_format'];
 | 
			
		||||
        $form['value']['min']['#date_year_range'] = $this->options['year_range'];
 | 
			
		||||
        $form['value']['max']['#type'] = 'date_popup';
 | 
			
		||||
        $form['value']['max']['#date_format'] =  $this->options['date_popup_format'];
 | 
			
		||||
        $form['value']['max']['#date_year_range'] = $this->options['year_range'];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // If we are using the date popup widget, overwrite the settings of the form
 | 
			
		||||
    // according to what date_popup expects.
 | 
			
		||||
    if ($this->options['widget_type'] == 'date_popup' && module_exists('date_popup')) {
 | 
			
		||||
    elseif ($is_date_popup) {
 | 
			
		||||
      $form['value']['#type'] = 'date_popup';
 | 
			
		||||
      $form['value']['#date_format'] =  $this->options['date_popup_format'];
 | 
			
		||||
      $form['value']['#date_year_range'] = $this->options['year_range'];
 | 
			
		||||
@@ -109,17 +122,38 @@ class SearchApiViewsHandlerFilterDate extends SearchApiViewsHandlerFilter {
 | 
			
		||||
   * Add this filter to the query.
 | 
			
		||||
   */
 | 
			
		||||
  public function query() {
 | 
			
		||||
    $this->normalizeValue();
 | 
			
		||||
 | 
			
		||||
    if ($this->operator === 'empty') {
 | 
			
		||||
      $this->query->condition($this->real_field, NULL, '=', $this->options['group']);
 | 
			
		||||
    }
 | 
			
		||||
    elseif ($this->operator === 'not empty') {
 | 
			
		||||
      $this->query->condition($this->real_field, NULL, '<>', $this->options['group']);
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      while (is_array($this->value)) {
 | 
			
		||||
        $this->value = $this->value ? reset($this->value) : NULL;
 | 
			
		||||
    elseif (in_array($this->operator, array('between', 'not between'), TRUE)) {
 | 
			
		||||
      $min = $this->value['min'];
 | 
			
		||||
      if ($min !== '') {
 | 
			
		||||
        $min = is_numeric($min) ? $min : strtotime($min, REQUEST_TIME);
 | 
			
		||||
      }
 | 
			
		||||
      $v = is_numeric($this->value) ? $this->value : strtotime($this->value, REQUEST_TIME);
 | 
			
		||||
      $max = $this->value['max'];
 | 
			
		||||
      if ($max !== '') {
 | 
			
		||||
        $max = is_numeric($max) ? $max : strtotime($max, REQUEST_TIME);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (is_numeric($min) && is_numeric($max)) {
 | 
			
		||||
        $this->query->condition($this->real_field, array($min, $max), strtoupper($this->operator), $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
      elseif (is_numeric($min)) {
 | 
			
		||||
        $operator = $this->operator === 'between' ? '>=' : '<';
 | 
			
		||||
        $this->query->condition($this->real_field, $min, $operator, $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
      elseif (is_numeric($max)) {
 | 
			
		||||
        $operator = $this->operator === 'between' ? '<=' : '>';
 | 
			
		||||
        $this->query->condition($this->real_field, $min, $operator, $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      $v = is_numeric($this->value['value']) ? $this->value['value'] : strtotime($this->value['value'], REQUEST_TIME);
 | 
			
		||||
      if ($v !== FALSE) {
 | 
			
		||||
        $this->query->condition($this->real_field, $v, $this->operator, $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
 
 | 
			
		||||
@@ -121,6 +121,11 @@ class SearchApiViewsHandlerFilterFulltext extends SearchApiViewsHandlerFilterTex
 | 
			
		||||
    $words = preg_split('/\s+/', $input);
 | 
			
		||||
    $quoted = FALSE;
 | 
			
		||||
    foreach ($words as $i => $word) {
 | 
			
		||||
      $word_length = drupal_strlen($word);
 | 
			
		||||
      if (!$word_length) {
 | 
			
		||||
        unset($words[$i]);
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      // Protect quoted strings.
 | 
			
		||||
      if ($quoted && $word[strlen($word) - 1] === '"') {
 | 
			
		||||
        $quoted = FALSE;
 | 
			
		||||
@@ -130,7 +135,7 @@ class SearchApiViewsHandlerFilterFulltext extends SearchApiViewsHandlerFilterTex
 | 
			
		||||
        $quoted = TRUE;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      if (drupal_strlen($word) < $this->options['min_length']) {
 | 
			
		||||
      if ($word_length < $this->options['min_length']) {
 | 
			
		||||
        unset($words[$i]);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -18,10 +18,13 @@ class SearchApiViewsHandlerFilterLanguage extends SearchApiViewsHandlerFilterOpt
 | 
			
		||||
   */
 | 
			
		||||
  protected function get_value_options() {
 | 
			
		||||
    parent::get_value_options();
 | 
			
		||||
    $this->value_options = array(
 | 
			
		||||
      'current' => t("Current user's language"),
 | 
			
		||||
      'default' => t('Default site language'),
 | 
			
		||||
    ) + $this->value_options;
 | 
			
		||||
    $options = array();
 | 
			
		||||
    if (module_exists('language_hierarchy')) {
 | 
			
		||||
      $options['fallback'] = t("Current user's language with fallback");
 | 
			
		||||
    }
 | 
			
		||||
    $options['current'] = t("Current user's language");
 | 
			
		||||
    $options['default'] = t('Default site language');
 | 
			
		||||
    $this->value_options = $options + $this->value_options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -40,6 +43,11 @@ class SearchApiViewsHandlerFilterLanguage extends SearchApiViewsHandlerFilterOpt
 | 
			
		||||
      elseif ($v == 'default') {
 | 
			
		||||
        $this->value[$i] = language_default('language');
 | 
			
		||||
      }
 | 
			
		||||
      elseif ($v == 'fallback' && module_exists('language_hierarchy')) {
 | 
			
		||||
        $fallbacks = array($language_content->language => $language_content->language);
 | 
			
		||||
        $fallbacks += array_keys(language_hierarchy_get_ancestors($language_content->language));
 | 
			
		||||
        $this->value[$i] = drupal_map_assoc($fallbacks);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    parent::query();
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,248 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Contains SearchApiViewsHandlerFilterNumeric.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Views filter handler class for handling numeric and "string" fields.
 | 
			
		||||
 */
 | 
			
		||||
class SearchApiViewsHandlerFilterNumeric extends SearchApiViewsHandlerFilter {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function init(&$view, &$options) {
 | 
			
		||||
    parent::init($view, $options);
 | 
			
		||||
 | 
			
		||||
    $this->normalizeValue();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
    $options['value'] = array(
 | 
			
		||||
      'contains' => array(
 | 
			
		||||
        'value' => array('default' => ''),
 | 
			
		||||
        'min' => array('default' => ''),
 | 
			
		||||
        'max' => array('default' => ''),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function operator_options() {
 | 
			
		||||
    $operators = parent::operator_options();
 | 
			
		||||
 | 
			
		||||
    $index = search_api_index_load(substr($this->table, 17));
 | 
			
		||||
    $server = NULL;
 | 
			
		||||
    try {
 | 
			
		||||
      if ($index) {
 | 
			
		||||
        $server = $index->server();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    catch (SearchApiException $e) {
 | 
			
		||||
      // Ignore.
 | 
			
		||||
    }
 | 
			
		||||
    if ($server && $server->supportsFeature('search_api_between')) {
 | 
			
		||||
      $operators += array(
 | 
			
		||||
        'between' => t('Is between'),
 | 
			
		||||
        'not between' => t('Is not between'),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $operators;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Provides a form for setting the filter value.
 | 
			
		||||
   *
 | 
			
		||||
   * Heavily borrowed from views_handler_filter_numeric.
 | 
			
		||||
   *
 | 
			
		||||
   * @see views_handler_filter_numeric::value_form()
 | 
			
		||||
   */
 | 
			
		||||
  public function value_form(&$form, &$form_state) {
 | 
			
		||||
    $form['value']['#tree'] = TRUE;
 | 
			
		||||
 | 
			
		||||
    $single_field_operators = $this->operator_options();
 | 
			
		||||
    unset(
 | 
			
		||||
      $single_field_operators['empty'],
 | 
			
		||||
      $single_field_operators['not empty'],
 | 
			
		||||
      $single_field_operators['between'],
 | 
			
		||||
      $single_field_operators['not between']
 | 
			
		||||
    );
 | 
			
		||||
    $between_operators = array('between', 'not between');
 | 
			
		||||
 | 
			
		||||
    // We have to make some choices when creating this as an exposed
 | 
			
		||||
    // filter form. For example, if the operator is locked and thus
 | 
			
		||||
    // not rendered, we can't render dependencies; instead we only
 | 
			
		||||
    // render the form items we need.
 | 
			
		||||
    $which = 'all';
 | 
			
		||||
    $source = NULL;
 | 
			
		||||
    if (!empty($form['operator'])) {
 | 
			
		||||
      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $identifier = NULL;
 | 
			
		||||
    if (!empty($form_state['exposed'])) {
 | 
			
		||||
      $identifier = $this->options['expose']['identifier'];
 | 
			
		||||
      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
 | 
			
		||||
        // Exposed and locked.
 | 
			
		||||
        $which = in_array($this->operator, $between_operators) ? 'minmax' : 'value';
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Hide the value box if the operator is 'empty' or 'not empty'.
 | 
			
		||||
    // Radios share the same selector so we have to add some dummy selector.
 | 
			
		||||
    if ($which == 'all') {
 | 
			
		||||
      $form['value']['value'] = array(
 | 
			
		||||
        '#type' => 'textfield',
 | 
			
		||||
        '#title' => empty($form_state['exposed']) ? t('Value') : '',
 | 
			
		||||
        '#size' => 30,
 | 
			
		||||
        '#default_value' => $this->value['value'],
 | 
			
		||||
        '#dependency' => array($source => array_keys($single_field_operators)),
 | 
			
		||||
      );
 | 
			
		||||
      if ($identifier && !isset($form_state['input'][$identifier]['value'])) {
 | 
			
		||||
        $form_state['input'][$identifier]['value'] = $this->value['value'];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    elseif ($which == 'value') {
 | 
			
		||||
      // When exposed we drop the value-value and just do value if
 | 
			
		||||
      // the operator is locked.
 | 
			
		||||
      $form['value'] = array(
 | 
			
		||||
        '#type' => 'textfield',
 | 
			
		||||
        '#title' => empty($form_state['exposed']) ? t('Value') : '',
 | 
			
		||||
        '#size' => 30,
 | 
			
		||||
        '#default_value' => isset($this->value['value']) ? $this->value['value'] : '',
 | 
			
		||||
      );
 | 
			
		||||
      if ($identifier && !isset($form_state['input'][$identifier])) {
 | 
			
		||||
        $form_state['input'][$identifier] = isset($this->value['value']) ? $this->value['value'] : '';
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($which == 'all' || $which == 'minmax') {
 | 
			
		||||
      $form['value']['min'] = array(
 | 
			
		||||
        '#type' => 'textfield',
 | 
			
		||||
        '#title' => empty($form_state['exposed']) ? t('Min') : '',
 | 
			
		||||
        '#size' => 30,
 | 
			
		||||
        '#default_value' => $this->value['min'],
 | 
			
		||||
      );
 | 
			
		||||
      $form['value']['max'] = array(
 | 
			
		||||
        '#type' => 'textfield',
 | 
			
		||||
        '#title' => empty($form_state['exposed']) ? t('And max') : t('And'),
 | 
			
		||||
        '#size' => 30,
 | 
			
		||||
        '#default_value' => $this->value['max'],
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      if ($which == 'all') {
 | 
			
		||||
        $form['value']['min']['#dependency'] = array($source => $between_operators);
 | 
			
		||||
        $form['value']['max']['#dependency'] = array($source => $between_operators);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['min'])) {
 | 
			
		||||
        $form_state['input'][$identifier]['min'] = $this->value['min'];
 | 
			
		||||
      }
 | 
			
		||||
      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier]['max'])) {
 | 
			
		||||
        $form_state['input'][$identifier]['max'] = $this->value['max'];
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!isset($form['value']['value'])) {
 | 
			
		||||
        // Ensure there is something in the 'value'.
 | 
			
		||||
        $form['value']['value'] = array(
 | 
			
		||||
          '#type' => 'value',
 | 
			
		||||
          '#value' => NULL,
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function admin_summary() {
 | 
			
		||||
    if (!empty($this->options['exposed'])) {
 | 
			
		||||
      return t('exposed');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ($this->operator === 'empty') {
 | 
			
		||||
      return t('is empty');
 | 
			
		||||
    }
 | 
			
		||||
    if ($this->operator === 'not empty') {
 | 
			
		||||
      return t('is not empty');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (in_array($this->operator, array('between', 'not between'), TRUE)) {
 | 
			
		||||
      // This is of course wrong for translation purposes, but copied from
 | 
			
		||||
      // views_handler_filter_numeric::admin_summary() so probably still better
 | 
			
		||||
      // to re-use this than to do it correctly.
 | 
			
		||||
      $operator = $this->operator === 'between' ? t('between') : t('not between');
 | 
			
		||||
      $vars = array(
 | 
			
		||||
        '@min' => (string) $this->value['min'],
 | 
			
		||||
        '@max' => (string) $this->value['max'],
 | 
			
		||||
      );
 | 
			
		||||
      return $operator . ' ' . t('@min and @max', $vars);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return check_plain((string) $this->operator) . ' ' . check_plain((string) $this->value['value']);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function query() {
 | 
			
		||||
    $this->normalizeValue();
 | 
			
		||||
 | 
			
		||||
    if (in_array($this->operator, array('between', 'not between'), TRUE)) {
 | 
			
		||||
      $min = $this->value['min'];
 | 
			
		||||
      $max = $this->value['max'];
 | 
			
		||||
      if ($min !== '' && $max !== '') {
 | 
			
		||||
        $this->query->condition($this->real_field, array($min, $max), strtoupper($this->operator), $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
      elseif ($min !== '') {
 | 
			
		||||
        $operator = $this->operator === 'between' ? '>=' : '<';
 | 
			
		||||
        $this->query->condition($this->real_field, $min, $operator, $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
      elseif ($max !== '') {
 | 
			
		||||
        $operator = $this->operator === 'between' ? '<=' : '>';
 | 
			
		||||
        $this->query->condition($this->real_field, $min, $operator, $this->options['group']);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
      // The parent handler doesn't expect our value structure, just pass the
 | 
			
		||||
      // scalar value instead.
 | 
			
		||||
      $this->value = $this->value['value'];
 | 
			
		||||
      parent::query();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Sets $this->value to an array of options as defined by the filter.
 | 
			
		||||
   *
 | 
			
		||||
   * @see SearchApiViewsHandlerFilterNumeric::option_definition()
 | 
			
		||||
   */
 | 
			
		||||
  protected function normalizeValue() {
 | 
			
		||||
    $value = $this->value;
 | 
			
		||||
    if (is_array($value) && isset($value[0])) {
 | 
			
		||||
      $value = $value[0];
 | 
			
		||||
    }
 | 
			
		||||
    if (!is_array($value)) {
 | 
			
		||||
      $value = array('value' => $value);
 | 
			
		||||
    }
 | 
			
		||||
    $this->value = array(
 | 
			
		||||
      'value' => isset($value['value']) ? $value['value'] : '',
 | 
			
		||||
      'min' => isset($value['min']) ? $value['min'] : '',
 | 
			
		||||
      'max' => isset($value['max']) ? $value['max'] : '',
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -121,6 +121,7 @@ class SearchApiViewsHandlerFilterOptions extends SearchApiViewsHandlerFilter {
 | 
			
		||||
   */
 | 
			
		||||
  public function option_definition() {
 | 
			
		||||
    $options = parent::option_definition();
 | 
			
		||||
    $options['value'] = array('default' => '');
 | 
			
		||||
    $options['expose']['contains']['reduce'] = array('default' => FALSE);
 | 
			
		||||
    return $options;
 | 
			
		||||
  }
 | 
			
		||||
@@ -256,6 +257,32 @@ class SearchApiViewsHandlerFilterOptions extends SearchApiViewsHandlerFilter {
 | 
			
		||||
    return $operator . (($values !== '') ? ' ' . $values : '');
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  function accept_exposed_input($input) {
 | 
			
		||||
    $accepted = parent::accept_exposed_input($input);
 | 
			
		||||
 | 
			
		||||
    // Grouped filters will have the raw form values structure from the
 | 
			
		||||
    // checkboxes as the value here. Convert that into the correct array of
 | 
			
		||||
    // values instead.
 | 
			
		||||
    if ($accepted && is_array($this->value) && $this->is_a_group()) {
 | 
			
		||||
      // For some reason, Views thinks it's a good idea to nest the form values
 | 
			
		||||
      // into a second array in some cases. That one will be numerically indexed
 | 
			
		||||
      // with just a single entry, though, so it should be relatively easy to
 | 
			
		||||
      // spot.
 | 
			
		||||
      if (count($this->value) && isset($this->value[0])) {
 | 
			
		||||
        $this->value = reset($this->value);
 | 
			
		||||
      }
 | 
			
		||||
      $this->value = array_keys(array_filter($this->value));
 | 
			
		||||
      if (!$this->value) {
 | 
			
		||||
        return FALSE;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $accepted;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Add this filter to the query.
 | 
			
		||||
   */
 | 
			
		||||
 
 | 
			
		||||
@@ -321,9 +321,13 @@ class SearchApiViewsHandlerFilterTaxonomyTerm extends SearchApiViewsHandlerFilte
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  protected function ids_to_strings(array $ids) {
 | 
			
		||||
    $ids = array_filter($ids);
 | 
			
		||||
    if (!$ids) {
 | 
			
		||||
      return '';
 | 
			
		||||
    }
 | 
			
		||||
    return implode(', ', db_select('taxonomy_term_data', 'td')
 | 
			
		||||
      ->fields('td', array('name'))
 | 
			
		||||
      ->condition('td.tid', array_filter($ids))
 | 
			
		||||
      ->condition('td.tid', $ids)
 | 
			
		||||
      ->execute()
 | 
			
		||||
      ->fetchCol());
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -35,11 +35,16 @@ class SearchApiViewsCache extends views_plugin_cache_time {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $cid = $this->get_results_key();
 | 
			
		||||
    $results = NULL;
 | 
			
		||||
    $query_plugin = $this->view->query;
 | 
			
		||||
    if ($query_plugin instanceof SearchApiViewsQuery) {
 | 
			
		||||
      $results = $query_plugin->getSearchApiResults();
 | 
			
		||||
    }
 | 
			
		||||
    $data = array(
 | 
			
		||||
      'result' => $this->view->result,
 | 
			
		||||
      'total_rows' => isset($this->view->total_rows) ? $this->view->total_rows : 0,
 | 
			
		||||
      'current_page' => $this->view->get_current_page(),
 | 
			
		||||
      'search_api results' => $this->view->query->getSearchApiResults(),
 | 
			
		||||
      'search_api results' => $results,
 | 
			
		||||
    );
 | 
			
		||||
    cache_set($cid, $data, $this->table, $this->cache_set_expire($type));
 | 
			
		||||
  }
 | 
			
		||||
@@ -80,7 +85,7 @@ class SearchApiViewsCache extends views_plugin_cache_time {
 | 
			
		||||
   * Overrides views_plugin_cache::get_cache_key().
 | 
			
		||||
   *
 | 
			
		||||
   * Use the Search API query as the main source for the key. Note that in
 | 
			
		||||
   * Views < 3.8, this function does not exist.
 | 
			
		||||
   * Views < 3.8, this method does not exist.
 | 
			
		||||
   */
 | 
			
		||||
  public function get_cache_key($key_data = array()) {
 | 
			
		||||
    global $user;
 | 
			
		||||
@@ -121,7 +126,7 @@ class SearchApiViewsCache extends views_plugin_cache_time {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Get the Search API query object associated with the current view.
 | 
			
		||||
   * Retrieves the Search API query object associated with the current view.
 | 
			
		||||
   *
 | 
			
		||||
   * @return SearchApiQueryInterface|null
 | 
			
		||||
   *   The Search API query object associated with the current view; or NULL if
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,146 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Contains the SearchApiViewsContentCache class.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Plugin class for caching Search API views, with additional invalidation.
 | 
			
		||||
 */
 | 
			
		||||
class SearchApiViewsContentCache extends views_content_cache_plugin_cache {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Static cache for get_results_key().
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $_results_key = NULL;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Static cache for getSearchApiQuery().
 | 
			
		||||
   *
 | 
			
		||||
   * @var SearchApiQueryInterface
 | 
			
		||||
   */
 | 
			
		||||
  protected $search_api_query = NULL;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides views_plugin_cache::cache_set().
 | 
			
		||||
   *
 | 
			
		||||
   * Also stores Search API's internal search results.
 | 
			
		||||
   */
 | 
			
		||||
  public function cache_set($type) {
 | 
			
		||||
    if ($type != 'results') {
 | 
			
		||||
      return parent::cache_set($type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $cid = $this->get_results_key();
 | 
			
		||||
    $results = NULL;
 | 
			
		||||
    $query_plugin = $this->view->query;
 | 
			
		||||
    if ($query_plugin instanceof SearchApiViewsQuery) {
 | 
			
		||||
      $results = $query_plugin->getSearchApiResults();
 | 
			
		||||
    }
 | 
			
		||||
    $data = array(
 | 
			
		||||
      'result' => $this->view->result,
 | 
			
		||||
      'total_rows' => isset($this->view->total_rows) ? $this->view->total_rows : 0,
 | 
			
		||||
      'current_page' => $this->view->get_current_page(),
 | 
			
		||||
      'search_api results' => $results,
 | 
			
		||||
    );
 | 
			
		||||
    cache_set($cid, $data, $this->table, $this->cache_set_expire($type));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides views_plugin_cache::cache_get().
 | 
			
		||||
   *
 | 
			
		||||
   * Additionally stores successfully retrieved results with
 | 
			
		||||
   * search_api_current_search().
 | 
			
		||||
   */
 | 
			
		||||
  public function cache_get($type) {
 | 
			
		||||
    if ($type != 'results') {
 | 
			
		||||
      return parent::cache_get($type);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Values to set: $view->result, $view->total_rows, $view->execute_time,
 | 
			
		||||
    // $view->current_page.
 | 
			
		||||
    if ($cache = cache_get($this->get_results_key(), $this->table)) {
 | 
			
		||||
      $cutoff = $this->cache_expire($type);
 | 
			
		||||
      if (!$cutoff || $cache->created > $cutoff) {
 | 
			
		||||
        $this->view->result = $cache->data['result'];
 | 
			
		||||
        $this->view->total_rows = $cache->data['total_rows'];
 | 
			
		||||
        $this->view->set_current_page($cache->data['current_page']);
 | 
			
		||||
        $this->view->execute_time = 0;
 | 
			
		||||
 | 
			
		||||
        // Trick Search API into believing a search happened, to make facetting
 | 
			
		||||
        // et al. work.
 | 
			
		||||
        $query = $this->getSearchApiQuery();
 | 
			
		||||
        search_api_current_search($query->getOption('search id'), $query, $cache->data['search_api results']);
 | 
			
		||||
 | 
			
		||||
        return TRUE;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides views_plugin_cache::get_cache_key().
 | 
			
		||||
   *
 | 
			
		||||
   * Use the Search API query as the main source for the key. Note that in
 | 
			
		||||
   * Views < 3.8, this method does not exist.
 | 
			
		||||
   */
 | 
			
		||||
  public function get_cache_key($key_data = array()) {
 | 
			
		||||
    global $user;
 | 
			
		||||
 | 
			
		||||
    if (!isset($this->_results_key)) {
 | 
			
		||||
      $query = $this->getSearchApiQuery();
 | 
			
		||||
      $query->preExecute();
 | 
			
		||||
      $key_data += array(
 | 
			
		||||
        'query' => $query,
 | 
			
		||||
        'roles' => array_keys($user->roles),
 | 
			
		||||
        'super-user' => $user->uid == 1, // special caching for super user.
 | 
			
		||||
        'language' => $GLOBALS['language']->language,
 | 
			
		||||
        'base_url' => $GLOBALS['base_url'],
 | 
			
		||||
        'offset' => $this->view->get_current_page() . '*' . $this->view->get_items_per_page() . '+' . $this->view->get_offset(),
 | 
			
		||||
      );
 | 
			
		||||
      // Not sure what gets passed in exposed_info, so better include it. All
 | 
			
		||||
      // other parameters used in the parent method are already reflected in the
 | 
			
		||||
      // Search API query object we use.
 | 
			
		||||
      if (isset($_GET['exposed_info'])) {
 | 
			
		||||
        $key_data['exposed_info'] = $_GET['exposed_info'];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $key = drupal_hash_base64(serialize($key_data));
 | 
			
		||||
    return $key;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Overrides views_plugin_cache::get_results_key().
 | 
			
		||||
   *
 | 
			
		||||
   * This is unnecessary for Views >= 3.8.
 | 
			
		||||
   */
 | 
			
		||||
  public function get_results_key() {
 | 
			
		||||
    if (!isset($this->_results_key)) {
 | 
			
		||||
      $this->_results_key = $this->view->name . ':' . $this->display->id . ':results:' . $this->get_cache_key();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $this->_results_key;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Retrieves the Search API query object associated with the current view.
 | 
			
		||||
   *
 | 
			
		||||
   * @return SearchApiQueryInterface|null
 | 
			
		||||
   *   The Search API query object associated with the current view; or NULL if
 | 
			
		||||
   *   there is none.
 | 
			
		||||
   */
 | 
			
		||||
  protected function getSearchApiQuery() {
 | 
			
		||||
    if (!isset($this->search_api_query)) {
 | 
			
		||||
      $this->search_api_query = FALSE;
 | 
			
		||||
      if (isset($this->view->query) && $this->view->query instanceof SearchApiViewsQuery) {
 | 
			
		||||
        $this->search_api_query = $this->view->query->getSearchApiQuery();
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return $this->search_api_query ? $this->search_api_query : NULL;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -135,7 +135,9 @@ class SearchApiViewsQuery extends views_plugin_query {
 | 
			
		||||
   *   The order to sort items in - either 'ASC' or 'DESC'. Defaults to 'ASC'.
 | 
			
		||||
   */
 | 
			
		||||
  public function add_selector_orderby($selector, $order = 'ASC') {
 | 
			
		||||
    $this->query->sort($selector, $order);
 | 
			
		||||
    if (!$this->errors) {
 | 
			
		||||
      $this->query->sort($selector, $order);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
@@ -213,7 +215,7 @@ class SearchApiViewsQuery extends views_plugin_query {
 | 
			
		||||
      '#default_value' => $this->options['search_api_bypass_access'],
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    if ($this->index->getEntityType()) {
 | 
			
		||||
    if ($this->index && $this->index->getEntityType()) {
 | 
			
		||||
      $form['entity_access'] = array(
 | 
			
		||||
        '#type' => 'checkbox',
 | 
			
		||||
        '#title' => t('Additional access checks on result entities'),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
name = Search views
 | 
			
		||||
name = Search Views
 | 
			
		||||
description = Integrates the Search API with Views, enabling users to create views with searches as filters or arguments.
 | 
			
		||||
dependencies[] = search_api
 | 
			
		||||
dependencies[] = views
 | 
			
		||||
dependencies[] = search_api:search_api
 | 
			
		||||
dependencies[] = views:views
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Search
 | 
			
		||||
 | 
			
		||||
@@ -19,17 +19,18 @@ files[] = includes/handler_filter_date.inc
 | 
			
		||||
files[] = includes/handler_filter_entity.inc
 | 
			
		||||
files[] = includes/handler_filter_fulltext.inc
 | 
			
		||||
files[] = includes/handler_filter_language.inc
 | 
			
		||||
files[] = includes/handler_filter_numeric.inc
 | 
			
		||||
files[] = includes/handler_filter_options.inc
 | 
			
		||||
files[] = includes/handler_filter_taxonomy_term.inc
 | 
			
		||||
files[] = includes/handler_filter_text.inc
 | 
			
		||||
files[] = includes/handler_filter_user.inc
 | 
			
		||||
files[] = includes/handler_sort.inc
 | 
			
		||||
files[] = includes/plugin_cache.inc
 | 
			
		||||
files[] = includes/plugin_content_cache.inc
 | 
			
		||||
files[] = includes/query.inc
 | 
			
		||||
 | 
			
		||||
; Information added by Drupal.org packaging script on 2017-02-23
 | 
			
		||||
version = "7.x-1.21"
 | 
			
		||||
; Information added by Drupal.org packaging script on 2019-03-11
 | 
			
		||||
version = "7.x-1.26"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "search_api"
 | 
			
		||||
datestamp = "1487844493"
 | 
			
		||||
 | 
			
		||||
datestamp = "1552334832"
 | 
			
		||||
 
 | 
			
		||||
@@ -27,8 +27,11 @@ function search_api_views_search_api_index_insert() {
 | 
			
		||||
 */
 | 
			
		||||
function search_api_views_search_api_index_update(SearchApiIndex $index) {
 | 
			
		||||
  // Check whether index was disabled.
 | 
			
		||||
  if (!$index->enabled && $index->original->enabled) {
 | 
			
		||||
  $is_enabled = $index->enabled;
 | 
			
		||||
  $was_enabled = $index->original->enabled;
 | 
			
		||||
  if (!$is_enabled && $was_enabled) {
 | 
			
		||||
    _search_api_views_index_unavailable($index);
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Check whether the indexed fields changed.
 | 
			
		||||
@@ -36,7 +39,9 @@ function search_api_views_search_api_index_update(SearchApiIndex $index) {
 | 
			
		||||
  $old_fields = $old_fields['fields'];
 | 
			
		||||
  $new_fields = $index->options + array('fields' => array());
 | 
			
		||||
  $new_fields = $new_fields['fields'];
 | 
			
		||||
  if ($old_fields != $new_fields) {
 | 
			
		||||
 | 
			
		||||
  // If the index was enabled or its fields changed, invalidate the Views cache.
 | 
			
		||||
  if ($is_enabled != $was_enabled || $old_fields != $new_fields) {
 | 
			
		||||
    views_invalidate_cache();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -99,6 +99,7 @@ function search_api_views_views_data() {
 | 
			
		||||
      $table['search_api_relevance']['title'] = t('Relevance');
 | 
			
		||||
      $table['search_api_relevance']['help'] = t('The relevance of this search result with respect to the query.');
 | 
			
		||||
      $table['search_api_relevance']['field']['type'] = 'decimal';
 | 
			
		||||
      $table['search_api_relevance']['field']['float'] = TRUE;
 | 
			
		||||
      $table['search_api_relevance']['field']['handler'] = 'entity_views_handler_field_numeric';
 | 
			
		||||
      $table['search_api_relevance']['field']['click sortable'] = TRUE;
 | 
			
		||||
      $table['search_api_relevance']['sort']['handler'] = 'SearchApiViewsHandlerSort';
 | 
			
		||||
@@ -219,6 +220,9 @@ function _search_api_views_add_handlers($id, array $field, EntityMetadataWrapper
 | 
			
		||||
      $table[$id]['filter']['vocabulary'] = $vocabulary;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  elseif (in_array($inner_type, array('integer', 'decimal', 'duration', 'string'))) {
 | 
			
		||||
    $table[$id]['filter']['handler'] = 'SearchApiViewsHandlerFilterNumeric';
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    $table[$id]['filter']['handler'] = 'SearchApiViewsHandlerFilter';
 | 
			
		||||
  }
 | 
			
		||||
@@ -285,6 +289,16 @@ function search_api_views_views_plugins() {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (module_exists('views_content_cache')) {
 | 
			
		||||
    $ret['cache']['search_api_views_content_cache'] = array(
 | 
			
		||||
      'title' => t('Search-specific content-based'),
 | 
			
		||||
      'help' => t("Cache Search API views based on content updates. (Requires Views Content Cache)"),
 | 
			
		||||
      'base' => $bases,
 | 
			
		||||
      'handler' => 'SearchApiViewsContentCache',
 | 
			
		||||
      'uses options' => TRUE,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -20,11 +20,23 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
 | 
			
		||||
   */
 | 
			
		||||
  protected $reductionType;
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * A separator to use when the aggregation type is 'fulltext'.
 | 
			
		||||
   *
 | 
			
		||||
   * Used to temporarily store a string separator when the aggregation type is
 | 
			
		||||
   * "fulltext", for use in SearchApiAlterAddAggregation::reduce() with
 | 
			
		||||
   * array_reduce().
 | 
			
		||||
   *
 | 
			
		||||
   * @var string
 | 
			
		||||
   */
 | 
			
		||||
  protected $fulltextReductionSeparator;
 | 
			
		||||
 | 
			
		||||
  public function configurationForm() {
 | 
			
		||||
    $form['#attached']['css'][] = drupal_get_path('module', 'search_api') . '/search_api.admin.css';
 | 
			
		||||
 | 
			
		||||
    $fields = $this->index->getFields(FALSE);
 | 
			
		||||
    $field_options = array();
 | 
			
		||||
    $field_properties = array();
 | 
			
		||||
    foreach ($fields as $name => $field) {
 | 
			
		||||
      $field_options[$name] = check_plain($field['name']);
 | 
			
		||||
      $field_properties[$name] = array(
 | 
			
		||||
@@ -79,9 +91,23 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
 | 
			
		||||
        '#required' => TRUE,
 | 
			
		||||
      );
 | 
			
		||||
      $form['fields'][$name]['type_descriptions'] = $type_descriptions;
 | 
			
		||||
      $type_selector = ':input[name="callbacks[search_api_alter_add_aggregation][settings][fields][' . $name . '][type]"]';
 | 
			
		||||
      foreach (array_keys($types) as $type) {
 | 
			
		||||
        $form['fields'][$name]['type_descriptions'][$type]['#states']['visible'][':input[name="callbacks[search_api_alter_add_aggregation][settings][fields][' . $name . '][type]"]']['value'] = $type;
 | 
			
		||||
        $form['fields'][$name]['type_descriptions'][$type]['#states']['visible'][$type_selector]['value'] = $type;
 | 
			
		||||
      }
 | 
			
		||||
      $form['fields'][$name]['separator'] = array(
 | 
			
		||||
        '#type' => 'textfield',
 | 
			
		||||
        '#title' => t('Fulltext separator'),
 | 
			
		||||
        '#description' => t('For aggregation type "Fulltext", set the text that should be used to separate the aggregated field values. Use "\t" for tabs and "\n" for newline characters.'),
 | 
			
		||||
        '#default_value' => addcslashes(isset($field['separator']) ? $field['separator'] : "\n\n", "\0..\37\\"),
 | 
			
		||||
        '#states' => array(
 | 
			
		||||
          'visible' => array(
 | 
			
		||||
            $type_selector => array(
 | 
			
		||||
              'value' => 'fulltext',
 | 
			
		||||
            ),
 | 
			
		||||
          ),
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
      $form['fields'][$name]['fields'] = array_merge($field_properties, array(
 | 
			
		||||
        '#type' => 'checkboxes',
 | 
			
		||||
        '#title' => t('Contained fields'),
 | 
			
		||||
@@ -125,11 +151,12 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    foreach ($values['fields'] as $name => $field) {
 | 
			
		||||
      $fields = $values['fields'][$name]['fields'] = array_values(array_filter($field['fields']));
 | 
			
		||||
      unset($values['fields'][$name]['actions']);
 | 
			
		||||
      $fields = $values['fields'][$name]['fields'] = array_values(array_filter($field['fields']));
 | 
			
		||||
      if ($field['name'] && !$fields) {
 | 
			
		||||
        form_error($form['fields'][$name]['fields'], t('You have to select at least one field to aggregate. If you want to remove an aggregated field, please delete its name.'));
 | 
			
		||||
      }
 | 
			
		||||
      $values['fields'][$name]['separator'] = stripcslashes($field['separator']);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -176,6 +203,7 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
 | 
			
		||||
            $values = $this->flattenArray($values);
 | 
			
		||||
 | 
			
		||||
            $this->reductionType = $field['type'];
 | 
			
		||||
            $this->fulltextReductionSeparator = isset($field['separator']) ? $field['separator'] : "\n\n";
 | 
			
		||||
            $item->$name = array_reduce($values, array($this, 'reduce'), NULL);
 | 
			
		||||
            if ($field['type'] == 'count' && !$item->$name) {
 | 
			
		||||
              $item->$name = 0;
 | 
			
		||||
@@ -192,7 +220,7 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
 | 
			
		||||
  public function reduce($a, $b) {
 | 
			
		||||
    switch ($this->reductionType) {
 | 
			
		||||
      case 'fulltext':
 | 
			
		||||
        return isset($a) ? $a . "\n\n" . $b : $b;
 | 
			
		||||
        return isset($a) ? $a . $this->fulltextReductionSeparator . $b : $b;
 | 
			
		||||
      case 'sum':
 | 
			
		||||
        return $a + $b;
 | 
			
		||||
      case 'count':
 | 
			
		||||
@@ -300,10 +328,10 @@ class SearchApiAlterAddAggregation extends SearchApiAbstractAlterCallback {
 | 
			
		||||
          'count' => 'integer',
 | 
			
		||||
          'max' => 'integer',
 | 
			
		||||
          'min' => 'integer',
 | 
			
		||||
          'first' => 'string',
 | 
			
		||||
          'first_char' => 'string',
 | 
			
		||||
          'last' => 'string',
 | 
			
		||||
          'list' => 'list<string>',
 | 
			
		||||
          'first' => 'token',
 | 
			
		||||
          'first_char' => 'token',
 | 
			
		||||
          'last' => 'token',
 | 
			
		||||
          'list' => 'list<token>',
 | 
			
		||||
        );
 | 
			
		||||
      case 'description':
 | 
			
		||||
        return array(
 | 
			
		||||
 
 | 
			
		||||
@@ -108,7 +108,7 @@ class SearchApiAlterAddHierarchy extends SearchApiAbstractAlterCallback {
 | 
			
		||||
        $this->extractHierarchy($child, $prop, $values[$key]);
 | 
			
		||||
      }
 | 
			
		||||
      foreach ($values as $key => $value) {
 | 
			
		||||
        $item->$key = $value;
 | 
			
		||||
        $item->$key = array_values($value);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,57 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Contains SearchApiAlterAddUserContent.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adds the nodes created by the indexed user for indexing.
 | 
			
		||||
 */
 | 
			
		||||
class SearchApiAlterAddUserContent extends SearchApiAbstractAlterCallback {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function supportsIndex(SearchApiIndex $index) {
 | 
			
		||||
    return $index->getEntityType() === 'user';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function propertyInfo() {
 | 
			
		||||
    return array(
 | 
			
		||||
      'search_api_user_content' => array(
 | 
			
		||||
        'label' => t('User content'),
 | 
			
		||||
        'description' => t('The nodes created by this user'),
 | 
			
		||||
        'type' => 'list<node>',
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function alterItems(array &$items) {
 | 
			
		||||
    $uids = array();
 | 
			
		||||
    foreach ($items as $item) {
 | 
			
		||||
      $uids[] = $item->uid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    $sql = 'SELECT nid, uid FROM {node} WHERE uid IN (:uids)';
 | 
			
		||||
    $nids = db_query($sql, array(':uids' => $uids));
 | 
			
		||||
    $user_nodes = array();
 | 
			
		||||
    foreach ($nids as $row) {
 | 
			
		||||
      $user_nodes[$row->uid][] = $row->nid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    foreach ($items as $item) {
 | 
			
		||||
      $item->search_api_user_content = array();
 | 
			
		||||
      if (!empty($user_nodes[$item->uid])) {
 | 
			
		||||
        $item->search_api_user_content = $user_nodes[$item->uid];
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -315,99 +315,141 @@ class SearchApiHighlight extends SearchApiAbstractProcessor {
 | 
			
		||||
   * @param array $keys
 | 
			
		||||
   *   Search keywords entered by the user.
 | 
			
		||||
   *
 | 
			
		||||
   * @return string
 | 
			
		||||
   *   A string containing HTML for the excerpt.
 | 
			
		||||
   * @return string|null
 | 
			
		||||
   *   A string containing HTML for the excerpt, or NULL if none could be
 | 
			
		||||
   *   created.
 | 
			
		||||
   */
 | 
			
		||||
  protected function createExcerpt($text, array $keys) {
 | 
			
		||||
    // Prepare text by stripping HTML tags and decoding HTML entities.
 | 
			
		||||
    $text = strip_tags(str_replace(array('<', '>'), array(' <', '> '), $text));
 | 
			
		||||
    $text = ' ' . decode_entities($text);
 | 
			
		||||
    $text = decode_entities($text);
 | 
			
		||||
    $text = preg_replace('/\s+/', ' ', $text);
 | 
			
		||||
    $text = trim($text, ' ');
 | 
			
		||||
    $text_length = strlen($text);
 | 
			
		||||
 | 
			
		||||
    // Extract fragments around keywords.
 | 
			
		||||
    // First we collect ranges of text around each keyword, starting/ending
 | 
			
		||||
    // at spaces, trying to get to the requested length.
 | 
			
		||||
    // If the sum of all fragments is too short, we look for second occurrences.
 | 
			
		||||
    // Try to reach the requested excerpt length with about two fragments (each
 | 
			
		||||
    // with a keyword and some context).
 | 
			
		||||
    $ranges = array();
 | 
			
		||||
    $included = array();
 | 
			
		||||
    $length = 0;
 | 
			
		||||
    $work_keys = $keys;
 | 
			
		||||
    while ($length < $this->options['excerpt_length'] && $work_keys) {
 | 
			
		||||
      foreach ($work_keys as $k => $key) {
 | 
			
		||||
        if ($length >= $this->options['excerpt_length']) {
 | 
			
		||||
    $look_start = array();
 | 
			
		||||
    $remaining_keys = $keys;
 | 
			
		||||
 | 
			
		||||
    // Get the set excerpt length from the configuration. If the length is too
 | 
			
		||||
    // small, only use one fragment.
 | 
			
		||||
    $excerpt_length = $this->options['excerpt_length'];
 | 
			
		||||
    $context_length = round($excerpt_length / 4) - 3;
 | 
			
		||||
    if ($context_length < 32) {
 | 
			
		||||
      $context_length = round($excerpt_length / 2) - 1;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    while ($length < $excerpt_length && !empty($remaining_keys)) {
 | 
			
		||||
      $found_keys = array();
 | 
			
		||||
      foreach ($remaining_keys as $key) {
 | 
			
		||||
        if ($length >= $excerpt_length) {
 | 
			
		||||
          break;
 | 
			
		||||
        }
 | 
			
		||||
        // Remember occurrence of key so we can skip over it if more occurrences
 | 
			
		||||
        // are desired.
 | 
			
		||||
        if (!isset($included[$key])) {
 | 
			
		||||
          $included[$key] = 0;
 | 
			
		||||
 | 
			
		||||
        // Remember where we last found $key, in case we are coming through a
 | 
			
		||||
        // second time.
 | 
			
		||||
        if (!isset($look_start[$key])) {
 | 
			
		||||
          $look_start[$key] = 0;
 | 
			
		||||
        }
 | 
			
		||||
        // Locate a keyword (position $p, always >0 because $text starts with a
 | 
			
		||||
        // space).
 | 
			
		||||
        $p = 0;
 | 
			
		||||
        if (empty($this->options['highlight_partial'])) {
 | 
			
		||||
          $regex = '/' . self::$boundary . preg_quote($key, '/') . self::$boundary . '/iu';
 | 
			
		||||
          if (preg_match($regex, $text, $match, PREG_OFFSET_CAPTURE, $included[$key])) {
 | 
			
		||||
            $p = $match[0][1];
 | 
			
		||||
 | 
			
		||||
        // See if we can find $key after where we found it the last time. Since
 | 
			
		||||
        // we are requiring a match on a word boundary, make sure $text starts
 | 
			
		||||
        // and ends with a space.
 | 
			
		||||
        $matches = array();
 | 
			
		||||
 | 
			
		||||
        if (!$this->options['highlight_partial']) {
 | 
			
		||||
          $found_position = FALSE;
 | 
			
		||||
          $regex = '/' . static::$boundary . preg_quote($key, '/') . static::$boundary . '/iu';
 | 
			
		||||
          if (preg_match($regex, ' ' . $text . ' ', $matches, PREG_OFFSET_CAPTURE, $look_start[$key])) {
 | 
			
		||||
            $found_position = $matches[0][1];
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
          $p = stripos($text, $key, $included[$key]);
 | 
			
		||||
          $found_position = stripos($text, $key, $look_start[$key]);
 | 
			
		||||
        }
 | 
			
		||||
        // Now locate a space in front (position $q) and behind it (position $s),
 | 
			
		||||
        // leaving about 60 characters extra before and after for context.
 | 
			
		||||
        // Note that a space was added to the front and end of $text above.
 | 
			
		||||
        if ($p) {
 | 
			
		||||
          if (($q = strpos(' ' . $text, ' ', max(0, $p - 61))) !== FALSE) {
 | 
			
		||||
            $end = substr($text . ' ', $p, 80);
 | 
			
		||||
            if (($s = strrpos($end, ' ')) !== FALSE) {
 | 
			
		||||
              // Account for the added spaces.
 | 
			
		||||
              $q = max($q - 1, 0);
 | 
			
		||||
              $s = min($s, strlen($end) - 1);
 | 
			
		||||
              $ranges[$q] = $p + $s;
 | 
			
		||||
              $length += $p + $s - $q;
 | 
			
		||||
              $included[$key] = $p + 1;
 | 
			
		||||
              continue;
 | 
			
		||||
        if ($found_position !== FALSE) {
 | 
			
		||||
          $look_start[$key] = $found_position + 1;
 | 
			
		||||
          // Keep track of which keys we found this time, in case we need to
 | 
			
		||||
          // pass through again to find more text.
 | 
			
		||||
          $found_keys[] = $key;
 | 
			
		||||
 | 
			
		||||
          // Locate a space before and after this match, leaving some context on
 | 
			
		||||
          // each end.
 | 
			
		||||
          if ($found_position > $context_length) {
 | 
			
		||||
            $before = strpos($text, ' ', $found_position - $context_length);
 | 
			
		||||
            if ($before !== FALSE) {
 | 
			
		||||
              ++$before;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          else {
 | 
			
		||||
            $before = 0;
 | 
			
		||||
          }
 | 
			
		||||
          if ($before !== FALSE && $before <= $found_position) {
 | 
			
		||||
            if ($text_length > $found_position + $context_length) {
 | 
			
		||||
              $after = strrpos(substr($text, 0, $found_position + $context_length), ' ', $found_position);
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
              $after = $text_length;
 | 
			
		||||
            }
 | 
			
		||||
            if ($after !== FALSE && $after > $found_position) {
 | 
			
		||||
              if ($before < $after) {
 | 
			
		||||
                // Save this range.
 | 
			
		||||
                $ranges[$before] = $after;
 | 
			
		||||
                $length += $after - $before;
 | 
			
		||||
              }
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        // Unless we got a match above, we don't need to look for this key any
 | 
			
		||||
        // more.
 | 
			
		||||
        unset($work_keys[$k]);
 | 
			
		||||
      }
 | 
			
		||||
      // Next time through this loop, only look for keys we found this time,
 | 
			
		||||
      // if any.
 | 
			
		||||
      $remaining_keys = $found_keys;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (count($ranges) == 0) {
 | 
			
		||||
      // We didn't find any keyword matches, so just return NULL.
 | 
			
		||||
    if (!$ranges) {
 | 
			
		||||
      // We didn't find any keyword matches, return NULL.
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Sort the text ranges by starting position.
 | 
			
		||||
    ksort($ranges);
 | 
			
		||||
 | 
			
		||||
    // Now we collapse overlapping text ranges into one. The sorting makes it O(n).
 | 
			
		||||
    // Collapse overlapping text ranges into one. The sorting makes it O(n).
 | 
			
		||||
    $newranges = array();
 | 
			
		||||
    $from1 = $to1 = NULL;
 | 
			
		||||
    foreach ($ranges as $from2 => $to2) {
 | 
			
		||||
      if (!isset($from1)) {
 | 
			
		||||
      if ($from1 === NULL) {
 | 
			
		||||
        // This is the first time through this loop: initialize.
 | 
			
		||||
        $from1 = $from2;
 | 
			
		||||
        $to1 = $to2;
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      if ($from2 <= $to1) {
 | 
			
		||||
        // The ranges overlap: combine them.
 | 
			
		||||
        $to1 = max($to1, $to2);
 | 
			
		||||
      }
 | 
			
		||||
      else {
 | 
			
		||||
        // The ranges do not overlap: save the working range and start a new
 | 
			
		||||
        // one.
 | 
			
		||||
        $newranges[$from1] = $to1;
 | 
			
		||||
        $from1 = $from2;
 | 
			
		||||
        $to1 = $to2;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    // Save the remaining working range.
 | 
			
		||||
    $newranges[$from1] = $to1;
 | 
			
		||||
 | 
			
		||||
    // Fetch text
 | 
			
		||||
    // Fetch text within the combined ranges we found.
 | 
			
		||||
    $out = array();
 | 
			
		||||
    foreach ($newranges as $from => $to) {
 | 
			
		||||
      $out[] = substr($text, $from, $to - $from);
 | 
			
		||||
    }
 | 
			
		||||
    if (!$out) {
 | 
			
		||||
      return NULL;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Let translators have the ... separator text as one chunk.
 | 
			
		||||
    $dots = explode('!excerpt', t('... !excerpt ... !excerpt ...'));
 | 
			
		||||
 
 | 
			
		||||
@@ -24,12 +24,11 @@ class SearchApiPorterStemmer extends SearchApiAbstractProcessor {
 | 
			
		||||
    $form = parent::configurationForm();
 | 
			
		||||
 | 
			
		||||
    $args = array(
 | 
			
		||||
      '!algorithm' => url('https://github.com/markfullmer/porter2'),
 | 
			
		||||
      '!exclusions' => url('https://github.com/markfullmer/porter2#user-content-custom-exclusions'),
 | 
			
		||||
      '@algorithm' => url('http://snowball.tartarus.org/algorithms/english/stemmer.html'),
 | 
			
		||||
    );
 | 
			
		||||
    $form += array(
 | 
			
		||||
      'help' => array(
 | 
			
		||||
        '#markup' => '<p>' . t('Optionally, provide an exclusion list to override the stemmer algorithm. Read about the <a href="@algorithm">algorithm</a> and <a href="@exclusions">exclusions</a>.', $args) . '</p>',
 | 
			
		||||
        '#markup' => '<p>' . t('Optionally, provide an exclusion list to override the stemmer algorithm. (<a href="@algorithm">Read about the algorithm</a>.)', $args) . '</p>',
 | 
			
		||||
      ),
 | 
			
		||||
      'exceptions' => array(
 | 
			
		||||
        '#type' => 'textarea',
 | 
			
		||||
@@ -66,7 +65,7 @@ class SearchApiPorterStemmer extends SearchApiAbstractProcessor {
 | 
			
		||||
        $stemmed[] = $word;
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    $value = implode('', $stemmed);
 | 
			
		||||
    $value = implode(' ', $stemmed);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
 
 | 
			
		||||
@@ -528,7 +528,7 @@ function theme_search_api_server(array $variables) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Form constructor for completely clearing a server.
 | 
			
		||||
 * Form constructor for server operations.
 | 
			
		||||
 *
 | 
			
		||||
 * @param SearchApiServer $server
 | 
			
		||||
 *   The server for which the form is displayed.
 | 
			
		||||
@@ -543,15 +543,39 @@ function search_api_server_status_form(array $form, array &$form_state, SearchAp
 | 
			
		||||
  $form['clear'] = array(
 | 
			
		||||
    '#type' => 'submit',
 | 
			
		||||
    '#value' => t('Delete all indexed data on this server'),
 | 
			
		||||
    '#submit' => array('search_api_server_status_form_clear_submit')
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  $count = $server->enabled ? search_api_server_tasks_count($server) : 0;
 | 
			
		||||
  if ($count) {
 | 
			
		||||
    $message = format_plural($count, '@count pending task must be executed before indexing.', '@count pending tasks must be executed before indexing.');
 | 
			
		||||
    drupal_set_message($message, 'warning', FALSE);
 | 
			
		||||
    $form['execute_pending_tasks'] = array(
 | 
			
		||||
      '#type' => 'submit',
 | 
			
		||||
      '#value' => t('Execute all pending tasks on this server'),
 | 
			
		||||
      '#submit' => array('search_api_server_status_form_execute_pending_tasks_submit')
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $form;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
* Form submission handler for search_api_server_status_form().
 | 
			
		||||
*/
 | 
			
		||||
function search_api_server_status_form_submit(array $form, array &$form_state) {
 | 
			
		||||
 * Form submission handler for search_api_server_status_form().
 | 
			
		||||
 *
 | 
			
		||||
 * Used for the "Execute all pending tasks" button.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_server_status_form_execute_pending_tasks_submit($form, &$form_state) {
 | 
			
		||||
  $server_id = $form_state['server']->machine_name;
 | 
			
		||||
  $form_state['redirect'] = "admin/config/search/search_api/server/$server_id/execute-tasks";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Form submission handler for search_api_server_status_form().
 | 
			
		||||
 *
 | 
			
		||||
 * Used for the "Delete all indexed data" button.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_server_status_form_clear_submit(array $form, array &$form_state) {
 | 
			
		||||
  $server_id = $form_state['server']->machine_name;
 | 
			
		||||
  $form_state['redirect'] = "admin/config/search/search_api/server/$server_id/clear";
 | 
			
		||||
}
 | 
			
		||||
@@ -1566,10 +1590,13 @@ function search_api_admin_index_workflow(array $form, array &$form_state, Search
 | 
			
		||||
  $form['processors'] = array(
 | 
			
		||||
    '#type' => 'fieldset',
 | 
			
		||||
    '#title' => t('Processors'),
 | 
			
		||||
    '#description' => t('Select processors which will pre- and post-process data at index and search time, and their order. ' .
 | 
			
		||||
        'Most processors will only influence fulltext fields, but refer to their individual descriptions for details regarding their effect.'),
 | 
			
		||||
    '#description' => '<p>' . t("Select processors which will pre- and post-process data at index and search time, and their order. Most processors will only influence fulltext fields, but refer to their individual descriptions for details regarding their effect.<br />Also, some processors shouldn't be used with more advanced search engines (like Solr or Elasticsearch), since the search engine already provides this functionality.") . '</p>',
 | 
			
		||||
    '#collapsible' => TRUE,
 | 
			
		||||
  );
 | 
			
		||||
  if ($index->server) {
 | 
			
		||||
    $form['processors']['#description'] .= '<p>' . t("Check the <a href='@server-url'>server's</a> service class description for details.",
 | 
			
		||||
        array('@server-url' => url('admin/config/search/search_api/server/' . $index->server . '/edit'))) . '</p>';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Processor status.
 | 
			
		||||
  $form['processors']['status'] = array(
 | 
			
		||||
@@ -1696,6 +1723,7 @@ function search_api_admin_index_workflow_submit(array $form, array &$form_state)
 | 
			
		||||
  unset($values['callbacks']['settings']);
 | 
			
		||||
  unset($values['processors']['settings']);
 | 
			
		||||
  $index = $form_state['index'];
 | 
			
		||||
  $index_path = 'admin/config/search/search_api/index/' . $index->machine_name;
 | 
			
		||||
 | 
			
		||||
  $options = empty($index->options) ? array() : $index->options;
 | 
			
		||||
 | 
			
		||||
@@ -1761,13 +1789,14 @@ function search_api_admin_index_workflow_submit(array $form, array &$form_state)
 | 
			
		||||
 | 
			
		||||
    $index->save();
 | 
			
		||||
    $index->reindex();
 | 
			
		||||
    drupal_set_message(t("The indexing workflow was successfully edited. All content was scheduled for re-indexing so the new settings can take effect."));
 | 
			
		||||
    $vars = array('@url' => url($index_path));
 | 
			
		||||
    drupal_set_message(t('The indexing workflow was successfully edited. All content was scheduled for <a href="@url">re-indexing</a> so the new settings can take effect.', $vars));
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    drupal_set_message(t('No values were changed.'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $form_state['redirect'] = 'admin/config/search/search_api/index/' . $index->machine_name . '/workflow';
 | 
			
		||||
  $form_state['redirect'] = $index_path . '/workflow';
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
@@ -1822,8 +1851,8 @@ function search_api_admin_index_fields(array $form, array &$form_state, SearchAp
 | 
			
		||||
        'In any case, fields of type "Fulltext" will always be fulltext-searchable.</p>'),
 | 
			
		||||
  );
 | 
			
		||||
  if ($index->server) {
 | 
			
		||||
    $form['description']['#description'] .= '<p>' . t('Check the <a href="@server-url">' . "server's</a> service class description for details.",
 | 
			
		||||
        array('@server-url' => url('admin/config/search/search_api/server/' . $index->server))) . '</p>';
 | 
			
		||||
    $form['description']['#description'] .= '<p>' . t("Check the <a href='@server-url'>server's</a> service class description for details.",
 | 
			
		||||
        array('@server-url' => url('admin/config/search/search_api/server/' . $index->server . '/edit'))) . '</p>';
 | 
			
		||||
  }
 | 
			
		||||
  foreach ($fields as $key => $info) {
 | 
			
		||||
    $form['fields'][$key]['title']['#markup'] = check_plain($info['name']);
 | 
			
		||||
 
 | 
			
		||||
@@ -95,6 +95,18 @@ function search_api_drush_command() {
 | 
			
		||||
    'aliases' => array('sapi-r'),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  $items['search-api-reindex-items'] = array(
 | 
			
		||||
    'description' => 'Force re-indexing of one or more specific items.',
 | 
			
		||||
    'examples' => array(
 | 
			
		||||
      'drush search-api-reindex-items node 12,34,56' => dt('Schedule the nodes with ID 12, 34 and 56 for re-indexing.'),
 | 
			
		||||
    ),
 | 
			
		||||
    'arguments' => array(
 | 
			
		||||
      'entity_type' => dt('The entity type whose items should be re-indexed.'),
 | 
			
		||||
      'entities' => dt('The entities of the given entity type to be re-indexed.'),
 | 
			
		||||
    ),
 | 
			
		||||
    'aliases' => array('sapi-ri'),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  $items['search-api-clear'] = array(
 | 
			
		||||
    'description' => 'Clear one or all search indexes and mark them for re-indexing.',
 | 
			
		||||
    'examples' => array(
 | 
			
		||||
@@ -109,6 +121,19 @@ function search_api_drush_command() {
 | 
			
		||||
    'aliases' => array('sapi-c'),
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  $items['search-api-execute-tasks'] = array(
 | 
			
		||||
    'description' => 'Execute all pending tasks or all for a given server.',
 | 
			
		||||
    'examples' => array(
 | 
			
		||||
      'drush search-api-execute-tasks my_solr_server' => dt('Execute all pending tasks on !server', array('!server' => 'my_solr_server')),
 | 
			
		||||
      'drush sapi-et my_solr_server' => dt('Execute all pending tasks on !server', array('!server' => 'my_solr_server')),
 | 
			
		||||
      'drush sapi-et' => dt('Execute all pending tasks on all servers.')
 | 
			
		||||
    ),
 | 
			
		||||
    'arguments' => array(
 | 
			
		||||
      'server_id' => dt('The numeric ID or machine name of a server to execute tasks on.'),
 | 
			
		||||
    ),
 | 
			
		||||
    'aliases' => array('sapi-et')
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  $items['search-api-set-index-server'] = array(
 | 
			
		||||
    'description' => 'Set the search server used by a given index.',
 | 
			
		||||
    'examples' => array(
 | 
			
		||||
@@ -448,6 +473,33 @@ function drush_search_api_reindex($index_id = NULL) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Marks the given entities as needing to be re-indexed.
 | 
			
		||||
 */
 | 
			
		||||
function drush_search_api_reindex_items($entity_type, $entities) {
 | 
			
		||||
  if (search_api_drush_static(__FUNCTION__)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Validate list of entity ids.
 | 
			
		||||
  if (!empty($entities) && !preg_match('#^[0-9]*(,[0-9]*)*$#', $entities)) {
 | 
			
		||||
    drush_log(dt('Entities should be a single numeric entity ID or a list with the numeric entity IDs separated by comma.'), 'error');
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $ids = explode(',', $entities);
 | 
			
		||||
 | 
			
		||||
  if (!empty($ids)) {
 | 
			
		||||
    search_api_track_item_change($entity_type, $ids);
 | 
			
		||||
 | 
			
		||||
    $combined_ids = array();
 | 
			
		||||
    foreach ($ids as $id) {
 | 
			
		||||
      $combined_ids[] = $entity_type . '/' . $id;
 | 
			
		||||
    }
 | 
			
		||||
    search_api_track_item_change('multiple', $combined_ids);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Clear an index.
 | 
			
		||||
 */
 | 
			
		||||
@@ -466,6 +518,34 @@ function drush_search_api_clear($index_id = NULL) {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Execute all pending tasks or all for a given server.
 | 
			
		||||
 */
 | 
			
		||||
function drush_search_api_execute_tasks($server_id = NULL) {
 | 
			
		||||
  if (search_api_drush_static(__FUNCTION__)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Attempt to load the associated server.
 | 
			
		||||
  $server = NULL;
 | 
			
		||||
  if ($server_id) {
 | 
			
		||||
    $servers = search_api_drush_get_server($server_id);
 | 
			
		||||
    if (!$servers) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    $server = reset($servers);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Process batch op with drush.
 | 
			
		||||
  try {
 | 
			
		||||
    search_api_execute_pending_tasks($server);
 | 
			
		||||
    drush_log(dt('!server tasks have been successfully executed.', array('!server' => $server->machine_name ? $server->machine_name : 'All')), 'ok');
 | 
			
		||||
  }
 | 
			
		||||
  catch (SearchApiException $e) {
 | 
			
		||||
    drush_log($e->getMessage(), 'error');
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Set the server for a given index.
 | 
			
		||||
 */
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
name = Search API
 | 
			
		||||
description = "Provides a generic API for modules offering search capabilities."
 | 
			
		||||
dependencies[] = entity
 | 
			
		||||
dependencies[] = entity:entity
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Search
 | 
			
		||||
 | 
			
		||||
@@ -16,6 +16,7 @@ files[] = includes/callback_language_control.inc
 | 
			
		||||
files[] = includes/callback_node_access.inc
 | 
			
		||||
files[] = includes/callback_node_status.inc
 | 
			
		||||
files[] = includes/callback_role_filter.inc
 | 
			
		||||
files[] = includes/callback_user_content.inc
 | 
			
		||||
files[] = includes/callback_user_status.inc
 | 
			
		||||
files[] = includes/datasource.inc
 | 
			
		||||
files[] = includes/datasource_entity.inc
 | 
			
		||||
@@ -37,9 +38,8 @@ files[] = includes/service.inc
 | 
			
		||||
 | 
			
		||||
configure = admin/config/search/search_api
 | 
			
		||||
 | 
			
		||||
; Information added by Drupal.org packaging script on 2017-02-23
 | 
			
		||||
version = "7.x-1.21"
 | 
			
		||||
; Information added by Drupal.org packaging script on 2019-03-11
 | 
			
		||||
version = "7.x-1.26"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "search_api"
 | 
			
		||||
datestamp = "1487844493"
 | 
			
		||||
 | 
			
		||||
datestamp = "1552334832"
 | 
			
		||||
 
 | 
			
		||||
@@ -264,6 +264,51 @@ function search_api_schema() {
 | 
			
		||||
  return $schema;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_requirements().
 | 
			
		||||
 */
 | 
			
		||||
function search_api_requirements($phase) {
 | 
			
		||||
  $requirements = array();
 | 
			
		||||
 | 
			
		||||
  if ($phase == 'runtime') {
 | 
			
		||||
    // Check whether at least one server has pending tasks.
 | 
			
		||||
    if (search_api_server_tasks_count()) {
 | 
			
		||||
      $items = array();
 | 
			
		||||
 | 
			
		||||
      $conditions = array('enabled' => TRUE);
 | 
			
		||||
      foreach (search_api_server_load_multiple(FALSE, $conditions) as $server) {
 | 
			
		||||
        $count = search_api_server_tasks_count($server);
 | 
			
		||||
        if ($count) {
 | 
			
		||||
          $args = array(
 | 
			
		||||
            '@name' => $server->name,
 | 
			
		||||
          );
 | 
			
		||||
          $text = format_plural($count, '@name has @count pending task.', '@name has @count pending tasks.', $args);
 | 
			
		||||
          $items[] = l($text, "admin/config/search/search_api/server/{$server->machine_name}/execute-tasks");
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if ($items) {
 | 
			
		||||
        $text = t('There are pending tasks for the following servers:');
 | 
			
		||||
        $text .= theme('item_list', array(
 | 
			
		||||
          'type' => 'ul',
 | 
			
		||||
          'items' => $items,
 | 
			
		||||
        ));
 | 
			
		||||
        if (count($items) > 1) {
 | 
			
		||||
          $label = t('Execute pending tasks on all servers');
 | 
			
		||||
          $text .= l($label, 'admin/config/search/search_api/execute-tasks');
 | 
			
		||||
        }
 | 
			
		||||
        $requirements['search_api_pending_tasks'] = array(
 | 
			
		||||
          'title' => t('Search API'),
 | 
			
		||||
          'value' => $text,
 | 
			
		||||
          'severity' => REQUIREMENT_WARNING,
 | 
			
		||||
        );
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $requirements;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_install().
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -72,6 +72,15 @@ function search_api_menu() {
 | 
			
		||||
    'type' => MENU_LOCAL_TASK,
 | 
			
		||||
    'context' => MENU_CONTEXT_INLINE | MENU_CONTEXT_PAGE,
 | 
			
		||||
  );
 | 
			
		||||
  $items[$pre . '/server/%search_api_server/execute-tasks'] = array(
 | 
			
		||||
    'title' => 'Execute pending tasks',
 | 
			
		||||
    'description' => 'Attempt to process pending tasks for a given server.',
 | 
			
		||||
    'page callback' => 'search_api_execute_pending_tasks',
 | 
			
		||||
    'page arguments' => array(5),
 | 
			
		||||
    'access callback' => 'search_api_access_execute_tasks_batch',
 | 
			
		||||
    'access arguments' => array(5),
 | 
			
		||||
    'type' => MENU_CALLBACK,
 | 
			
		||||
  );
 | 
			
		||||
  $items[$pre . '/server/%search_api_server/disable'] = array(
 | 
			
		||||
    'title' => 'Disable',
 | 
			
		||||
    'description' => 'Disable index.',
 | 
			
		||||
@@ -98,6 +107,13 @@ function search_api_menu() {
 | 
			
		||||
    'context' => MENU_CONTEXT_INLINE,
 | 
			
		||||
    'weight' => 10,
 | 
			
		||||
  );
 | 
			
		||||
  $items[$pre . '/execute-tasks'] = array(
 | 
			
		||||
    'title' => 'Execute pending tasks',
 | 
			
		||||
    'description' => 'Attempt to process pending server tasks.',
 | 
			
		||||
    'page callback' => 'search_api_execute_pending_tasks',
 | 
			
		||||
    'access callback' => 'search_api_access_execute_tasks_batch',
 | 
			
		||||
    'type' => MENU_LOCAL_ACTION,
 | 
			
		||||
  );
 | 
			
		||||
  $items[$pre . '/index/%search_api_index'] = array(
 | 
			
		||||
    'title' => 'View index',
 | 
			
		||||
    'title callback' => 'search_api_admin_item_title',
 | 
			
		||||
@@ -1025,6 +1041,28 @@ function search_api_search_api_item_type_info() {
 | 
			
		||||
  return $types;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_module_implements_alter().
 | 
			
		||||
 *
 | 
			
		||||
 * Ensures the item type and service class static caches are invalidated at the
 | 
			
		||||
 * right time.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_module_implements_alter(array &$implementations, $hook) {
 | 
			
		||||
  switch ($hook) {
 | 
			
		||||
    case 'modules_enabled':
 | 
			
		||||
      $group = $implementations['search_api'];
 | 
			
		||||
      unset($implementations['search_api']);
 | 
			
		||||
      $implementations = array('search_api' => $group) + $implementations;
 | 
			
		||||
      break;
 | 
			
		||||
 | 
			
		||||
    case 'modules_disabled':
 | 
			
		||||
      $group = $implementations['search_api'];
 | 
			
		||||
      unset($implementations['search_api']);
 | 
			
		||||
      $implementations['search_api'] = $group;
 | 
			
		||||
      break;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_modules_enabled().
 | 
			
		||||
 */
 | 
			
		||||
@@ -1103,6 +1141,11 @@ function search_api_search_api_alter_callback_info() {
 | 
			
		||||
    'description' => t('Exclude unpublished nodes from the index. <strong>Caution:</strong> This only affects the indexed nodes themselves. If an enabled node has references to disabled nodes, those will still be indexed (or displayed) normally.'),
 | 
			
		||||
    'class' => 'SearchApiAlterNodeStatus',
 | 
			
		||||
  );
 | 
			
		||||
  $callbacks['search_api_alter_user_content'] = array(
 | 
			
		||||
    'name' => t('Add user content'),
 | 
			
		||||
    'description' => t('Allows indexing of nodes (and their fields) created by the indexed user. (Caution: This might lead to performance problems, or even errors during indexing, on larger sites.)'),
 | 
			
		||||
    'class' => 'SearchApiAlterAddUserContent',
 | 
			
		||||
  );
 | 
			
		||||
  $callbacks['search_api_alter_user_status'] = array(
 | 
			
		||||
    'name' => t('Exclude blocked users'),
 | 
			
		||||
    'description' => t('Exclude blocked users from the index. <strong>Caution:</strong> This only affects the indexed users themselves. If an active user account includes a reference to a disabled user, that reference will still be indexed (or displayed) normally.'),
 | 
			
		||||
@@ -1382,6 +1425,10 @@ function search_api_server_tasks_check(SearchApiServer $server = NULL) {
 | 
			
		||||
  // Sometimes the order of tasks might be important, so make sure to order by
 | 
			
		||||
  // the task ID (which should be in order of insertion).
 | 
			
		||||
  $select->orderBy('t.id');
 | 
			
		||||
  // Only retrieve and execute 100 tasks at once, to avoid running out of memory
 | 
			
		||||
  // or time. We just can't do anything else until all tasks have been resolved,
 | 
			
		||||
  // but at least we shouldn't crash sites, or keep piling up tasks, that way.
 | 
			
		||||
  $select->range(0, 100);
 | 
			
		||||
  $tasks = $select->execute();
 | 
			
		||||
 | 
			
		||||
  $executed_tasks = array();
 | 
			
		||||
@@ -1429,7 +1476,7 @@ function search_api_server_tasks_check(SearchApiServer $server = NULL) {
 | 
			
		||||
 | 
			
		||||
      default:
 | 
			
		||||
        // This should never happen.
 | 
			
		||||
        continue;
 | 
			
		||||
        continue 2;
 | 
			
		||||
    }
 | 
			
		||||
    $executed_tasks[] = $task->id;
 | 
			
		||||
  }
 | 
			
		||||
@@ -1438,11 +1485,116 @@ function search_api_server_tasks_check(SearchApiServer $server = NULL) {
 | 
			
		||||
  if (!$executed_tasks) {
 | 
			
		||||
    return TRUE;
 | 
			
		||||
  }
 | 
			
		||||
  // Otherwise, delete the executed tasks and check if new tasks were created.
 | 
			
		||||
  // Otherwise, delete the executed tasks and check if new tasks were created
 | 
			
		||||
  // (or if we didn't even fetch all due to the 100 tasks limit).
 | 
			
		||||
  search_api_server_tasks_delete($executed_tasks);
 | 
			
		||||
  return $count_query->execute()->fetchField() === 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Provides a batch wrapper for search_api_server_tasks_check().
 | 
			
		||||
 *
 | 
			
		||||
 * @param SearchApiServer|null $server
 | 
			
		||||
 *   (optional) The server whose tasks should be executed, or NULL to execute
 | 
			
		||||
 *   tasks for all servers.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_execute_pending_tasks(SearchApiServer $server = NULL) {
 | 
			
		||||
  batch_set(array(
 | 
			
		||||
    'title' => t('Processing pending tasks'),
 | 
			
		||||
    'operations' => array(
 | 
			
		||||
      array(
 | 
			
		||||
        'search_api_execute_pending_tasks_batch',
 | 
			
		||||
        array(
 | 
			
		||||
          $server,
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    ),
 | 
			
		||||
    'finished' => 'search_api_execute_pending_tasks_finished'
 | 
			
		||||
  ));
 | 
			
		||||
  if ($server) {
 | 
			
		||||
    $path = 'admin/config/search/search_api/server/' . $server->machine_name;
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    $path = 'admin/config/search/search_api';
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (function_exists('drush_backend_batch_process')) {
 | 
			
		||||
    drush_backend_batch_process();
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    batch_process($path);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Executes pending server tasks as part of a batch operation.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_execute_pending_tasks_batch(SearchApiServer $server = NULL, &$context) {
 | 
			
		||||
  if (!isset($context['results']['total'])) {
 | 
			
		||||
    $context['results']['total'] = search_api_server_tasks_count($server);
 | 
			
		||||
  }
 | 
			
		||||
  $total = $context['results']['total'];
 | 
			
		||||
 | 
			
		||||
  search_api_server_tasks_check($server);
 | 
			
		||||
 | 
			
		||||
  $remaining = search_api_server_tasks_count($server);
 | 
			
		||||
  $executed = max($total - $remaining, 0);
 | 
			
		||||
 | 
			
		||||
  $args['@remaining'] = $remaining;
 | 
			
		||||
  $context['message'] = format_plural($executed, 'Successfully executed @count task, @remaining remaining.', 'Successfully executed @count tasks, @remaining remaining.', $args);
 | 
			
		||||
  $context['finished'] = $executed / $total;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Batch finish callback for pending server tasks.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_execute_pending_tasks_finished($success, $results, $operations) {
 | 
			
		||||
  if ($success) {
 | 
			
		||||
    // Clear the previous warning.
 | 
			
		||||
    drupal_get_messages('warning');
 | 
			
		||||
 | 
			
		||||
    // Alert user to the number of tasks executed.
 | 
			
		||||
    drupal_set_message(format_plural($results['total'], 'Successfully executed @count task.', 'Successfully executed @count tasks.'));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Return the number of pending tasks.
 | 
			
		||||
 *
 | 
			
		||||
 * @param SearchApiServer|null $server
 | 
			
		||||
 *   (optional) The server for which tasks should be counted, or NULL to count
 | 
			
		||||
 *   for all enabled servers.
 | 
			
		||||
 *
 | 
			
		||||
 * @return int
 | 
			
		||||
 *   The number of pending tasks for the server, or in total.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_server_tasks_count(SearchApiServer $server = NULL) {
 | 
			
		||||
  $query = db_select('search_api_task', 't')
 | 
			
		||||
    ->fields('t');
 | 
			
		||||
 | 
			
		||||
  if ($server) {
 | 
			
		||||
    $query->condition('server_id', $server->machine_name);
 | 
			
		||||
  }
 | 
			
		||||
  else {
 | 
			
		||||
    $query->join('search_api_server', 's', 's.machine_name = t.server_id');
 | 
			
		||||
    $query->condition('s.enabled', 1);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return $query->countQuery()->execute()->fetchField();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Access callback: Checks whether a user can execute pending tasks.
 | 
			
		||||
 *
 | 
			
		||||
 * @param SearchApiServer|null $server
 | 
			
		||||
 *   (optional) The server for which tasks would be executed.
 | 
			
		||||
 */
 | 
			
		||||
function search_api_access_execute_tasks_batch(SearchApiServer $server = NULL) {
 | 
			
		||||
  return user_access('administer search_api')
 | 
			
		||||
      && search_api_server_tasks_count($server)
 | 
			
		||||
      && (!$server || $server->enabled);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adds an entry into a server's list of pending tasks.
 | 
			
		||||
 *
 | 
			
		||||
 
 | 
			
		||||
@@ -86,6 +86,7 @@ class SearchApiWebTest extends DrupalWebTestCase {
 | 
			
		||||
   * and then run tests on it.
 | 
			
		||||
   */
 | 
			
		||||
  public function testFramework() {
 | 
			
		||||
    module_enable(array('search_api_test_2'));
 | 
			
		||||
    $this->drupalLogin($this->drupalCreateUser(array('administer search_api')));
 | 
			
		||||
    $this->insertItems();
 | 
			
		||||
    $this->createIndex();
 | 
			
		||||
@@ -730,13 +731,17 @@ class SearchApiWebTest extends DrupalWebTestCase {
 | 
			
		||||
   * deleteServer()) and that all associated tables and variables are removed.
 | 
			
		||||
   */
 | 
			
		||||
  protected function disableModules() {
 | 
			
		||||
    module_disable(array('search_api_test_2'), FALSE);
 | 
			
		||||
    $this->assertFalse(module_exists('search_api_test_2'), 'Second test module was successfully disabled.');
 | 
			
		||||
    module_disable(array('search_api_test'), FALSE);
 | 
			
		||||
    $this->assertFalse(module_exists('search_api_test'), 'Test module was successfully disabled.');
 | 
			
		||||
    $this->assertFalse(module_exists('search_api_test'), 'First test module was successfully disabled.');
 | 
			
		||||
    module_disable(array('search_api'), FALSE);
 | 
			
		||||
    $this->assertFalse(module_exists('search_api'), 'Search API module was successfully disabled.');
 | 
			
		||||
 | 
			
		||||
    drupal_uninstall_modules(array('search_api_test_2'), FALSE);
 | 
			
		||||
    $this->assertEqual(drupal_get_installed_schema_version('search_api_test_2', TRUE), SCHEMA_UNINSTALLED, 'Second test module was successfully uninstalled.');
 | 
			
		||||
    drupal_uninstall_modules(array('search_api_test'), FALSE);
 | 
			
		||||
    $this->assertEqual(drupal_get_installed_schema_version('search_api_test', TRUE), SCHEMA_UNINSTALLED, 'Test module was successfully uninstalled.');
 | 
			
		||||
    $this->assertEqual(drupal_get_installed_schema_version('search_api_test', TRUE), SCHEMA_UNINSTALLED, 'First test module was successfully uninstalled.');
 | 
			
		||||
    $this->assertFalse(db_table_exists('search_api_test'), 'Test module table was successfully removed.');
 | 
			
		||||
    drupal_uninstall_modules(array('search_api'), FALSE);
 | 
			
		||||
    $this->assertEqual(drupal_get_installed_schema_version('search_api', TRUE), SCHEMA_UNINSTALLED, 'Search API module was successfully uninstalled.');
 | 
			
		||||
 
 | 
			
		||||
@@ -1,18 +1,16 @@
 | 
			
		||||
 | 
			
		||||
name = Search API test
 | 
			
		||||
name = Search API Test
 | 
			
		||||
description = "Some dummy implementations for testing the Search API."
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Search
 | 
			
		||||
 | 
			
		||||
dependencies[] = search_api
 | 
			
		||||
dependencies[] = search_api:search_api
 | 
			
		||||
 | 
			
		||||
files[] = search_api_test.module
 | 
			
		||||
 | 
			
		||||
hidden = TRUE
 | 
			
		||||
 | 
			
		||||
; Information added by Drupal.org packaging script on 2017-02-23
 | 
			
		||||
version = "7.x-1.21"
 | 
			
		||||
; Information added by Drupal.org packaging script on 2019-03-11
 | 
			
		||||
version = "7.x-1.26"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "search_api"
 | 
			
		||||
datestamp = "1487844493"
 | 
			
		||||
 | 
			
		||||
datestamp = "1552334832"
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,16 @@
 | 
			
		||||
name = Search API Test Service 2
 | 
			
		||||
description = "A module providing a second test search service."
 | 
			
		||||
core = 7.x
 | 
			
		||||
package = Search
 | 
			
		||||
 | 
			
		||||
dependencies[] = search_api:search_api
 | 
			
		||||
 | 
			
		||||
files[] = search_api_test_service_2.module
 | 
			
		||||
 | 
			
		||||
hidden = TRUE
 | 
			
		||||
 | 
			
		||||
; Information added by Drupal.org packaging script on 2019-03-11
 | 
			
		||||
version = "7.x-1.26"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "search_api"
 | 
			
		||||
datestamp = "1552334832"
 | 
			
		||||
@@ -0,0 +1,136 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @file
 | 
			
		||||
 * Provides a second test service and server for testing Search API.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_search_api_service_info().
 | 
			
		||||
 */
 | 
			
		||||
function search_api_test_2_search_api_service_info() {
 | 
			
		||||
  $name = 'search_api_test_service_2';
 | 
			
		||||
  $services[$name] = array(
 | 
			
		||||
    'name' => $name,
 | 
			
		||||
    'description' => 'search_api_test_service_2 description',
 | 
			
		||||
    'class' => 'SearchApiDummyService',
 | 
			
		||||
  );
 | 
			
		||||
  return $services;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Implements hook_default_search_api_server().
 | 
			
		||||
 */
 | 
			
		||||
function search_api_test_2_default_search_api_server() {
 | 
			
		||||
  $id = 'test_server_2';
 | 
			
		||||
  $items[$id] = entity_create('search_api_server', array(
 | 
			
		||||
    'name' => 'Search API test server 2',
 | 
			
		||||
    'machine_name' => $id,
 | 
			
		||||
    'enabled' => 1,
 | 
			
		||||
    'description' => 'A server used for testing.',
 | 
			
		||||
    'class' => 'search_api_test_service_2',
 | 
			
		||||
  ));
 | 
			
		||||
  return $items;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Dummy service for testing.
 | 
			
		||||
 */
 | 
			
		||||
class SearchApiDummyService implements SearchApiServiceInterface {
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function __construct(\SearchApiServer $server) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function configurationForm(array $form, array &$form_state) {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function configurationFormValidate(array $form, array &$values, array &$form_state) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function configurationFormSubmit(array $form, array &$values, array &$form_state) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function supportsFeature($feature) {
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function viewSettings() {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function postCreate() {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function postUpdate() {
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function preDelete() {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function addIndex(SearchApiIndex $index) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function fieldsUpdated(SearchApiIndex $index) {
 | 
			
		||||
    return FALSE;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function removeIndex($index) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function indexItems(SearchApiIndex $index, array $items) {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function deleteItems($ids = 'all', SearchApiIndex $index = NULL) {}
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function query(SearchApiIndex $index, $options = array()) {
 | 
			
		||||
    throw new SearchApiException("The dummy service doesn't support queries");
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * {@inheritdoc}
 | 
			
		||||
   */
 | 
			
		||||
  public function search(SearchApiQueryInterface $query) {
 | 
			
		||||
    return array();
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@@ -1 +1,39 @@
 | 
			
		||||
See major version branches.
 | 
			
		||||
INTRODUCTION
 | 
			
		||||
------------
 | 
			
		||||
Allows you to override solr connection settings on an environment (site) basis,
 | 
			
		||||
via your settings.php without editing servers managed in features.
 | 
			
		||||
 | 
			
		||||
REQUIREMENTS
 | 
			
		||||
------------
 | 
			
		||||
* search_api_solr module
 | 
			
		||||
 | 
			
		||||
CONFIGURATION
 | 
			
		||||
-------------
 | 
			
		||||
The module has no menu or modifiable settings. There is no configuration. When
 | 
			
		||||
enabled, you can set your override values in your settings.php file.
 | 
			
		||||
Search api will automatically pick up your values, but make sure to clear your
 | 
			
		||||
cache first.
 | 
			
		||||
 | 
			
		||||
EXAMPLE
 | 
			
		||||
-------
 | 
			
		||||
You can add following example to your settings.php file.
 | 
			
		||||
 | 
			
		||||
$conf['search_api_solr_overrides'] = array(
 | 
			
		||||
  'solr-server-id' => array(
 | 
			
		||||
    'name' => 'Solr Server (Overridden)',
 | 
			
		||||
    'options' => array(
 | 
			
		||||
      'host' => '127.0.0.1',
 | 
			
		||||
      'port' => 8983,
 | 
			
		||||
      'path' => '/solr',
 | 
			
		||||
    ),
 | 
			
		||||
  ),
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
MAINTAINERS
 | 
			
		||||
-----------
 | 
			
		||||
Current maintainers:
 | 
			
		||||
* nick_schuch - https://www.drupal.org/u/nick_schuch
 | 
			
		||||
* cafuego - https://www.drupal.org/u/cafuego
 | 
			
		||||
 | 
			
		||||
This project has been sponsored by:
 | 
			
		||||
* PreviousNext - http://www.previousnext.com.au
 | 
			
		||||
 
 | 
			
		||||
@@ -3,9 +3,9 @@ description = Provides site specific overrides for search_api_solr configuration
 | 
			
		||||
core = 7.x
 | 
			
		||||
dependencies[] = search_api_solr
 | 
			
		||||
 | 
			
		||||
; Information added by drupal.org packaging script on 2013-10-01
 | 
			
		||||
version = "7.x-1.0-rc1+1-dev"
 | 
			
		||||
; Information added by Drupal.org packaging script on 2017-06-13
 | 
			
		||||
version = "7.x-1.0"
 | 
			
		||||
core = "7.x"
 | 
			
		||||
project = "search_api_solr_overrides"
 | 
			
		||||
datestamp = "1380626863"
 | 
			
		||||
datestamp = "1497319149"
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										10
									
								
								sites/all/modules/contrib/search/search_api_solr_overrides/search_api_solr_overrides.module
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										10
									
								
								sites/all/modules/contrib/search/search_api_solr_overrides/search_api_solr_overrides.module
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							@@ -15,7 +15,7 @@
 | 
			
		||||
 * Example:
 | 
			
		||||
 * $conf['search_api_solr_overrides'] = array(
 | 
			
		||||
 *   'solr-server-id' => array(
 | 
			
		||||
 *     'name' => t('Solr Server (Overridden)'),
 | 
			
		||||
 *     'name' => 'Solr Server (Overridden)',
 | 
			
		||||
 *       'options' => array(
 | 
			
		||||
 *         'host' => '127.0.0.1',
 | 
			
		||||
 *         'port' => 8983,
 | 
			
		||||
@@ -32,7 +32,7 @@ function search_api_solr_overrides_search_api_server_load($servers) {
 | 
			
		||||
  $overrides = variable_get('search_api_solr_overrides', FALSE);
 | 
			
		||||
 | 
			
		||||
  // Ensure the is information provided.
 | 
			
		||||
  if (empty($overrides)) {
 | 
			
		||||
  if (empty($overrides) || !is_array($overrides)) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -41,12 +41,12 @@ function search_api_solr_overrides_search_api_server_load($servers) {
 | 
			
		||||
    // Check to see if the server config exists.
 | 
			
		||||
    if (!empty($servers[$id])) {
 | 
			
		||||
      foreach ($servers[$id] as $key => $field) {
 | 
			
		||||
        // Ensure we need to override.
 | 
			
		||||
        if (empty($override[$key])) {
 | 
			
		||||
        // Ensure we need to override. User isset, so we can set FALSE values.
 | 
			
		||||
        if (!isset($override[$key])) {
 | 
			
		||||
          continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Check for if the field is an array.
 | 
			
		||||
        // Check if the field contains an array.
 | 
			
		||||
        if (is_array($field)) {
 | 
			
		||||
          $servers[$id]->$key = array_merge($servers[$id]->$key, $override[$key]);
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user