Журнал PC Magazine/RE №09/2009 — страница 26 из 33

ализации формы настроек модуля при помощи функции user_access, будем проверять, имеет ли текущий пользователь право доступа access currencies block settings или нет.

Важный момент. Пользователь с uid=1, т. е. первый созданный в системе, является суперпользователем, для него функция user_access всегда возвращает значение TRUE, а это значит, что он всегда имеет доступ ко всем функциям сайта. Это одна из причин, почему не рекомендуется работать в системе с учетной записью суперпользователя: зачастую разработчики забывают раздавать пользователям необходимые права доступа, так как сами, работая как суперпользователи, не имеют проблем с доступом к ресурсам сайта.

Для определения дополнительного системного пути, по которому в нашем примере будет доступна страница управления модулем, необходимо создать реализацию хука hook_menu:

function currencies_menu() {

  $items = array();

  $items['admin/settings/cur-block'] = array(

    'title' => t('Currencies block settings'),

    'description' => 'Currencies block settings.',

    'page callback' => 'drupal_get_form',

    'page arguments' => array('currencies_settings'),

    'access arguments' => array('access cur block settings'),

  );

  return $items;

}

Эта функция также возвращает ассоциативный массив. Ключом каждого элемента массива должен быть путь, регистрируемый в системе (в нашем случае это admin/settings/cur-block), а значением – вложенный массив, содержащий информацию о создаваемом пункте меню. Давайте разберем каждый из параметров отдельно.

Title – заголовок меню – будет использоваться при переходе на страницу с адресом admin/settings/cur-block в строке заголовка браузера (тег ) и в качестве заголовка страницы (тег <h1>), а также в качестве текста ссылки, ведущей на созданную страницу настроек.</p><p>Description – описание пункта меню, которое в нашем случае будет использоваться на странице администрирования.</p><p>Page callback – функция, которая будет генерировать страницу, создаваемую по указанному пути. В простом случае значением этого параметра должна быть функция, возвращающая HTML-код, который будет показан пользователю. Однако мы по указанному адресу создаем не обычную страницу, а форму, значения которой автоматически сохраняются в БД. Поэтому для параметра page callback мы назначаем вызов системной функции drupal_get_form(), которая выведет на экран форму, созданную функцией с именем, указанным в элементе массива page arguments; в нашем случае это функция currencies_settings(). Функция currencies_settings() должна вернуть ассоциативный массив, содержащий информацию об элементах создаваемой формы. Подробнее об этом массиве будет рассказано ниже.</p><p>Access arguments – массив «прав доступа». Пользователи, обладающие правами доступа, перечисленными в этом массиве, могут получить доступ к создаваемому пункту меню.</p><div class='cite'><div class='subtitle'>Подготовка Web-страницы</div><p>Тема оформления в Drupal – это набор особым образом сформированных HTML-шаблонов и CSS-файлов, на основе которых ядро Drupal генерирует запрашиваемую пользователем страницу. Если в системе используется встроенный в Drupal шаблонный «движок» PHPTemplate, то каждая тема оформления может содержать служебный файл template.php, в котором могут размещаться функции, переопределяющие стандартный вывод модулей. У каждой темы оформления, как и у каждого модуля, должно быть свое уникальное имя и файл настроек .info.</p></div><p>Более подробную информацию о параметрах пунктов меню можно найти в документации.</p><p>Сейчас в нашем модуле определен новый пункт меню, но не определена функция, формирующая содержимое страницы, на которую этот пункт указывает (см. листинг 2).</p><div class='cite'><div class='subtitle'>Листинг 2</div><p>function currencies_settings() {</p><p>  $form['currencies_list'] = array(</p><p>    '#type' => 'textfield',</p><p>    '#title' => t('Currencies'),</p><p>    '#default_value' => variable_get('currencies_list',</p><p>      "USD,EUR,CNY,BYR,KZT,TRY,UAH,JPY"),</p><p>    '#maxlength' => 255,</p><p>  );</p><p>  $form['currencies_list_freq'] = array(</p><p>    '#type' => 'textfield',</p><p>    '#title' => t('Frequency of updating of the data</p><p>      (in seconds)'),</p><p>    '#default_value' => variable_get('currencies_list_freq',</p><p>      3600),</p><p>    '#maxlength' => 255,</p><p>    '#description' => t('It is recommended to use value</p><p>      not less than 3600.'),</p><p>  );</p><p>  $form['currencies_list_url'] = array(</p><p>    '#type' => 'textfield',</p><p>    '#title' => t('Адрес xml-файла'),</p><p>    '#default_value' => variable_get('currencies_list_url',</p><p>      "http://www.cbr.ru/scripts/XML_daily.asp?date_req=</p><p>      %d/%m/%y"),</p><p>    '#maxlength' => 255,</p><p>    '#description' => t('The XML-file address.'),</p><p>  );</p><p>  return system_settings_form($form);</p><p>}</p></div><p>Как и хуки hook_menu, hook_schema и многие другие хуки Drupal, эта функция должна возвращать ассоциативный массив, на этот раз содержащий информацию о параметрах создаваемой формы. Здесь мы создаем три однострочных текстовых поля (параметр #type имеет значение textfield), значения по умолчанию для которых (параметр #default_value) будут храниться и выбираться из стандартной таблицы variables Drupal при помощи функций variable_set() и variable_get(). Благодаря использованию функций drupal_get_form и system_settings_form нет необходимости заботиться о создании кнопок Submit и Reset, а также о функциях, обрабатывающих и сохраняющих данные формы. В более сложных случаях, которые будут рассмотрены в следующей статье, придется вручную создавать функции проверки введенных пользователем значений и сохранения данных.</p><p>Подробное описание типов полей, используемых в формах, можно найти в документации.</p><p>Все, мы завершили разработку первой из трех частей нашего модуля – административного интерфейса и переходим к разработке второй его части – инструмента получения данных от удаленного сервера.</p><div class='subtitle'>Регулярные процедуры</div><p>Чтобы Drupal периодически выполнял определенные действия, в планировщике задач операционной системы необходимо настроить запуск файла cron.php, который находится в корне каждого Drupal-сайта. При выполнении этого файла будет вызываться хук hook_cron, и в нашем модуле мы напишем его реализацию:</p><div class='cite'><p>function currencies_cron() {</p><p>  currencies_contents();</p><p>}</p></div><p>Процедура получения и обработки XML-файла, расположенного на удаленном сервере, довольно обычна, поэтому она здесь не приведена. При желании вы можете самостоятельно разобрать логику работы этой функции, изучив исходные коды модуля Currencies, которые есть на диске, прилагаемом к журналу. В результате ее работы формируется массив $result, в котором содержится информация о курсах валют и который передается функции темизации. Функцию currencies_contents() см. в листинге 3. Здесь мы сначала проверяем, нет ли запрашиваемых данных в кэше Drupal, если нет, то происходит соединение с удаленным сервером (его адрес указан через административный интерфейс модуля), получение и обработка XML-файла и формирование массива данных, который передает функции темизации. Функция темизации формирует выходной HTML-код, записываемый в кэш, его время жизни явно указывается исходя из соответствующей настройки, заданной в интерфейсе управления модулем. Drupal автоматически управляет закэшированными данными и при необходимости удаляет устаревшие записи.</p><div class='cite'><div class='subtitle'>Листинг 3</div><p>function currencies_contents() {</p><p>  if(!$c = cache_get('currencies')) {</p><p>    /* здесь пропущен код, отвечающий за получение</p><p>       и обработку XML-файла */</p><p>    $output = theme('currencies_block', $result);</p><p>    $t = variable_get('currencies_list_freq', 3600);</p><p>    if(!$t || !is_numeric($t)) $t = 3600;</p><p>    cache_set("currencies", $output, 'cache', time() + $t);</p><p>  } else {</p><p>    $output = $c->data;</p><p>  }</p><p>  return $output;</p><p>}</p></div><p>Функция currencies_contents() будет использоваться не только при запуске cron-задания, но и при формировании блока с данными, который будет показываться пользователю. Таким образом, практически всегда пользователи будут видеть данные, полученные из кэша Drupal, если же на сайте не работает cron и нет закэшированных данных о курсах валют, то произойдет соединение с сервером ЦБ, формирование и запись в кэш необходимых данных.</p><div class='subtitle'>Функции темизации</div><p>Теперь подробнее остановимся на функциях темизации (theming; термин не слишком благозвучен, но уже стал общепринятым). Теоретически прямо в коде функции currencies_contents() можно было бы сформировать HTML-код, который в дальнейшем и видел бы посетитель сайта в браузере. Однако такой подход неверен, поскольку при изменении оформления данных пришлось бы менять код модуля, а это влечет за собой две проблемы. Во-первых, модуль могут использовать сторонние разработчики, и им для внесения изменений придется вникнуть в структуру модуля и внести в него изменения, которые могут привести к ошибкам. Во-вторых, часто при разработке крупных проектов версткой и программированием занимаются разные люди. Верстальщик может не иметь представления о том, как работать с языком PHP в целом и модулями Drupal в частности. По этому правильнее вынести все действия, связанные с оформлением данных, в отдельные файлы и функции, для чего и нужны функции темизации.</p><div class='cite'><p>Функции темизации – это функции, генерирующие HTML-код, который впоследствии показывается пользователю.</p></div><p>Функции темизации – это функции, генерирующие HTML-код, который впоследствии показывается пользователю. Особенность таких функций в том, что, во-первых, они не должны реализовывать никакой бизнес-логики, т. е. в их задачи входит только генерирование HTML-кода на основе полученных аргументов. Во-вторых, эти функции могут быть переопределены разработчиком сайта без редактирования кода модуля, путем изменения файла template.php или создания файла-шаблона.</p> <div class="pagination"> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/25/">Предыдущая</a> <span>Стр. 26 из 33</span> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/27/">Следующая</a> </div> </main> <footer> <div class="footer-content"> <div class="center"> <a href="/contact/">Связь с администрацией</a> <a href="/privacy/">Обработка персональных данных</a> </div> </div> </footer> <div id="tocModal"> <div class="modal-content"> <h3>Оглавление</h3> <p><a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/">К карточке книги</a></p> <ul> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/1/#1"> Новости Новости и комментарии: pcmag.ru/news </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/1/#2"> …плюс викификация вооруженных сил </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/1/#3"> Австралия – земля несвободы </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/1/#4"> Техасское правосудие: Microsoft – 2:0 </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/1/#5"> Интернет-няня с отечественным лицом </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/1/#6"> Тайное становится явным </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/2/#7"> Время закрывать Wintel? </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/2/#8"> Беззащитная клавиатура </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/2/#9"> Интернет как сон суперпингвина </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/2/#10"> Актуальные новинки </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/3/#11"> На первый взгляд Новинки индустрии: pcmag.ru/guide/ </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/4/#12"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/5/#13"> Лаборатория Тесты и обзоры: pcmag.ru/reviews </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/5/#14"> Программы </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/6/#15"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/7/#16"> Проекторы </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/8/#17"> Сканеры </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/8/#18"> Электронные книги </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/9/#19"> Системные платы </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/10/#20"> Гид покупателя </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/10/#21"> Коммуникаторы: парад тенденций </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/11/#22"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/12/#23"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/13/#24"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/14/#25"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/15/#26"> Инфраструктура </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/15/#27"> В преддверии SaaS </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/16/#28"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/17/#29"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/18/#30"> Сделай сам </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/18/#31"> Игры по сети WiFi: настройка маршрутизатора </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/19/#32"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/20/#33"> Короли, капуста и… компьютеры Мнения и мысли: pcmag.ru/columns </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/20/#34"> Facebook и Twitter: битва за знаменитостей </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/21/#35"> Разработка ПО </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/21/#36"> «Лента друзей»: разрабатываем компонент «1С-Битрикс» </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/22/#37"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/23/#38"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/24/#39"> Drupal: разработка модуля </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/25/#40"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/26/#41"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/27/#42"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/28/#43"> Операционные системы </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/28/#44"> Windows 7: новые средства управления энергопотреблением </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/29/#45"> Проблемы и решения Советы и секреты: pcmag.ru/solutions/ </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/29/#46"> Mac под управлением Windows </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/30/#47"> Социальные сети: осторожно, Facebook! </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/31/#48"> Мгновенные сообщения как офисный инструмент </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/32/#49"> *** </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/33/#50"> Читайте в следующих номерах </a> </li> <li> <a href="/zhurnal-pc-magazine-re-09-2009-pc-magazine-re-id398241/read/notes/#0"> Примечания </a> </li> </ul> </div> </div> <script src="/static/reader.js"></script> <!-- Yandex.Metrika counter --> <script type="text/javascript"> (function (m, e, t, r, i, k, a) { m[i] = m[i] || function () { (m[i].a = m[i].a || []).push(arguments) }; m[i].l = 1 * new Date(); for (var j = 0; j < document.scripts.length; j++) { if (document.scripts[j].src === r) { return; } } k = e.createElement(t), a = e.getElementsByTagName(t)[0], k.async = 1, k.src = r, a.parentNode.insertBefore(k, a) }) (window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym"); ym(103140073, "init", { clickmap: true, trackLinks: true, accurateTrackBounce: true, webvisor: true }); </script> <noscript> <div><img src="https://mc.yandex.ru/watch/103140073" style="position:absolute; left:-9999px;" alt=""/></div> </noscript> <!-- /Yandex.Metrika counter --> </body> </html>