УрокПрограммное изменение запроса к базе данных во 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
Аватар пользователя Spleshka
Spleshka написал:

Суть поста не показать, как значение в аргумент добавляется, а помочь при изменении запроса во 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
Аватар пользователя Spleshka
Spleshka написал:

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

16.04.2012 23:49
Аватар пользователя sun-fire
sun-fire написал:

Большое спасибо за решение. Крайне мало примеров. Прокопался пару часов в исходниках, но так до конца и не получалось. После того, как посмотрел пример - все стало ясно. :)

20.06.2012 23:41
Аватар пользователя sun-fire
sun-fire написал:

UPD: крайне мало - имелось в виду в сети.

20.06.2012 23:42
Аватар пользователя Alexander Borisenko
Alexander Borisenko написал:

А у меня другая беда. Есть views (постороенный в UI) и нужно поменять базовую таблицу (с node на ссk), в целях значительного увеличения произодительность. Как это можно сделать???

03.10.2012 09:47
Аватар пользователя Роман
Роман написал:

А не можете показать на примере, каким образом с помощью Views строить запрос типа
select nid from node where nid>АРГУМЕНТ_1 and nid", "

27.12.2012 17:00
Аватар пользователя podarok ( http://druler.com )
podarok ( http:... написал:

а разве сессии не в контекст фильтрах Видов ?

19.02.2013 12:33

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