9 января 2012. 13:11
Views — очень классный модуль. Он позволяет сэкономить километр времени, когда нужно сделать простые сборные страницы. Но в нем иногда не хватает гибкости. Например, для темизации. Либо для построения нужной структуры адресов. Либо в случае, когда нужно сделать сложную логику какого-нибудь каталога. Не важно. Суть в том, что зачастую проще написать простой модуль, чем извращаться с Views и темизацией полей. (С таксономией та же ерунда, между прочим.)
Я хочу показать, как просто создавать сборные страницы (и не только) программно — через модули. Достаточно знать пару хуков. Снипеты, которые я приведу ниже, я сохранил себе в Эверноуте — очень удобно.
Скажем, модуль, который мы напишем, будет называется catalog. Создаем папку catalog в sites/all/modules. В нем — два файла: catalog.info и catalog.module.
В файле catalog.info — служебная информация о модуле:
name = "Catalog"
description = "Catalog module"
package = "Custom"
core = 6.x
Открываем файл catalog.module и добавим в реестр меню пока только главную страницу каталога:
/**
* Implementation of hook_menu ().
*/
function catalog_menu () {
$items['catalog'] = array (
'title' => t ('Catalog'),
'page callback' => 'catalog_catalog',
'access callback' => TRUE,
);
return $items;
}
function catalog_catalog () {
$output = 'Hello, world!';
return $output;
}
Русским языком: функция catalog_menu () возвращает массив элементов меню $items. Ключ каждого нового пункта меню есть его адрес. В данном случае, мы добавили страницу с адресом /catalog. У страницы каталог будет заголовок Catalog (либо его перевод, если доступен). Содержимое страницы будет определятся тем, что вернет функция catalog_catalog (), которую мы указали в качестве page callback. У этого хука может быть много параметров. Эта заметка их не освещает. Подробнее об этом хуке вы можете узнать в API Друпала или, например, в книге Pro Drupal Development Джона Вандюка.
Идем на страницу со списком модулей admin/build/modules и включаем наш модуль.
Страница готова. Это основа. Будем усложнять путь аргументами.
Аргументы
Допустим. Наша задача — построить каталог изданий с возможностью выборки за год, за месяц и страница издания. Не будем спорить о том, что это можно сделать с помощью Вьюс. Цель этой заметки совсем другая.
Итак. Для газеты «Три топора» возможные страницы каталога будут такими:
-
/catalog
-
/catalog/tri-topora
-
/catalog/tri-topora/2012
-
/catalog/tri-topora/2012/01
Добавляем в catalog_menu () новые элементы массива, заменяя аргументы знаком процента %:
/**
* Implementation of hook_menu ().
*/
function catalog_shelves_menu () {
$items['magazines'] = array (
'title' => t ('Catalog'),
'page callback' => 'catalog_catalog',
'access callback' => TRUE,
);
$items['catalog/%/%'] = array (
'title' => t ('Catalog'),
'page callback' => 'catalog_catalog',
'access callback' => TRUE,
'page arguments' => array (1, 2),
);
$items['catalog/%/%/%'] = array (
'title' => t ('Catalog'),
'page callback' => 'catalog_catalog',
'access callback' => TRUE,
'page arguments' => array (1, 2, 3),
);
return $items;
}
Отмечу, что любые изменения hook_menu () требуют очистки друпаловского кэша.
Все, что в адресе может меняться, мы заменяем % и определяем их как аргументы, которые передаются функции catalog_catalog (). Кстати, она тоже теперь измениться:
function catalog_catalog ($edition = NULL, $year = NULL, $month = NULL) {
$output = '';
$edition;
$year;
$month;
if (is_numeric ($month)) {
//страница выпусков за месяц
//делаем запрос к базе, который вернет все выпуски газеты за месяц
$query = '...‘;
} else {
if (is_numeric ($year)) {
//страница выпусков за год
//делаем запрос к базе, который вернет все выпуски газеты за год
$query = '...';
} else {
//страница выпусков всего издания
//делаем запрос к базе, который вернет все выпуски газеты за все время
$query = '...‘;
}
}
}
while ($result = db_fetch_object ($query)) {
//рендерим по очереди все выпуски
}
return $output;
}
Все страницы каталога у нас обращаются к одной и той же функции — catalog_catalog (). Определяем типа страницы исходя из аргументов. Делаем нужный запрос к базе. Рендерим в HTML результаты запроса.
На данном этапе ядро каталога уже готово. Осталось заморочится с мелочами.
Рендеринг
Хорошо будет, если мы не будем мешать логику приложения с отображением. Через hook_theme () создадим новый элемент темизации issue и воспользуемся им в теле цикла while функции catalog_catalog ():
while ($result = db_fetch_object ($query)) {
//рендерим по очереди все выпуски
$output .= theme ('issue', $result);
}
Для этого нужно зарегистрировать в реестре элемент issue:
function catalog_theme () {
return array (
'issue' => array (
'arguments' => array ('form' => NULL),
),
);
}
И, наконец, определить функцию, которая и будет отвечать за рендеринг issue:
function theme_issue ($issue) {
$output = '<div class="b-issue">' . l ($issue->title, 'node/' . $issue->nid) . '</div>';
return $output;
}
Чистим кэш. Обновляем страницу.
Манипулирование заголовком
Заголовки можно изменять прямо в теле функции-колбэка. Так, в зависимости от типа страницы, мы можем определять заголовок страницы через функцию drupal_set_title ();.
Страница издания. Почему ее нет в хуке меню
Внимательный читатель мог заметить, что в hook_menu () мы не зарегистрировали путь страницы издания — catalog/%.
Давайте для интереса рассмотрим случай, если бы мы определили издание как самостоятельный тип контента Edition. Делаем у Edition алиас catalog/[title]. Тогда нужный нам адрес catalog/% — это страница ноды типа Edition.
Создаем файл node-edition.tpl.php. В файле пишем:
if ($page) {
echo catalog_catalog ($issue_title);
}
$issue_title — это аргумент пути. Не путать с $node->title.
Готово. На странице ноды будет выводиться то, что мы определим для страницы выпусков всего издания в модуле catalog.
Каталог изданий готов. Это простейший случай. Но у вас в руках есть очень гибкий инструмент — непосредственно язык программирования, а не ограниченный в возможностях графический интерфейс. Я считаю, что это здорово!
Успехов!