УрокПрограммное изменение запроса к базе данных во 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); } }
Однако такой вариант является "деревянным". Т.е. никто, кроме программистов, не сможет убрать вывод данного вьюса с главной страницы, т.к. он всегда будет заменять вывод его содержимого. Да и немного кривое это решение ;)
Поэтому перед тем, как браться за реализацию, подумайте - действительно ли ваш вариант самый оптимальный? А так же не забывайте про то, что после вас на проект могут придти другие люди, которым надо будет разбираться в том, что вы написали. А это отнюдь не простая задача..
- SplasH
- 24.12.2011
- 1039
Комментарии
> А Views не даёт возможности подставить значение в фильтр из сессий.
аргумент - provide default value: php code - return $_SESSION['city'];
Суть поста не показать, как значение в аргумент добавляется, а помочь при изменении запроса во Views. Но за замечание спасибо, оно дельное.
есть более качественный подход - через добавление своих хендлеров для вьюса
во пример http://drupal.org/node/357079
Простите за нескромный вопрос.
куда эту функцию надо воткнуть и на что заменить function ИМЯМОДУЛЯ_preprocess_page(&$vars)
Заранее спасибо.
Ну точнее что это за преславутое
, третий день не могу догнать
Это название модуля, в котором вы имплементируете данную функцию.
Комментировать