protected function Database::createDbCondition in Search API 8
Creates a database query condition for a given search filter.
Used as a helper method in createDbQuery().
Parameters
\Drupal\search_api\Query\ConditionGroupInterface $conditions: The conditions for which a condition should be created.
array $fields: Internal information about the index's fields.
\Drupal\Core\Database\Query\SelectInterface $db_query: The database query to which the condition will be added.
\Drupal\search_api\IndexInterface $index: The index we're searching on.
Return value
\Drupal\Core\Database\Query\ConditionInterface|null The condition to set on the query, or NULL if none is necessary.
Throws
\Drupal\search_api\SearchApiException Thrown if an unknown field or operator was used in one of the contained conditions.
1 call to Database::createDbCondition()
- Database::createDbQuery in modules/
search_api_db/ src/ Plugin/ search_api/ backend/ Database.php - Creates a database query for a search.
File
- modules/
search_api_db/ src/ Plugin/ search_api/ backend/ Database.php, line 2212
Class
- Database
- Indexes and searches items using the database.
Namespace
Drupal\search_api_db\Plugin\search_api\backendCode
protected function createDbCondition(ConditionGroupInterface $conditions, array $fields, SelectInterface $db_query, IndexInterface $index) {
$conjunction = $conditions
->getConjunction();
$db_condition = $db_query
->conditionGroupFactory($conjunction);
$db_info = $this
->getIndexDbInfo($index);
// Store the table aliases for the fields in this condition group.
$tables = [];
$wildcard_count = 0;
foreach ($conditions
->getConditions() as $condition) {
if ($condition instanceof ConditionGroupInterface) {
$sub_condition = $this
->createDbCondition($condition, $fields, $db_query, $index);
if ($sub_condition) {
$db_condition
->condition($sub_condition);
}
}
else {
$field = $condition
->getField();
$operator = $condition
->getOperator();
$value = $condition
->getValue();
$this
->validateOperator($operator);
$not_equals_operators = [
'<>',
'NOT IN',
'NOT BETWEEN',
];
$not_equals = in_array($operator, $not_equals_operators);
$not_between = $operator == 'NOT BETWEEN';
if (!isset($fields[$field])) {
throw new SearchApiException("Unknown field in filter clause: '{$field}'.");
}
$field_info = $fields[$field];
// For NULL values, we can just use the single-values table, since we
// only need to know if there's any value at all for that field.
if ($value === NULL || empty($field_info['multi-valued'])) {
if (empty($tables[NULL])) {
$table = [
'table' => $db_info['index_table'],
];
$tables[NULL] = $this
->getTableAlias($table, $db_query);
}
$column = $tables[NULL] . '.' . $field_info['column'];
if ($value === NULL) {
$method = $not_equals ? 'isNotNull' : 'isNull';
$db_condition
->{$method}($column);
}
elseif ($not_between) {
$nested_condition = $db_query
->conditionGroupFactory('OR');
$nested_condition
->condition($column, $value[0], '<');
$nested_condition
->condition($column, $value[1], '>');
$nested_condition
->isNull($column);
$db_condition
->condition($nested_condition);
}
elseif ($not_equals) {
// Since SQL never returns TRUE for comparison with NULL values, we
// need to include "OR field IS NULL" explicitly for some operators.
$nested_condition = $db_query
->conditionGroupFactory('OR');
$nested_condition
->condition($column, $value, $operator);
$nested_condition
->isNull($column);
$db_condition
->condition($nested_condition);
}
else {
$db_condition
->condition($column, $value, $operator);
}
}
elseif ($this
->getDataTypeHelper()
->isTextType($field_info['type'])) {
$tokenizer_active = $index
->isValidProcessor('tokenizer');
$keys = $this
->prepareKeys($value, $tokenizer_active);
if (!isset($keys)) {
continue;
}
$query = $this
->createKeysQuery($keys, [
$field => $field_info,
], $fields, $index);
// We only want the item IDs, so we use the keys query as a nested
// query.
$query = $this->database
->select($query, 't')
->fields('t', [
'item_id',
]);
$db_condition
->condition('t.item_id', $query, $not_equals ? 'NOT IN' : 'IN');
}
elseif ($not_equals) {
// The situation is more complicated for negative conditions on
// multi-valued fields, since we must make sure that results are
// excluded if ANY of the field's values equals the one(s) given in
// this condition. Probably the most performant way to do this is to
// do a LEFT JOIN with a positive filter on the excluded values in the
// ON clause and then make sure we have no value for the field.
if ($not_between) {
$wildcard1 = ':values_' . ++$wildcard_count;
$wildcard2 = ':values_' . ++$wildcard_count;
$arguments = array_combine([
$wildcard1,
$wildcard2,
], $value);
$additional_on = "%alias.value BETWEEN {$wildcard1} AND {$wildcard2}";
}
else {
$wildcard = ':values_' . ++$wildcard_count . '[]';
$arguments = [
$wildcard => (array) $value,
];
$additional_on = "%alias.value IN ({$wildcard})";
}
$alias = $this
->getTableAlias($field_info, $db_query, TRUE, 'leftJoin', $additional_on, $arguments);
$db_condition
->isNull($alias . '.value');
}
else {
// We need to join the table if it hasn't been joined (for this
// condition group) before, or if we have "AND" as the active
// conjunction.
if ($conjunction == 'AND' || empty($tables[$field])) {
$tables[$field] = $this
->getTableAlias($field_info, $db_query, TRUE);
}
$column = $tables[$field] . '.value';
$db_condition
->condition($column, $value, $operator);
}
}
}
return $db_condition
->count() ? $db_condition : NULL;
}