Как изменить союз условий в существующем запросе

mbaev 30.09.2016, 11:15

Предположим, вам необходимо выбрать все опубликованные ноды и автор которых - суперадмин. В SQL запрос должен выглядеть так:

  1. SELECT n.*
  2. FROM node n
  3. WHERE (n.STATUS = 1 AND n.uid = 1)

Сформировать такой запрос не составит труда.

Создание запроса
  1. $query = db_select('node', 'n')
  2.         ->fields('n')
  3.         ->condition('n.status', NODE_PUBLISHED)
  4.         ->condition('n.uid', 1);

Вдруг, внезапно вам захотелось изменить союз с AND на OR.

  1. SELECT *
  2. FROM node n
  3. WHERE (n.STATUS = 1 OR n.uid = 1)

Создать такой запрос изначально было бы не сложно. Пример:

  1. $conditions = db_or()
  2.         ->condition('n.status', NODE_PUBLISHED)
  3.         ->condition('n.uid', 1);
  4.        
  5. $query = db_select('node', 'n')
  6.         ->fields('n')
  7.         ->condition($conditions);

Но изменить союз сложнее, если у вас уже есть готовый объект запроса. Вся проблема заключается в том, что Друпал не даёт доступ к свойству where класса SelectQuery.

Мы можем получить доступ к ключу conditions, который находится в свойстве where. От этого и будем отталкиваться.

Изменение союза

Проще всего изменить союз в массиве (дальше будем использовать переменную $query полученную в результате выполнения примера кода из блока "Создание запроса"):

Создание запроса
  1. $conditions = &$query->conditions();
  2. $conditions['#conjunction'] = 'OR';

Но это стремный метод и плох он, в первую очередь, тем, что появляются вопросы:

  • А что будет если завтра Drupal решит использовать выдуманные собой названия союзов, вместо стандартных SQL-ных? Например, WHETHER вместо OR.
  • А что если изменится название ключа в котором хранится союз? Вместо #conjunction будет, например, #combination.

Вопросы, конечно, надуманные, но у меня они вызывают ощущение неправильного подхода.

Еще один способ изменения союза, на мой взгляд, более правильный. Почему этот способ лучше, я опишу в следующей статье, а сейчас пример:

  1. // Создаём класс набора условий с союзом OR. (будем называть его класс "OR").
  2. $or = db_or();
  3. // Содаём ссылку на массив условий в классе с союзом OR.
  4. $conditions = &$or->conditions();
  5. // Копируем массив условий из запроса (будем называть условия в запросе класс "AND").
  6. $conditions = $query->conditions();
  7.  
  8. // Для того, чтобы другие программисты понимали,
  9. // что переменная была создана только для того,
  10. // чтобы скопировать условия из класса "AND" в класс "OR".
  11. unset($conditions);
  12.  
  13. // Удаление всех существующих условий в классе "AND".
  14. $conditions = &$query->conditions();
  15. foreach (element_children($conditions) as $idx) {
  16.   unset($conditions[$idx]);
  17. }
  18.  
  19. // Добавляем условия скопированные в класс "OR".
  20. $query->condition($or);