Добавление условия ИЛИ в существующий запрос
Я хочу иметь возможность искать дополнительные поля пользователя вместо стандартного имени пользователя. Например, я хотел бы, чтобы пользователи могли выполнять поиск в прикрепленном поле с реальным именем пользователя. Поисковый запрос пользователя можно найти в user_search_execute(). Я решил, что буду использовать hook_query_alter() для изменения запроса базы данных, сгенерированного этой функцией.
Проблема, с которой я сталкиваюсь, заключается в том, что если я добавлю что-нибудь подобное:
$arguments = $query->getArguments();
$query->condition('n.field_name_value',$arguments[':db_condition_placeholder_0'], 'LIKE');
$query->leftJoin('field_data_field_name', 'n', 'users.uid = n.entity_id');
Затем drupal добавляет "И" в список условий (вместо "ИЛИ").
Я даже пытался добавить что-то вроде этого:
$arguments = $query->getArguments();
$query->condition(db_or()->
condition('n.field_name_value',$arguments[':db_condition_placeholder_0'], 'LIKE'));
$query->leftJoin('field_data_field_name', 'n', 'users.uid = n.entity_id');
Однако это приводит к тем же результатам.
Спасибо!
3 answers
Добавление новых условий в запрос не приведет к перезаписи существующих, вам нужно сбросить существующий массив условий, создать новый и добавить его в запрос:
// Get the query args and then the search term
$args = $query->getArguments();
$search = array_shift($args);
// Get a reference to the existing query conditions.
$conditions =& $query->conditions();
// Reset the condition array. It needs a default #conjunction for which AND is fine
$conditions = array('#conjunction' => 'AND');
// Build up your condition
$condition = db_or()
->condition('users.name', $search, 'LIKE')
->condition('n.field_name_value', $search, 'LIKE');
// Add the new OR condition to the query
$query->condition($condition);
// Join the relevant table
$query->leftJoin('field_data_field_name', 'n', 'users.uid = n.entity_id');
Я только что протестировал это для работы с локальной установкой.
Есть небольшое предостережение... для пользователей с разрешением "администрировать пользователей" по умолчанию также выполняется поиск по адресам электронной почты пользователей. Вы можете удовлетворить это, добавив следующие строки непосредственно перед $query->condition($condition);
:
if (user_access('administer users')) {
$condition->condition('mail', $search, 'LIKE');
}
Также может быть разумно проверить столбцы bundle
и entity_type
в таблице объединенных полей на случай, если вы когда-либо присоедините одно и то же поле к другому объекту. Таким образом, вы не получите никаких ложных результатов:
$join = "users.uid = n.entity_id AND n.entity_type = 'user' AND n.bundle = 'user'";
$query->leftJoin('field_data_field_name', 'n', $join);
РЕДАКТИРОВАТЬ
Согласно комментарию Бердира, для обеспечения максимальной совместимости с другими модулями, которые также могут изменить этот запрос, вы, вероятно, захотите просмотреть условия, найти те, которые вам нужно изменить, и сделать это индивидуально основа.
Приведенный выше пример довольно примитивен и работает на "ванильной" установке Drupal, надеюсь, он укажет вам правильное направление.
Метод db_or() должен предоставить то, что вам нужно. Вот пример, где мы получаем все узлы "блога", которые либо созданы uid=1, либо опубликованы:
$query = db_select('node', 'n');
$query->fields('n', array('nid'))
->condition('n.type', 'blog')
->condition(db_or()->condition('n.uid', 1)->condition('n.status', 1));
$result = $query->execute();
В принципе, я думаю, что вам просто нужно связать несколько условий в рамках метода db_or().
Вот некоторые дополнительные сведения о тема:
- http://drupal.org/node/310086
- http://www.rahulsingla.com/blog/2011/06/drupal-7-creating-arbitrary-anded-ored-database-queries-using-the-dbtng-abstraction-lay
Редактировать: Взгляните на метод условия() , чтобы получить список условий (по ссылке) и управлять ими - возможно, полностью удалить их и добавить в свой метод db_or().
Вместо того, чтобы вручную перестраивать существующие условия, как в ответе @Clive, вы можете сделать это автоматически.
// Get a reference to the existing query conditions.
$conditions =& $query->conditions();
// Build a new AND condition from the existing conditions.
$and = db_and();
foreach ($conditions as $key => $condition) {
// Skip the '#conjunction' special key.
if (is_numeric($key)) {
$and->condition($condition['field'], $condition['value'], $condition['operator']);
}
}
// Reset the conditions.
// It needs a default #conjunction that will end up being ignored.
$conditions = array('#conjunction' => 'OR');
// Create a new condition from the rebuilt conditions OR our new condition.
$or = db_or();
$or->condition('foo.my_field', $bar);
$or->condition($and);
// Add our new condition.
$query->condition($or);