В первом способе было рассмотрено создание сложной выборки с помощью контекстного фильтра. В этом способе покажу, как тоже самое можно сделать с помощью написания собственного filter handler-а.
Filter Handler — это класс, в котором прописана логика работы определённого типа фильтра. По умолчанию в Views 3 есть около 10 таких хэндлеров, это:
- views_handler_filter — базовый хэндлер, от которого должны наследоваться все остальные.
- views_handler_filter_numeric — позволяет фильтровать по числовым полям (больше, меньше, между и т.д.).
- views_handler_filter_string — позволяет фильтровать по строковым полям (равно, содержит, и т.д.).
- views_handler_filter_date — расширяет views_handler_filter_numeric и позволяет фильтровать по полям, в которых хранится Unix timestamp (позже, раньше, и т.д.).
и т.д.
Дефолтные хэндлеры хранятся в папке handlers
модуля Views (рекомендую к изучению).
Процесс создания своего фильтра:
1. В файле .module реализуем хук hook_views_api()
, в котором сообщаем Views, что мы желаем расширить его функционал:
/**
* Implements of hook_views_api().
*/
function mymodule_views_api() {
return array('api' => 3);
}
2. Создаём в папке модуля файл mymodule.views.inc
.
3. Реализуем в нём хук hook_views_data()
, в котором рассказываем Views о нашем кастомном фильтре:
/**
* Implements of hook_views_data().
*/
function mymodule_views_data() {
return array(
'node' => array(
'mycustomfilter' => array(
'group' => t('Custom'),
'title' => t('My custom filter'),
'help' => t('My custom filter'),
'filter' => array(
'handler' => 'mymodule_handler_filter_mycustomfilter',
),
)
)
);
}
node
— это базовая таблица (подробнее тут), mycustomfilter
— системное название нашего фильтра, mymodule_handler_filter_mycustomfilter
— хэндлер (класс), в котором будет описана логика фильтра.
Хэндлеры принято именовать по шаблону — [module_name]_handler_[handler_type]_[handler_name]
.
Если сейчас включить модуль и попытаться добавить новый фильтр, то в списке появится и наш:
4. В папке модуля создаём файл mymodule_handler_filter_mycustomfilter.inc
.
5. Добавляем в него класс mymodule_handler_filter_mycustomfilter
унаследованный от views_handler_filter
и переопределяем в этом классе функцию query()
:
/**
* My custom filter handler
*/
class mymodule_handler_filter_mycustomfilter extends views_handler_filter {
function query() {
$this->ensure_my_table();
// ...
}
}
Вместо троеточия, с помощью функций $this->query->add_where()
и $this->query->add_where_expression()
реализуем логику работы фильтра. Например если мы хотим сделать фильтр по нодам, дата изменения которых больше даты создания, то код будет:
$this->query->add_where_expression($this->options['group'], "{$this->table_alias}.changed > {$this->table_alias}.created");
Другие примеры ищите в файлах handlers/views_handler_filter_*.inc
.
6. Добавляем в .info файл информацию о новом классе:
files[] = mymodule_handler_filter_mycustomfilter.inc
7. Сбрасываем кэш.
Всё. Исходники демо модуля.
Аналогичным способом можно добавить хэндлеры для полей, сортировки и контекстных фильтров.
Полезные ссылки:
— Creating Custom Filters in Views
— How To Create A Custom Filter Handler In Views
- Views сортировка по выражению/условию/формуле
- Необязательное значение одной из дат в раскрытом фильтре с оператором BETWEEN
- Как расширить функционал фильтр-плагина Views? (добавляем возможность фильтровать числовые поля по нескольким значениям)
- Экспорт представления Views в код
- Программно добавить шапку или подвал в представление
Комментарии
Когда ты только успеваешь :) Спасибо за познавательный материал.
Очень полезные сведения.
Всё-таки я пока не совсем понял... А как фильтровать по значению какого-нибудь кастомного поля?? Назовём его, например, field_class.
Как будет выглядеть условие?? Да и вообще, я толком не понял, где указывать, для какого именно поля фильтрация...
изучайте handlers/views_handler_filter_*.inc
Фильтры я все уже перечитал. Собственно, всё написано, просто не получается нужное поле брать. Даже на простейший запрос вышеуказанным способом
$this->query->add_where(0, 'field_class', 'B', '=');
все равно ругается:
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'field_class' in 'where clause'
Может как-то рассказывать views про это поле надо в mymodule_views_data()?? Или ещё что-то... Просто для седьмого друпала очень мало написано про Views API. В шестёрке поля по другому хранились. Тут ведь отдельная таблица для каждого поля. Он должен сам подхватывать значения без приклеивания этих таблиц JOINом??
не должен
а как изменить отображение фильтра для числового поля: в случаи "between" вместо двух полей вывести список интервалов и соответственно корректно обработать их?
переопределите метод options_form. я сам этим не занимался, поэтому не помощник. смотрите исходники дефолтных фильтров.
Webtoucher, нужно сначала присоединить таблицу с нужным вам полем. Для вашего случая:
Дима Мельник, спасибо!
А может кто знает, как сделать GROUP BY по этому полю
Пробую
$this->query->add_groupby('таблица_с_полем.поле');
не работает
А как добавляются кастомные сортировки к вьюшкам? тоже описываются в mymodule_views_data ? интересует именно шаг два. Что должно поменяться в этом коде, для описания сортировки
А что означает $this->options['group'] ?
'sort' => array('handler' => 'mymodule_handler_sort_mycustomsort'),
А как можно удалить условие из результирующего sql-запроса ?
Спс очень хорошая статья
Здравствуйте. Вроде бы все сделал по вашей статье, но когда применяю фильтр выводится ошибка базы данных, думаю вся причина в том, что я не правильно делаю запрос, или оно не знает к какой таблице я хочу подключится, или вообще не пойму в чем причина. Помогите пожалуйста. в коде хендлера я пишу
и вот дальше тупик! вот в этом и проблема, что я не знаю как этот запрос составить, в папке хендлеров пересмотрел все, но ничего не понял... есть таблица og_membership в ней поле etid нужно сделать 2 запроса базе данных. этот код работает
то есть, нужно чтобы фильтр смотрел к какой группе принадлежит текущий пользователь и выводил только тех пользователей, с которыми он в одной группе
так понимаю вам нужно приджойнить таблицу? ищите примеры использования $this->query->add_table()
что-то нихрена не понял куда какой файл класть. Хотел сделать выборку 5 ближайших событий по дате указанной в типе материала.
В общем, в дополнение к предыдущей статье, если вы хотите добавить фильтр не к новой, а к существующей entity, нужно делать так:
hook_views_data в этом случае не нужен.
Подскажите пожалуйста, как написать модуль для зависимости фильтров.
Очень помогло! Спасибо
Notice: Undefined index: mycustomfilter в функции views_handler_filter->accept_exposed_input() как исправить?
Спасибо за статью, получилось сделать сложный фильтр на основе views_handler_filter_numeric.inc
Теперь стоит задача сделать фильтр с выбором вариантов, пытаюсь сделать по аналогии с views_handler_filter_node_type.inc:
Фильтр создается, все замечательно.
Подскажите пожалуйста, где теперь прописывать сами условия фильтрации?
Все, сама разобралась, также в function op_simple()
Подскажите пожалуйста где мне взять название "таблицы_с_полем" которая применяется в этом коде... про который упоминалось выше... разбираю эту тему и немного запутался что куда
Статья очень важная и нужная. Полагаю, решение моей задачи где-то рядом. Может быть подскажете?
Есть два критерия фильтрации, у обоих стоит отметка «помнить последнее значение». Задаю значерия в URL (?a=1&b=2), но Drupal их помнит лишь до тех пор, пока одно из значений не будет изменено (например, если задам в адресе ?b=3). Где / что нужно переопределить, чтобы менялось только то значение, которое задано, а незаданные значения были взяты с «прошлого раза»?
А если мне например нужно через views вывести словарь в котором 200 терминов, и каждый термин мне нужно отфильтровать на наличие контента и к примеру я уже сделал хендлер который это делает. В этом случае views сделает 200 запросов в базу данных?
Добавить комментарий