УрокПрограммное изменение запроса к базе данных во Views

Возникают ситуации, когда необходимо сделать во Views фильтр с помощью программного вмешательства. Например, совсем недавно я реализовывал такую задачу:

Есть тип материала "акция". Акция содержит поле со списком городов (чекбоксы), к которым она приурочена. В шапке сайта есть выпадающий список с этим же списком городов. На главной странице сделана вьюха, которая выводит акции по городам, т.е. в зависимости от выбранного города из выпадающего списка в шапке сайта. Так как это должно работать и для анонимов, то выбранный город решено хранить в сессии пользователя. А Views не даёт возможности подставить значение в фильтр из сессий. Следовательно, пришлось создать небольшой модуль, который изменяет запрос вьюса к базе данных, подставив в качестве фильтра города значение из сессии пользователя.

Итак, реализация. Покопавшись в хуках Views я нашёл желаемый - hook_views_query_alter(), который позволяет программно изменять запрос к базе данных. Однако ни в официальной документации, ни в других более-менее нормальных источниках я не нашёл примера работы с этим хуком. Максимум, что было найдено - это либо примеры под 6й Друпал (которые под 7ку не работают), либо же примеры добавление секции WHERE в запрос. А мне ведь ещё и таблицу с данными по городам подключить надо было. В общем, в результате активного поиска, склеивания различных примеров да и просто методом научного тыка решение было найдено:

**
 * Implements hook_views_query_alter().
 */
function ИМЯМОДУЛЯ_views_query_alter(&$view, &$query) {
  // Изменяем фильтр у вьюса с названием front_page
  if ($view->name == 'front_page') {
 
    // Получаем значени выбранного города из сессии
    $city = $_SESSION['city'];
 
    // Присоединяем к запросу таблицу field_data_field_action_city
    $join = new views_join();
    $join->construct('field_data_field_action_city', 'node', 'nid', 'entity_id');
    $query->add_relationship('field_data_field_action_city', $join, 'node');
 
    // Добавляем в секцию WHERE фильтр, в котором значени города должно
    // равняться значению города из сессии
    $query->add_where(1, 'field_data_field_action_city.field_action_city_value', $city);
  }
}

Вот и всё. Оказалось-то пару строк кода, а столько поисков!

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

/**
 * Implements hook_preprocess_page().
 */
function ИМЯМОДУЛЯ_preprocess_page(&$vars) {
  if (drupal_is_front_page() && module_exists('views')) {
    $city = $_SESSION['city'];
    //$vars['content'] = views_embed_view('ИМЯ_ВЬЮСА', 'ИМЯ_ВЫВОДА', 'АРГУМЕНТ');
    $vars['content'] = views_embed_view('front_page', 'page_1', $city);
  }
}

Однако такой вариант является "деревянным". Т.е. никто, кроме программистов, не сможет убрать вывод данного вьюса с главной страницы, т.к. он всегда будет заменять вывод его содержимого. Да и немного кривое это решение ;)

Поэтому перед тем, как браться за реализацию, подумайте - действительно ли ваш вариант самый оптимальный? А так же не забывайте про то, что после вас на проект могут придти другие люди, которым надо будет разбираться в том, что вы написали. А это отнюдь не простая задача..

Комментарии

Аватар пользователя xandeadx
xandeadx написал:

> А Views не даёт возможности подставить значение в фильтр из сессий.

аргумент - provide default value: php code - return $_SESSION['city'];

24.12.2011 21:45
Аватар пользователя SplasH
SplasH написал:

Суть поста не показать, как значение в аргумент добавляется, а помочь при изменении запроса во Views. Но за замечание спасибо, оно дельное.

24.12.2011 21:52
Аватар пользователя cosmos
cosmos написал:

есть более качественный подход - через добавление своих хендлеров для вьюса
во пример http://drupal.org/node/357079

13.04.2012 20:52
Аватар пользователя прапор
прапор написал:

Простите за нескромный вопрос.

куда эту функцию надо воткнуть и на что заменить function ИМЯМОДУЛЯ_preprocess_page(&$vars)

Заранее спасибо.

16.04.2012 05:48
Аватар пользователя прапор
прапор написал:

Ну точнее что это за преславутое

ИМЯМОДУЛЯ

, третий день не могу догнать

16.04.2012 05:51
Аватар пользователя SplasH
SplasH написал:

Это название модуля, в котором вы имплементируете данную функцию.

16.04.2012 23:49

Комментировать

                                                                   
,ad8888ba, 88 ad88888ba 88 88888888ba
d8"' `"8b 88 d8" "8b ,d88 88 "8b
d8' 88 Y8a a8P 888888 88 ,8P
88 88 "Y8aaa8P" 88 88aaaaaa8P'
88 88888 88 ,d8"""8b, 88 88""""""'
Y8, 88 88 d8" "8b 88 88
Y8a. .a88 88 Y8a a8P 88 88
`"Y88888P" 88888888888 "Y88888P" 88 88

Enter the code depicted in ASCII art style.