Разработка модуля для Drupal. Часть3. Cron и темизация
Регулярные процедуры
Чтобы Drupal периодически выполнял определенные действия, в планировщике задач операционной системы необходимо настроить запуск файла cron.php, который находится в корне каждого Drupal-сайта. При выполнении этого файла будет вызываться хук hook_cron, и в нашем модуле мы напишем его реализацию.
Процедура получения и обработки XML-файла, расположенного на удаленном сервере, довольно проста, поэтому она здесь не приведена. При желании вы можете самостоятельно разобрать логику работы этой функции, изучив исходные коды модуля Currencies. В результате ее работы формируется массив $result
, в котором содержится информация о курсах валют и который передается функции темизации.
function currencies_cron() {
currencies_contents();
}
Функцию currencies_contents() см. в листинге 3.
Листинг 3
function currencies_contents() {
if(!$c = cache_get('currencies')) {
/* здесь пропущен код, отвечающий за получение
и обработку XML-файла */
$output = theme('currencies_block', $result);
$t = variable_get('currencies_list_freq', 3600);
if(!$t || !is_numeric($t)) $t = 3600;
cache_set("currencies", $output, 'cache', time() + $t);
} else {
$output = $c->data;
}
return $output;
}
Здесь мы сначала проверяем, нет ли запрашиваемых данных в кэше Drupal, если нет, то происходит соединение с удаленным сервером (его адрес указан через административный интерфейс модуля), получение и обработка XML-файла и формирование массива данных, который передает функции темизации. Функция темизации формирует выходной HTML-код, записываемый в кэш, его время жизни явно указывается исходя из соответствующей настройки, заданной в интерфейсе управления модулем. Drupal автоматически управляет закэшированными данными и при необходимости удаляет устаревшие записи.
Функция currencies_contents() будет использоваться не только при запуске cron-задания, но и при формировании блока с данными, который будет показываться пользователю. Таким образом, практически всегда пользователи будут видеть данные, полученные из кэша Drupal, если же на сайте не работает cron и нет закэшированных данных о курсах валют, то произойдет соединение с сервером ЦБ, формирование и запись в кэш необходимых данных.
Функции темизации
Теперь подробнее остановимся на функциях темизации. Теоретически прямо в коде функции currencies_contents() можно было бы сформировать HTML-код, который в дальнейшем и видел бы посетитель сайта в браузере. Однако такой подход неверен, поскольку при изменении оформления данных пришлось бы менять код модуля, а это влечет за собой две проблемы. Во-первых, модуль могут использовать сторонние разработчики, и им для внесения изменений придется вникнуть в структуру модуля и внести в него изменения, которые могут привести к ошибкам. Во-вторых, часто при разработке крупных проектов версткой и программированием занимаются разные люди. Верстальщик может не иметь представления о том, как работать с языком PHP в целом и модулями Drupal в частности. По этому правильнее вынести все действия, связанные с оформлением данных, в отдельные файлы и функции, для чего и нужны функции темизации.
Функции темизации — это функции, генерирующие HTML-код, который впоследствии показывается пользователю. Особенность таких функций в том, что, во-первых, они не должны реализовывать никакой бизнес-логики, т. е. в их задачи входит только генерирование HTML-кода на основе полученных аргументов. Во-вторых, эти функции могут быть переопределены разработчиком сайта без редактирования кода модуля, путем изменения файла template.php или создания файла-шаблона.
В нашем случае массив данных формируется функцией currencies_contents(), а HTML-код создается функцией theme_currencies_block(), которую нам сейчас предстоит определить и зарегистрировать. Подчеркну, что вызов любой функции темизации осуществляется через вызов функции-обертки с именем theme(), т. е. функция theme_currencies_block($argument) должна вызываться как theme(‘currencies_block’, $argument). Чем вызвана эта необходимость, я объясню чуть позже.
Для регистрации функций темизации, используемых в модуле, мы должны реализовать hook_theme, который возвращает массив имен применяемых функций темизации и принимаемых ими параметров. В нашем модуле будет использоваться одна функция темизации theme_currencies_block(), которая на вход принимает один обязательный аргумент — массив курсов валют, поэтому реализация хука hook_theme будет выглядеть так:
function currencies_theme() {
return array(
'currencies_block' => array(
'arguments' => array('result' => NULL),
),
);
}
Без такой регистрации вызов theme(‘currencies_block’, $argument) будет невозможен. Сама функция темизации будет такой:
function theme_currencies_block($result) {
$output = "";
foreach($result as $k => $v) {
if($v["diff"] > 0) {
$color = "#5aaf43";
$v["diff"] = "+" . $v["diff"];
}
else if($v["diff"] < 0) $color = "#f00";
else if($v["diff"] == 0) $color = "#00f";
$output .= "-" . $v["nominal"] . " " . $v["name"] . " = "
. $v["value"] . " (<span style=\"color: " . $color . "\">"
. $v["diff"] . "</span>)
";
}
$output .= "";
return $output;
}
Еще раз обратите внимание на то, что в функции currencies_theme в качестве имени функции темизации указывается название currencies_block, а реализация ее имеет имя theme_currencies_block(). Нужно это, чтобы в дальнейшем разработчики сайтов, использующие наш модуль, могли переопределить эту функцию, т. е. изменить формируемый ею HTML-код. Для этого им в папке со своей темой в файле template.php достаточно будет создать функцию с именем, совпадающим с именем функции темизации, но в котором слово _theme _заменено на название используемой темы оформления, т. е. создать функцию _название_темы_оформленияcurrencies_block(). Ядро Drupal, когда встретит в коде модуля вызов вида theme(‘currencies_block’, $result), сначала попробует найти функцию темизации в файле template.php используемой в данный момент темы оформления, и только если там ее не найдет, использует функцию theme_currencies_block().
В случае больших шаблонов удобнее вынести функцию темизации из файла template.php в отдельный файл. Для этого в массиве, возвращаемом реализацией хука hook_theme, нужно добавить элемент с ключом _template _и именем, соответствующим имени файла-шаблона, а в каталоге с модулем разместить файл-шаблон с указанным ранее именем и расширением .tpl.php. В итоге hook_theme() примет вид:
function currencies_theme() {
return array(
'currencies_block' => array(
'arguments' => array('result' => NULL),
'template' => 'cur-block',
),
);
}
а в папке с модулем нужно разместить файл с именем cur-block.tpl.php и таким содержимым:
foreach($result as $k => $v) {
if($v["diff"] > 0) {
$color = "#5aaf43";
$v["diff"] = "+" . $v["diff"];
}
else if($v["diff"] < 0) $color = "#f00";
else $color = "#00f";
print "-" . $v["nominal"] . " " . $v["name"] . " = " .
$v["value"] . " (<span style=\"color: " . $color . "\">" .
$v["diff"] . "</span>)
";
}
Теперь, чтобы переопределить вывод данных, формируемых модулем Currencies, разработчику достаточно скопировать файл cur-block.tpl.php из папки с модулем в папку с используемой темой оформления и внести в него необходимые изменения.
Интерфейс пользователя
Сейчас наш модуль имеет интерфейс администратора, умеет автоматически соединяться с удаленным сервером, получать необходимую информацию, формировать из нее HTML-код и сохранять его в кэше. Осталась самая простая для программиста и наиболее значимая для посетителя сайта часть — вывод данных на экран.
Для решения этой задачи мы могли бы через созданную ранее функцию currencies_menu() зарегистрировать еще один путь и в качестве параметра page callback указать функцию currencies_contents(), которая получила бы необходимые данные (из кэша или от удаленного сервера) и вывела бы их на экран через функцию темизации. Но мы хотим, чтобы курсы валют выводились не отдельной страницей, а в блоке (оформленный особым образом элемент, содержащий данные) на любой заданной администратором сайта странице. Для этого необходимо создать реализацию хука hook_block() (см. листинг 4).
Листинг 4
function currencies_block($op = 'list', $delta = 0,
$edit = array()) {
switch ($op) {
case 'list':
$blocks[0] = array(
'info' => t('Currencies block'),
);
return $blocks;
case 'view':
switch ($delta) {
case 0:
$block['subject'] = t('Currencies block');
$block['content'] = currencies_contents();
break;
}
return $block;
}
}
Параметр $op (сокращение от operation), содержит информацию о том, какая операция над блоком в данный момент выполняется. Значение _list _сообщает модулю, что информация о нем выводится в списке модулей, здесь мы должны передать ядру Drupal один обязательный параметр — заголовок модуля и ряд необязательных параметров, информацию о которых можно найти в документации.
Значение _view _аргумента $op означает, что пользователь просматривает страницу, на которой должен быть отображен наш блок, и модуль обязан вернуть его содержимое. Для этого функция должна сформировать и выдать ассоциативный массив, элемент с ключом _content _которого будет использован в качестве содержимого блока, а необязательный элемент с ключом _subject _— заголовка.
Каждый модуль может создавать несколько блоков, параметр $delta хука hook_block содержит индекс обрабатываемого в текущий момент блока.
Все, разработка модуля завершена! Теперь администратор сайта, после инсталляции модуля Currencies, может активировать созданный им блок, для этого необходимо перейти в меню Administer — Blocks (admin/build/block), перетащить мышкой строку с описанием блока в нужный регион (область страницы, которая может содержать один или несколько блоков) и сохранить изменения. В свойствах модуля доступны стандартные для Drupal средства управления блоком: список страниц, на которых блок должен показываться (или наоборот список страниц, на которых блок не должен показываться), список ролей пользователей, которые имеют доступ к содержимому блока, и другие.
Ссылки на другие части этой статьи:
- Часть 1. Основы модульной системы Друпала
- Часть 2. Разработка простейшего модуля
- Часть 3. Введение в темизацию Друпала (для программистов, а не дизайнеров)
Содержание всех статей: /blog/2010/my-drupal-articles