Smarty в веб-разработке

Автор: Денис Ковалкин

(написано для Hostinfo.ru, ссылка на публикацию)

Любой веб-разработчик рано или поздно задумывается об использовании в своем нелегком труде системы управления шаблонами. Особенно, когда число страниц проектируемого ресурса переваливает за десяток, а внезапно проснувшийся заказчик просит добавить в главное меню еще один «ма-аленький пунктик». Вот тут-то и приходит понимание, что использование подобных систем способно серьезно сэкономить время и силы.

В отличие от этой, «прямой и явной», выгоды, польза отделения программного кода веб-приложения от HTML-представления страницы далеко не так очевидна. Благородная цель – спасти нежные нервы веб-дизайнеров от созерцания прикладной логики веб-приложения – актуальна в условиях профессиональных веб-студий, практикующих распределенную разработку, но не имеет, на первый взгляд, резона для одиночек, или групп энтузиастов, каждый из которых и программист, и веб-дизайнер в одном флаконе.

Тем не менее, даже для таких «волков-одиночек» разделение дизайна и программного кода несёт немалую выгоду. Упакованные по отдельности, код и шаблон гораздо легче читаются, проще редактируются, легко копируются по мере необходимости. Разделение шаблона веб-страницы и кода не просто облегчает работу, а переводит ее в совершенно новое качество. Подобный подход позволяет браться за проекты любой сложности, не опасаясь, что однажды нагромождение его структур окажется за пределом понимания разработчика; а также возвращаться к предыдущим проектам, не вспоминая мучительно, с какого же конца  к ним подступиться.

Систем управления шаблонами в веб-программировании существует немало – даже сравнительный анализ их занял бы не одну публикацию – но в этой статье я сосредоточусь на одной из них, Smarty, уделив основное внимание идеологии построения веб-ресурса на базе этой системы. Важная ее особенность – предварительная компиляция  и кэширование пользовательских шаблонов, что существенно сокращает время на вывод обращающихся к ним страниц при последующих запросах.

Впрочем, правильнее называть Smarty не системой, но средой веб-разработки. Ее возможности выходят далеко за рамки обычных систем управления шаблонами, позволяя решать самый широкий круг прикладных задач. В этом сила Smarty и главная особенность ее использования — она не навязывает пользователю раз и навсегда заданный ее разработчиками подход, предлагая, скорее, конструктор «Сделай сам». Разумеется, конечный результат в этой ситуации напрямую зависит от квалификации «сборщика», которому Smarty предлагает:

  • солидный набор стандартных функций для дизайнера и программиста;
    отладочную консоль, демонстрирующую задействованные шаблоны, переменные и настройки;
  • префильтры и постфильтры, применяющиеся к шаблону до и после компиляции (но перед исполнением), а также фильтры вывода;
  • возможность подключения плагинов, позволяющих определять собственные функции, фильтры, источники шаблонов;
  • а также настраиваемый механизм кэширования откомпилированных шаблонов.

Этого вполне достаточно, чтобы реализовать практически любую схему разработки веб-приложения из распространенных ныне.

Схема MVC

По умолчанию Smarty «заточена» под схему разработки MVC (Model – View – Controller). Model (Ядро) здесь – совокупность источника данных и функций, работающих с этим данными на базовом уровне (прочитать/записать/изменить). View – шаблон, отвечающий за внешний вид страницы. Controller (Контроллер) – совокупность прикладной логики веб-приложения, которая обеспечиваетя обработку данных, полученных от Ядра или пользователя, выбор шаблона и вывод результата на экран. Простейший пример использования Smarty вы можете  увидеть ниже:

<?php

include(‘Smarty.class.php’);
$smarty = new Smarty;

$smarty->assign(‘text’, ‘Графиня изменившимся лицом бежит пруду.’);

$smarty->display(‘telegram.tpl’);

?>

Smarty целиком написан на языке PHP и представляет собой класс, объект которого создается перед началом работы и в дальнейшем используется для обеспечения доступа к функциям системы управления шаблонами, передачи ей данных, сгенерированных Ядром, и вывода выбранного шаблона. Фактически, листинг выше представляет собой пример простейшего Контроллера.

Контроллер в данной схеме разработки является ключевым элементом: он обращается к Модели за необходимыми данными, он определяет, какой шаблон (или шаблоны), будут использованы для отображения страницы, и в каком порядке они будут выведены на экран … и именно он испытывает тенденцию к росту/усложнению вместе с ростом веб-ресурса, хотя эта проблема, в принципе, решается стандартными приемами структурного программирования.

Другое дело – ряд других недостатков, которые порождает схема MVC, обусловленных тем, что она недостаточно хорошо подходит для разделения кода страницы и ее представления. Во-первых, Контроллер здесь единолично решает, какой шаблон будет использован для отображения запрошенной страницы, а значит, для его замены на другой придётся лезть в код. То же — для изменения порядка вывода нескольких шаблонов, используемых в одной странице.

Во-вторых, адресация на выводимой странице будет определяться относительно Контроллера, а не шаблона, что также не совсем удобно. К примеру, некоторые изображения, принадлежащие конкретному разделу сайта, удобней было бы хранить в нём, не захламляя основной каталог ресурса и не усложняя схему Контроллер – шаблон дополнительными ухищрениями.

Третий недостаток носит, в известной степени, идеологический характер: если дизайнер в процессе разработки воспринимает сайт как совокупность шаблонов, то для программиста сайт – это в первую очередь Контроллер. Посетитель сайта поддержит здесь, скорее, дизайнера – он знать не хочет про движок, ему страницу подавай! Из этого можно сделать вывод: чтобы создавать сайты, ориентируясь на  посетителя, необходимо танцевать от шаблонов, а не от контроллера.

Компонентный подход

Немного переиграем схему MVC, поставив во главу угла шаблон. Теперь именно он принимает обращения от браузера, подгружает по мере необходимости данные из Модели и отображает получившийся результат. Резонный вопрос – как же при этом соблюдается принцип отделения отображения страницы от программного кода? Ничего сложного: программист создает блоки кода, поставляющие данные для шаблона (вывод ленты новостей, содержимого гостевой книги, непосредственно текста данного раздела), а веб-дизайнер подключает эти блоки в шаблоне по мере необходимости, пользуясь псевдо-тэгами Smarty. Синтаксис псевдо-тэгов максимально упрощен, не нарушает вид и структуру HTML-шаблона, и легко осваивается даже незнакомым с веб-программированием человеком. Эти блоки принято называють компонентами, а рассматриваемую схему – компонентным подходом. Отличительная черта языка Smarty, позволяющая пользователю определять новые функции, фильтры, ресурсы, дает возможность реализовать компонентный подход без особых затрат времени и сил.

Как это выглядит в шаблоне? Приведу пример простой, и наиболее часто встречающейся задачи – вывод десяти последних новостей в новостной ленте сайта. Вот как она будет выглядеть в шаблоне:

<div class=”news”>
{news count=»10″}
{foreach from=$data item=»i»}
 {$i.0} — {$i.1} <br />
{/foreach}
</div>

Здесь псевдо-тэг {news} обеспечивает обращение к компоненту, отвечающему за считывание из файла нужного количества новостей и передачу их переменной Smarty $data (имеющей в итоге вид массива «дата новости» — «текст новости»); {foreach} – стандартная функция Smarty, обеспечивающая проход по всему массиву $data, формируемому компонентом. Но система управления шаблонами в своей первоначальной конфигурации знать ничего не знает про такой псевдо-тэг — {news}. Чтобы научить Smarty правильно обрабатывать его, мы пишем следующую функцию:

<?php

function smarty_function_news($params, &$smarty)
{
 $newsfile=file(«news.txt»);
 for ($i=0;$i<$params[‘count’];$i++) {
  $news_array[]=explode(«##»,$newsfile[$i]);
            // ## — используемый разделитель даты и текста новости.
 };
 $smarty->assign(‘data’,$news_array);
}

?>

Как вы можете заметить, существует соглашение по именованию пользовательских функций шаблонов – smarty_type_name. Так же существуют правила для имен файлов плагинов, содержащих подобные пользовательские элементы; общая структура их должна иметь вид type.name.php, иначе Smarty не сможет подключить файл плагина. Здесь type – тип плагина, в нашем случае – function, name – имя плагина/псевдо-тэга.

Необходимо отметить, что реализация компонентного подхода в чистом виде при работе со Smarty нецелесообразна. Эта система управления шаблонами требует инициализации, пример которой был приведен в ходе рассмотрения предыдущей схемы, и вставлять ее код в заголовок каждого шаблона – нерационально. Оптимален вариант, при котором все обращения к шаблонам сайта сначала переадресовываются на общий контроллер, который запускает Smarty, возвращая затем управление вызванному шаблону. Сделать это можно, используя, например, простейший обработчик Apache, размещенный в файле .htaccess:

 ## Подключаем общий контроллер для обработки запросов к всем файлам шаблонов
 Action templhandler «controller.php»
            AddHandler templhandler .html
 
В чём преимущества компонентного подхода? Ну, во-первых: код веб-приложения разбит на небольшие функциональные блоки, которые легко переносить из проекта в проект, подключать и отключать по мере необходимости. Написанием компонентов могут заниматься с равным успехом и один человек, и группа разработчиков, а единые стандарты их интерфейса позволят дизайнеру с легкостью использовать любые компоненты в разрабатываемом шаблоне.

Во-вторых: автономность шаблона позволяет дизайнеру копировать его в любой каталог сайта, формируя дерево последнего по своему вкусу. Добавим к этому адресацию относительно шаблона и появляющуюся вследствие возможность без особых проблем хранить данные конкретного раздела непосредственно в его каталоге.

Шаблонизатор

Рассмотренный выше компонентный подход нельзя назвать вершиной эволюции среди подходов к построению сайта. При взгляде на его структуру напрашивается, как минимум, еще одна возможная модификация. В самом деле, в предыдущем пункте мы по умолчанию полагали шаблон единым и неделимым. Между тем, в нем есть немало элементов – шапка с подвалом, главное меню, лента новостей сайта и т.д. — которые повторяются на всех страницах нашего сайта. А раз так – не лучше ли их выделить в отдельные блоки, подгружая по мере необходимости?

Единая и тяжелая для осмысления «глыба» шаблона при таком подходе превращается в лёгкий и понятный Макет, содержащий общую структуру сайта с отмеченным в нём расположением блоков (новостей, меню, основного содержимого страницы и т.д.). Фактически, мы применяем использованный в прошлой главе компонентный подход, но не к коду, а к HTML-представлению сайта, получая причитающиеся за это выгоды: легкость для понимания, переносимость отдельных элементов отображения из одного веб-приложения в другое, возможность параллельной работы над дизайном сайта.

Конкретный пример подобного подхода рассматривают в книге «PHP 5» Дмитрий Котеров и Алексей Костарев. Код разработанного ими движка сайта «Templier» вы сможете найти по адресу http://php5.dklab.ru/, в одноименной директории архива. Сами создатели предпочитают называть разработанную систему, а также подобный подход к построению сайта «шаблонизатором». Созданный на базе Smarty, Templier, помимо реализации блочного подхода, демонстрирует множество других полезных свойств: наследование блоков в поддиректориях, вложенных в текущую, установка «блоков-по-умолчанию» и «макетов-по-умолчанию» для конкретного каталога, управление кэшированием, реализация автозаполнения форм и многое другое. Изучение данного шаблонизатора поможет вам создать на базе Smarty свой собственный движок сайта, наиболее соответствующий вашим задачам и методам разработки.