You are here

public function SearchApiFulltext::query in Search API 8

Same name in this branch
  1. 8 src/Plugin/views/filter/SearchApiFulltext.php \Drupal\search_api\Plugin\views\filter\SearchApiFulltext::query()
  2. 8 src/Plugin/views/argument/SearchApiFulltext.php \Drupal\search_api\Plugin\views\argument\SearchApiFulltext::query()

Add this filter to the query.

Due to the nature of fapi, the value and the operator have an unintended level of indirection. You will find them in $this->operator and $this->value respectively.

Overrides FilterPluginBase::query

File

src/Plugin/views/filter/SearchApiFulltext.php, line 369

Class

SearchApiFulltext
Defines a filter for adding a fulltext search to the view.

Namespace

Drupal\search_api\Plugin\views\filter

Code

public function query() {
  while (is_array($this->value)) {
    $this->value = $this->value ? reset($this->value) : '';
  }

  // Catch empty strings entered by the user, but not "0".
  if ($this->value === '') {
    return;
  }
  $fields = $this->options['fields'];
  $fields = $fields ?: array_keys($this
    ->getFulltextFields());

  // Override the search fields, if exposed.
  if (!empty($this->searchedFields)) {
    $fields = array_intersect($fields, $this->searchedFields);
  }
  $query = $this
    ->getQuery();

  // Save any keywords that were already set.
  $old = $query
    ->getKeys();
  $old_original = $query
    ->getOriginalKeys();
  if ($this->options['parse_mode']) {

    /** @var \Drupal\search_api\ParseMode\ParseModeInterface $parse_mode */
    $parse_mode = $this
      ->getParseModeManager()
      ->createInstance($this->options['parse_mode']);
    $query
      ->setParseMode($parse_mode);
  }

  // If something already specifically set different fields, we silently fall
  // back to mere filtering.
  $old_fields = $query
    ->getFulltextFields();
  $use_conditions = $old_fields && (array_diff($old_fields, $fields) || array_diff($fields, $old_fields));
  if ($use_conditions) {
    $conditions = $query
      ->createConditionGroup('OR');
    $op = $this->operator === 'not' ? '<>' : '=';
    foreach ($fields as $field) {
      $conditions
        ->addCondition($field, $this->value, $op);
    }
    $query
      ->addConditionGroup($conditions);
    return;
  }

  // If the operator was set to OR or NOT, set OR as the conjunction. It is
  // also set for NOT since otherwise it would be "not all of these words".
  if ($this->operator != 'and') {
    $query
      ->getParseMode()
      ->setConjunction('OR');
  }
  $query
    ->setFulltextFields($fields);
  $query
    ->keys($this->value);
  if ($this->operator == 'not') {
    $keys =& $query
      ->getKeys();
    if (is_array($keys)) {
      $keys['#negation'] = TRUE;
    }
    else {

      // We can't know how negation is expressed in the server's syntax.
    }
    unset($keys);
  }

  // If there were fulltext keys set, we take care to combine them in a
  // meaningful way (especially with negated keys).
  if ($old) {
    $keys =& $query
      ->getKeys();

    // Array-valued keys are combined.
    if (is_array($keys)) {

      // If the old keys weren't parsed into an array, we instead have to
      // combine the original keys.
      if (is_scalar($old)) {
        $keys = "({$old}) ({$this->value})";
      }
      else {

        // If the conjunction or negation settings aren't the same, we have to
        // nest both old and new keys array.
        if (empty($keys['#negation']) !== empty($old['#negation']) || $keys['#conjunction'] !== $old['#conjunction']) {
          $keys = [
            '#conjunction' => 'AND',
            $old,
            $keys,
          ];
        }
        else {
          foreach ($old as $key => $value) {
            if (substr($key, 0, 1) === '#') {
              continue;
            }
            $keys[] = $value;
          }
        }
      }
    }
    elseif (is_scalar($old_original)) {
      $combined_keys = "({$old_original}) ({$keys})";
      $query
        ->keys($combined_keys);
      $keys = $combined_keys;
    }
    unset($keys);
  }
}