Добавление условия ИЛИ в существующий запрос


Я хочу иметь возможность искать дополнительные поля пользователя вместо стандартного имени пользователя. Например, я хотел бы, чтобы пользователи могли выполнять поиск в прикрепленном поле с реальным именем пользователя. Поисковый запрос пользователя можно найти в 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');

Однако это приводит к тем же результатам.

Спасибо!

 5
Author: kiamlaluno, 2012-02-20

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, надеюсь, он укажет вам правильное направление.

 8
Author: Clive, 2012-02-22 23:45:12

Метод 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().

Вот некоторые дополнительные сведения о тема:

Редактировать: Взгляните на метод условия() , чтобы получить список условий (по ссылке) и управлять ими - возможно, полностью удалить их и добавить в свой метод db_or().

 2
Author: Charlie Schliesser, 2012-02-22 23:07:47

Вместо того, чтобы вручную перестраивать существующие условия, как в ответе @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);
 0
Author: Dalin, 2014-04-09 17:21:54