Как подружить свой тип данных с Views
При разработке модулей для Drupal мы частенько создаем программно новые типы материалов (то есть нод). В процессе иногда возникает соблазн быстренько запрограммировать вывод какой-нибудь отсортированной коллекции этих материалов. Например, вывод нод-городов, отсортированных по алфавиту, или по древности, или сгруппированных по странам. Таких полезных коллекций может образоваться достаточно много и программно создавать каждую из них — не очень эффективно. Особенно если впоследствии нам захочется что-то поменять, объединить, или переделать. Гораздо аккуратнее — использовать модуль Views.
Вообще говоря, Views — один из краеугольных камней разработки на Drupal. Хотите помесячный архив нод? Views. Хотите вывести только заголовки и даты нод? Views. Хотите вывести ноды, сгруппированные по именам авторов? Views. Хотите получить список IP, с которых пользователь Василий заходил на сайт в течение Великого поста? Тоже Views. Один из самых популярных ответов на вопрос «Как в Друпале сделать…» — Views. Так что, чем быстрее разработчик подружится с этим прекрасным модулем — тем лучше. Для этого, кстати, есть неплохой мануал на английском языке: http://views-help.doc.logrus.com/.
Однако как только разработчик захочет получить с помощью Views коллекцию созданных им данных — например, из самодельной таблицы, сделанной для нового типа материала — он обнаружит, что Views еще не знает о его таблице. Так вот, раз и навсегда рассказать о своей таблице модулю Views — на мой взгляд, гораздо более правильное решение, чем программировать вручную все необходимые представления.
Далее — о том, как это сделать.
Предполагаю, что читатель уже умеет программно создавать свои типы материалов. Рассказывать буду на примере модуля, в котором новый тип уже создан. А чтобы не публиковать код модуля с описанием нового типа, предлагаю просто его скачать:
Скачать модуль mytest.
В модуле уже реализовано все, о чем дальше пойдет речь в заметке.
Итак, у нас есть тип материала testnodeint_countint_total{testnode}
Перво-наперво, доложим Views о том, какую версию API мы используем (а используем мы версию Views 2.8 с Drupal 6.x). Для этого добавим в наш файл mytest.module вызов хука hook_views_api
Затем создадим файл mytest.views.inc, в котором модуль Views самостоятельно сможет найти вызов нужных хуков. Пришла пора рассказать Views про нашу таблицу. Для этого используется хук hook_views_data()$data['имя_таблицы']['имена_полей']$data['имя_таблицы']['table']
Подмассив ['table']['group']['table']
Прежде чем перечислять поля таблицы {testnode}{testnode}
Для каждого поля нашей таблицы мы можем указывать следующую информацию:
— заголовок поля, таким он будет показан пользователю в интерфейсе Views;['title'] — если хочется, можем указать для поля группу, отличную от указанной в['group'] ;['table'] — здесь можно задать текст подсказки по данному полю, который пользователь увидит мелким шрифтом рядом с заголовком;['help'] — если в массиве $['real field'] мы в качестве ключа указали для данного поля синоним, то в$data нужно привести настоящее название поля в таблице БД.['real field']
Перечисленные элементы — заголовок, помощь, группа — имеют скорее декоративное назначение. Кроме них нам нужно заполнить элементы массива, имеющие непосредственное отношение к логике работы Views. Это элементы ['field']['filter']['sort']['argument']['relationship']['handler']['handler']
Здесь нужно еще одно лирическое отступление. В отличие от ядра Друпала и большинства сторонних модулей, API модуля Views — объектно-ориентированный (насколько это возможно). Товарищей, привыкших программировать под Друпал, Views API может несколько смутить, но смею заверить: это плюс, а не минус. Кстати, по поводу отсутствия объектно-ориентированного подхода в «капельке» разные граждане периодически поднимают бучу. Автор статьи, однако, относится к этой особенности безразлично и принимает ее как данность, с которой нужно работать, а не хаять почем зря.
Рассмотрение объектно-ориентированной модели Views API, в принципе, должно быть темой отдельной большой статьи. Поэтому здесь коснемся только того, что нас непосредственно волнует, то есть хэндлеров. Понимающий английское письмо читатель может ознакомиться с подробным описанием Views API на сайте: http://views2.logrus.com/doc/html/index.html.
Корнем модели является класс views_objectviews_handlerviews_handler{testnode}
Хэндлеры бывают очень разные в зависимости от типа данных, необходимого эффекта, оказываемого ими на запрос, сложности фильтра, который мы хотим использовать и тому подобное. Для нашего тестового модуля нам понадобятся хэндлеры views_handler_fieldviews_handler_filter_numericviews_handler_sort{testnode}
Теперь необходимо снова вернуться к секции ['table']$data['testnode']$data['имя_таблицы']['table']['base']['field']['title']['help']['database']
Но в рассматриваемом примере таблица не базовая, поэтому рассмотрим другой массив — $data['имя_таблицы']['table']['join']{testnode}
Поскольку в нашей таблице содержатся поля для нового типа ноды testnode, очевидно, что мы хотели бы присоединить их к таблице {node}int_countint_total['join']['node']'left_field'{node}'field'{testnode}nid
На этом интеграция таблицы {testnode}int_countint_total
Теперь же решим задачу добавления к «вьюхе» виртуального, то есть несуществующего в таблице {testnode}percentageint_countint_total(int_count*100/int_total)
Во-первых, нам необходимо добавить поле percentage['field']
Очевидно, мы не можем использовать стандартный field-хэндлер, поскольку он добавит в SQL-запрос поле 'percentage'{testnode}mytest_handler_field_percentage
В качестве родительского мы берем хэндлер views_handler_field_numericquery()query()
Затем озаботимся результатом, который будет записан в поле после выполнения запроса Views. За это отвечает метод render($values)$valuesrender()int_countint_total{testnode}int_countint_totalrender()int_countint_totalpercentageadd_additional_fields()int_countint_totaladditional_fieldquery()
Теперь, когда новое виртуальное поле описано, мы бы хотели иметь возможность сортировать по нему коллекции данных. Для этого подходит уже существующий хэндлер views_handler_sort_formula
Еще мы хотели бы научить Views фильтровать выборку из БД по виртуального полю percentage
Хэндлер mytest_handler_filter_percentage
Здесь мы переопределяем метод query()$this->ensure_my_table()int_countint_total$field
Наконец, прежде чем Views увидит наши новые хэндлеры, необходимо добавить в файл mytest.views.inc реализацию хука hook_views_handlers
Хук просто возвращает массив новых хэндлеров с информацией о том, какие классы-хэндлеры они наследуют и в каких файлах их искать.
Вот и все. Мы научили Views считывать, выводить и использовать для сортировки и фильтрации результатов запроса виртуальное поле percentage'admin/build/views/tools'
| Прикрепленный файл | Размер |
|---|---|
| mytest.tar.gz | 3.18 кб |
Пожалуйста. К сожалению, информация по Views API очень скудная не только на русском, но и на английском. Поэтому видимо инициативные пользователи Друпала должны сами стараться писать всякое про Views, чтобы набралась критическая масса статей. Тогда общими стараниями мы приблизимся к светлому будущему :)
Поскольку нет инфы о апи, очень помогает разбор инклудов в /views/modules, например из /views/modules/node.views.inc я узнал как выводить поле ввиде даты.
Вообще, по API есть информация, в заметке есть ссылки на нее.
Правда, некоторые вещи там не до конца описаны или вовсе не описаны, да, поэтому приходится выискивать их в коде.
А работали с числовыми полями, которые являются ключами от массива значений?
Например хранится в базе поле статус. Но мне при работе со views хочется видеть не сухие цифры, а их значения:
array(
'1' => 'Проект',
'2' => 'На согласовании',
'3' => 'Активный',
'4' => 'Закрыт',
'5' => 'Архив',
);
Почитал документацию по API — вобще скудно
Навскидку — через свой филд-хэндлер и метод render() легко делается, примерно так:
Спасибо за помощь!
Но что то не работает. Во вьюсах вылазит ошибка
«Error: handler for question > status doesn't exist!»
А попутно у меня еще задача выросла. Мне нужно добавить к вьюсам виртуальное поле, которое представляет собой сумму связанных полей из другой таблицы. Например, есть вопрос, а к нему надо добавить виртуальное поле — количество ответов для этого вопроса.
Это нужно опять же свой хендлер и определить там как то функцию function query() ?
Но что то не работает. Во вьюсах вылазит ошибка
«Error: handler for question > status doesn't exist!"
Насчет документации views — все основы изложены в самом модуле, просто нужно поставить модуль advanced_help
Да я как-то в курсе. Речь про особенности API, а не про работу с модулем.
Дык там и особенности API расписаны, как и для панелей.
Угу. Там копия вот этого: http://views-help.doc.logrus.com/. Ну или наоборот, по адресу — копия advanced_help-а по Views :) По мне, так для работы с API этого не совсем достаточно. Вот тут получше: http://views2.logrus.com/doc/html/index.html, но тоже мало и недоработано, в куче мест просто куски кода, без какого-либо описания логики.












Спасибо за статью. Для меня это послужило отправной точкой. За выходные более менее вник в азы и сам тоже небольшую заметку выложил по этой теме: http://www.allexx.info/drupal_views_api_1st_example