You are here

protected function SearchApiDbService::createFilterCondition in Search API Database Search 7

Creates a database query condition for a given search filter.

Used as a helper method in createDbQuery().

Parameters

SearchApiQueryFilterInterface $filter: The filter for which a condition should be created.

array $fields: Internal information about the index's fields.

SelectQueryInterface $db_query: The database query to which the condition will be added.

SearchApiIndex $index: (optional) The search index whose settings should be used.

Return value

DatabaseCondition|null The condition to set on the query, or NULL if none is necessary.

Throws

SearchApiException If an unknown field was used in the filter.

1 call to SearchApiDbService::createFilterCondition()
SearchApiDbService::createDbQuery in ./service.inc
Creates a database query for a search.

File

./service.inc, line 1699
Contains SearchApiDbService.

Class

SearchApiDbService
Indexes and searches items using the database.

Code

protected function createFilterCondition(SearchApiQueryFilterInterface $filter, array $fields, SelectQueryInterface $db_query, SearchApiIndex $index = NULL) {
  $cond = db_condition($filter
    ->getConjunction());

  // Store whether a JOIN already occurred for a field, so we don't JOIN
  // repeatedly for OR filters.
  $first_join = array();

  // Store the table aliases for the fields in this condition group.
  $tables = array();
  foreach ($filter
    ->getFilters() as $f) {
    if (is_object($f)) {
      $c = $this
        ->createFilterCondition($f, $fields, $db_query, $index);
      if ($c) {
        $cond
          ->condition($c);
      }
    }
    else {
      list($field, $value, $operator) = $f;
      if (!isset($fields[$field])) {
        throw new SearchApiException(t('Unknown field in filter clause: @field.', array(
          '@field' => $field,
        )));
      }
      $field_info = $fields[$field];
      $not_between = $operator === 'NOT BETWEEN';
      $not_equals = $not_between || $operator === '<>' || $operator === '!=';
      $text_type = search_api_is_text_type($field_info['type']);

      // If the field is in its own table, we have to check for NULL values in
      // a special way (i.e., check for missing entries in that table).
      if ($value === NULL && ($field_info['column'] === 'value' || $text_type)) {
        $query = $this->connection
          ->select($field_info['table'], 't')
          ->fields('t', array(
          'item_id',
        ));
        if ($text_type) {
          $query
            ->condition('t.field_name', $field);
        }
        $cond
          ->condition('t.item_id', $query, $not_equals ? 'IN' : 'NOT IN');
        continue;
      }
      if ($text_type) {
        if (!isset($tokenizer_active)) {
          $tokenizer_active = $index && static::isTokenizerActive($index);
        }
        $keys = $this
          ->prepareKeys($value, $tokenizer_active);
        if (!isset($keys)) {
          continue;
        }
        $query = $this
          ->createKeysQuery($keys, array(
          $field => $field_info,
        ), $fields);

        // We only want the item IDs, so we use the keys query as a nested query.
        $query = $this->connection
          ->select($query, 't')
          ->fields('t', array(
          'item_id',
        ));
        $cond
          ->condition('t.item_id', $query, $not_equals ? 'NOT IN' : 'IN');
      }
      else {
        $new_join = search_api_is_list_type($field_info['type']) && ($filter
          ->getConjunction() == 'AND' || empty($first_join[$field]));
        if ($new_join || empty($tables[$field])) {
          $tables[$field] = $this
            ->getTableAlias($field_info, $db_query, $new_join);
          $first_join[$field] = TRUE;
        }
        $column = $tables[$field] . '.' . $field_info['column'];
        if ($value === NULL) {
          $method = $operator == '=' ? 'isNull' : 'isNotNull';
          $cond
            ->{$method}($column);
        }
        elseif ($not_equals && search_api_is_list_type($field_info['type'])) {

          // The situation is more complicated for multi-valued fields, since
          // we must make sure that results are excluded if ANY of the field's
          // values equals the one given in this condition.
          $sub_operator = $not_between ? 'BETWEEN' : '=';
          $query = $this->connection
            ->select($field_info['table'], 't')
            ->fields('t', array(
            'item_id',
          ))
            ->condition($field_info['column'], $value, $sub_operator);
          $cond
            ->condition('t.item_id', $query, 'NOT IN');
        }
        elseif ($not_between) {
          $cond
            ->where("{$column} NOT BETWEEN {$value[0]} AND {$value[1]}");
        }
        else {
          $cond
            ->condition($column, $value, $operator);
        }
      }
    }
  }
  return count($cond
    ->conditions()) > 1 ? $cond : NULL;
}