Для чего нужны шаблоны в CGI скриптах? Для того, чтобы жизнь была радостной! Причем радостной она будет как у программиста, так и у вебмастера, ну а также у того бедолаги, который скачав бесплатный CGI скрипт не может подогнать его внешний вид под свой дизайн (ведь не у каждого хватит отваги отредактировать чужой, незнакомый и чуждый всему человеческому код скрипта)! Шаблоны позволяют каждому заниматься своим делом: у программиста будет аккуратный код, без различных HTML нагромождений, а у вебмастера будут статичные html документы, с которыми он может делать все что угодно не приставая к программисту и тем более (!) не ковыряясь своими кривыми ручонками в кодах. Наткнулся я недавно на модуль CGI::FastTemplate, который произвел на меня неизгладимое впечатление своей простотой и функциональностью, вот я и перевел документацию к этому модулю. О чем вы узнаете.. Освоив основные функции этого модуля, вы сможете вытворять нечто подобное: use CGI::FastTemplate; $tpl = new CGI::FastTemplate(); $tpl = new CGI::FastTemplate("/path/to/templates"); CGI::FastTemplate->set_root("/path/to/templates"); ## папка к шаблонам $tpl->set_root("/path/to/templates"); ## или так $tpl->define( main => "main.tpl", row => "table_row.tpl", all => "table_all.tpl", ); $tpl->assign(TITLE => "I am the title."); my %defaults = ( FONT => "<font size=+2 face=helvetica>", EMAIL => 'jmoore@sober.com', ); $tpl->assign(%defaults); $tpl->parse(ROWS => ".row"); ## '.' добавление к уже имеющемуся значению $tpl->parse(CONTENT => ["row", "all"]); $tpl->parse(CONTENT => "main"); $tpl->print(); ## выводится значение, образованное последним вызовом parse() $tpl->print("CONTENT"); ## то же самое, т.к. последний вызов parse() применялся к CONTENT $ref = $tpl->fetch("CONTENT"); ## создаем ссылку на результаты обработки CONTENT, ## теперь $$ref можно использовать для записи содержимого CONTENT в файл Как это работает? Шаблон - это обычный html документ, содержащий какие-либо переменные. В процессе разбора шаблона скриптом, эти переменные заменяются соответствующими значениями, и результат этой обработки - уже полноценный HTML документ, который и получает клиент. Самый простейший шаблон, с одной переменной ('$NAME'), может быть например таким: Привет $NAME. Как делишки? После обработки, вместо $NAME появится какое-то значение (например, имя посетителя, а может несколько десятков килобайт текста - все зависит от вас!). Отличия CGI::FastTemplate от ему подобных.. Скорость.FastTemplate не использует функцию eval, а разбор (парсинг) осуществляется при использовании простых регулярных выражений. Кроме того, этот модуль осуществляет простейшую замену переменной на ее значение, при этом в шаблонах не могут использоваться какие-либо логические структуры - вся логика должна содержаться в коде. Этот модуль назван 'Fast' не просто так! Эффективность. FastTemplate принимает ссылки на переменные, и возвращает, когда это возможно их значения, при этом избавляет вас от нагромождения копий одних и тех же аргументов ( хешей, скаляров и т.д.) Гибкость. Модуль чрезвычайно гибок и функционален, он позволяет создавать сложные и весьма разнообразные HTML документы. Модуль может работать как под UNIX, так и под NT. Ну и кроме того, работа модуля не ограничивается лишь HTML документами, вы вполне можете использовать его при работе с ASCII документами ( postscript, XML, email ..) Вы можете отыскать в CPAN архиве и другие шаблонные модули: Module HTML::Template (S/SA/SAMTREGAR/HTML-Template-0.04.tar.gz) Module Taco::Template (KWILLIAMS/Taco-0.04.tar.gz) Module Text::BasicTemplate (D/DC/DCARRAWAY/Text-BasicTemplate-0.9.8.tar.gz) Module Text::Template (MJD/Text-Template-1.20.tar.gz) Module HTML::Mason (J/JS/JSWARTZ/HTML-Mason-0.5.1.tar.gz) FastTemplate - инструкции по эксплуатации. Работу с модулем FastTemplates можно условно разбить на четыре этапа: - define - определение/описание необходимых шаблонов
- assign - назначение соответствий
- parse - разбор/обработка шаблонов.
- print - вывод результатов обработки
А теперь о каждом пункте и об основных методах их реализации подробнее. define(Хеш) На этом этапе мы определяем какие шаблоны будем использовать и даем им имена, которые и будут использоваться вместо имен самих файлов. Обратите внимание, что имена файлов-шаблонов появляются только на этом этапе, define(), и больше они нигде не фигурируют, в дальнейшем, для вызова того или иного шаблона мы используем присвоенные им имена. my $tpl = new FastTemplate(); $tpl->define( main => "main.tpl", footer => "footer.tpl", ); Это необходимый этап! Возможно, в случае простейших примеров (например, тот который сейчас приведен), это кажется не нужным и лишним, но при большом количестве шаблонов (а скорее всего так у вас и будет!) чрезвычайно удобно сразу присвоить всем своим шаблонам имена через функцию define(), а затем просто ссылаться на них. Подсказка: Шаблон, которому вы поставили в соответствие имя, используя функцию define(), не загружается сразу же в память, потому смелее описывайте через define(), все шаблоны, которые вы собираетесь где-нибудь и когда-нибудь задействовать - реально, ваш шаблон будет загружен лишь тогда, когда его необходимо будет задействовать, и не раньше! define_nofile(Хеш) синоним: define_raw(Хеш) Иногда не хочется создавать отдельный файл-шаблон для отображения некоторых стандартных видов переменных. Например, вы создали ленту новостей, и самые "горячие" новости вы желаете выделить иначе: сделать заголовки пожирнее, но не хотите для этого создавать отдельный шаблон (хотя все-таки рекомендуется создавать), так вот подобный трюк вы можете осуществить используя метод define_nofile(), а выглядит это так: my $tpl = new FastTemplate(); $tpl->define_nofile( new => '<b>$ITEM_NAME</b> <BR>', old => '$ITEM_NAME <BR>'); if ($new) { $tpl->parse($ITEM => "new"); } else { $tpl->parse($ITEM => "old"); } Рассматривая этот вариант, нельзя не отметить, что теперь вариант отображения "горячей" новости (ну а вобщем случае чего-то очень нужного), будете настраивать вы, т.е. программист, а если бы вы использовали для этих целей отдельный шаблон, то эту задачу можно было бы перепоручить кому-нибудь другому. Хоть использование метода define_nofile(), и является более эффективным, чем define() (не надо лишний шаблон создавать, загружать), но он также и более запутан, поэтому хорошенько подумайте, прежде чем будете его использовать! Подсказка: метод define_raw(Хеш) - синоним метода define_nofile(), т.е. одно и тоже, но под разными именами. assign(Хеш) Метод assign(Хеш) позволяет присвоить вашим переменным определенные значения. Такое присвоение необходимо для всех переменных, указанных в шаблонах. Существует две различные формы метода присвоения. Первая, простая форма assign(), задается в виде хеша, т.е. задаем пары ключ/значение и эти пары копируются в FastTemplate. Т.к. в FastTemplate - лишь один хеш, то в случае присвоения одному ключу двух разных значений, происходит замена одного значения на другое, например: $tpl->assign(TITLE => "king kong"); $tpl->assign(TITLE => "godzilla"); ## "king kong" заменяется на "godzilla" assign(Ссылка на Хеш) Более эффективным способом присвоения переменным соответствующих значений является создание ссылок на хеши. (Это особенно удобно, если мы ставим ссылку на хеш, выдаваемый нам в качестве результатов обращения к базе данных.) При создании ссылки на хеш не происходит копирования данных. В процессе обработки шаблона (parsing), если в основном хеше FastTemplates не находяься необходимые значения для переменных происходит проверка хешей, на которые поставлены ссылки. Как только для переменной найдено значение, просмотр хешей останавливается. Важно помнить, что необходимо вовремя удалять ненужные ссылки на хеши, иначе будут различные несуразности my %foo = ("TITLE" => "king kong"); my %bar = ("TITLE" => "godzilla"); $tpl->assign(%foo); ## TITLE назначается значение "king kong" $tpl->clear_href(1); ## удаляем последнее присвоение ссылки на хеш (%foo) $tpl->assign(%bar); ## TITLE назначается значение "godzilla" $tpl->clear_href(); ## удаляем все присвоения ссылок на хеши $tpl->assign(%foo); ## TITLE назначается значение "king kong" $tpl->assign(%bar); ## TITLE также (!) назначается значение "godzilla" parse(Хеш) Это основная функция FastTemplate, она принимает хеш, где ключ - это имя цели обработки (TARGET), а второе значение - это имена шаблонов, которые мы подвергнем обработке, т.е. это ЧТО мы будем обрабатывать (SOURCE). Возможны три варианта хешей: $tpl->parse(MAIN => "main"); ## regular $tpl->parse(MAIN => ["table", "main"]); ## compound $tpl->parse(MAIN => ".row"); ## append regular: при использовании этого способа, у нас происходит загрузка шаблона main (если он не был загружен ранее), далее происходит подстановка (интерполяция): все переменные заменяются на соответствующие им значения, и результат этой обработки сохраняется в FastTemplate как значение MAIN. Если позднее при обработке встретится шаблон, содержащий переменную '$MAIN' , то она будет заменена соответствующим значением, т.е. результатом обработки шаблона main. Это позволяет вам "вмонтировать" содержание одного шаблона в другой. Такое внедрение удобно осуществлять используя второй вариант compound, Запись $tpl->parse(MAIN => ["table", "main"]); ## compound Полностью аналогична такой: $tpl->parse(MAIN => "table"); $tpl->parse(MAIN => "main"); Только осуществляется compound быстрее. Внимание! При использовании метода compound, необходимо, чтобы в списке имен шаблонов, каждое последующее содержало переменную, которая бы заменялась на данные обработки предшествующих ей шаблонов. Например, в приведенном выше примере compound, шаблон с именем main должен обязательно содержать переменную '$MAIN', в которую будут помещены данные, полученные при обработке шаблона table. Если же, в шаблоне main переменной $MAIN не окажется, то данные обработки шаблона table будут ПОТЕРЯНЫ! append - позволяет данные обработки шаблона ПРИБАВИТЬ к уже имеющемуся значению какой-либо переменной. Такой способ удобно использовать при генерации таблиц, когда количество строк таблицы - переменная величина. Вариант практического применения: оформление результатов на запрос к БД - т.е. делается цикл, в котором обрабатывается одна строка и результат обработки добавляется к уже полученным значениям (т.е. что-то вроде счетчика-накопителя. Более наглядный пример будет продемонстрирован в конце документации). strict() По умолчанию опция включена. В случае обнаружения в шаблоне переменных, которые неопределенны происходит вывод предупреждения в STDERR, что-то вроде этого: [CGI::FastTemplate] Warning: no value found for variable: SOME_VARIABLE В более новой версии 1.04 такие "неопределенные" переменные будут оставаться в документе, это сделано по двум причинам: вы сможете использовать многократную обработку одного и того ж документа (т.е. некоторые переменные будут определены не сразу, а после какого-то события), и кроме того, так легче отлавливать "потерянные переменные". Если вы работали со старой версией FastTemplate и хотели бы оставить прежнее поведение модуля при парсинге (т.е. когда вместо всех неопределенных ничего не выводилось), то вам стоит использовать функцию no_strict(), о которой сказано чуть ниже. Примечание. С версии 1.07 добавлена поддержка двух видов переменных, указываемых в шаблоне, $VAR и ${VAR} - эти две записи совершенно эквивалентны. Но в случае, если переменная, указанная в шаблоне как ${VAR}, окажется "неопределенной", то в результатах она появится как $VAR - это небольшая несогласованность, в идеале, конечно надо бы вывести все как есть, т.е. ${VAR}. Примечание. Все сообщения об ошибках выводятся через STDERR и сохраняются в логах сервера error_log. Иногда, когда что-то не работает, стоит туда заглядывать. no_strict() Эта функция "выключает" сообщения об ошибках при обнаружениии неопрелделенных переменных в шаблоне. С версии 1.04 вызов no_strict() ничего не выводит вместо необнаруженных переменных. По умолчанию, считается что включена функция strict(). Установка no_strict() должна происходить при каждом обращении к FastTemplate. CGI::FastTemplate::no_strict; ## Нет my $tpl = CGI::FastTemplate; $tpl->no_strict; ## Да print(Скаляр) Метод print() выводит содержимое названной переменной. Если никакая переменная не дается, то выводится переменная, образованная при последнем вызове parse(). Например: $tpl->parse(MAIN => "main"); $tpl->print(); ## выводит значение MAIN $tpl->print("MAIN"); ## то же самое Если необходим вывод результатов не в STDOUT (а например в socket, файл), то смотрите функцию fetch(). Прочие методы. fetch(Скаляр) Возвращает ссылку на обработанные данные. Например: $tpl->parse(CONTENT => "main"); my $content = $tpl->fetch("CONTENT"); print $$content; ## вывод через STDOUT print FILE $$content; ## печать в файл clear() Примечание. Обратите внимание, что все функции 'clear' предназначены в основном для mod_perl. Для написании CGI сценариев они не особенно нужны (особый случай - упоминаемый ранее clear_href()). Очищает служебный хеш, в котором хранятся данные передаваемые при вызове функций assign() и parse() Часто clear() используется в конце mod_perl сценариев, например: $tpl->print(); $tpl->clear(); clear(Массив) Если не передается никакого имени переменной или массива, то будут удалены все переменные, прошедшие процедуру assign() или parse(), если же указано какое-то конкретное имя или список переменных, то удалены будут только указанные переменные. Например: $tpl->assign(TITLE => "Welcome"); $tpl->clear("TITLE"); ## title теперь пуст. Другой способ достижения подобного эффекта - это просто назначение переменной пустого значения, например: $tpl->assign(TITLE => ''); ## тоже что и: $tpl->clear("TITLE"); clear_parse() См. clear() clear_href(Число) Удаляет ссылку на хеш под заданным номером из списка ссылок, которые мы создавали таким образом (см. также вышеизложенный метод assign() ): $tpl->assign(HASH REF); Если при вызове функции никаких аргументов не указано, то удаляются все существующие ссылки. Эта функция часто используется при обработке результатов запросов, полученных от БД, например: while($hash_row = $sth->fetchrow_hashref) { $tpl->assign($hash_row); $tpl->parse(ROW => ".row"); $tpl->clear_href(1); } clear_define() Удаляет хеш, в котором хранятся данные передаваемые при обращении: $tpl->define(); Примечание: хеш, который содержит УЖЕ загруженные шаблоны, не удаляетя при использовании этого метода. Для того, что бы его все-таки удалить воспользуйтесь функцией clear_tpl. clear_tpl() clear_tpl(Имя) Если шаблон, использовался хоть раз, то он будет хранится в памяти. Функция clear_tpl() - удаляет все загруженные шаблоны, а функция clear_tpl(ИМЯ) - удаляет лишь один указанный шаблон. Подобные функции, имеет смысл использовать при выполнении больших сценариев, когда есть много шаблонов и требуется экономить ресурсы памяти. clear_all() Очищает модуль от всех данных. Вызов этой функции равнозначен одновременному обращению ко всем этим функциям: $tpl->clear_define(); $tpl->clear_href(); $tpl->clear_tpl(); $tpl->clear_parse(); Переменные Переменные имеют следующий вид: $[A-Z0-9][A-Z0-9_]+ Это означает, что в шаблонах, все переменные должны начинаться со знака доллара "$", а последующим знаком могут быть или заглавные латинские буквы, либо цифры, и знак подчеркивания "_" (или то, другое и третье вместе). С версии 1.07 возможно также такое оформление переменных ${[A-Z0-9][A-Z0-9_]+}, т.е. имя переменной в фигурной скобке. Вот пример того, как вы можете называть свои переменные: $FOO $F123F $TOP_OF_PAGE ${NEW_STYLE} Интерполяция (подстановка) переменных В процессе обработки шаблонов (парсинга) происходит проверка всех обрабатываемых шаблонов на содержание переменных - это довольно скользкий момент, т.к. обработчик весьма "жаден" и если сразу же после вашей переменной следуют еще какие-то символы, то их он может посчитать именем одной переменной. (Например, есть переменная $MY_VAR, а в шаблоне вы напишете так: $MY_VARWELCOME, тогда обработчик посчитает переменной $MY_VARWELCOME, которая окажется неопределенной) Будьте осторожны! С версии 1.07 вы можете задавать переменные в таком виде ${MY_VAR}- это несколько улучшает ситуацию с вышеизложенной проблемой. Если переменная, упомянутая в шаблоне оказывается неопределенной, то возможны такие варианты : 1. если используется функция strict() (используется по умолчанию), то все неопределенные переменные останутся в результатах обработки без изменений (т.е. была в шаблоне переменная $MY_VAR, и если для нее никакого значения не нашлось, то в результате обработке шаблонов у нас она будет видна $MY_VAR), при этом придупреждение об ошибке будет скинуто в STDERR. 2. Если используется функция no_strict(), то вместо всех неопределенных переменных будет вставлено пустое место [''] Проясним все вышесказанное на примере: Допустим, у нас имеются следующие значения для переменных: $FOO = "foo"; $BAR = "bar"; $ONE = "1"; $TWO = "2"; $UND = "_"; Запись Переменной в шаблоне | Вывод после обработки | Примечания | $FOO | foo | -- | $FOO-$BAR | foo-bar | -- | $ONE_$TWO | 2 | $ONE_ неопределена! При использовании no_strict() | $ONE_$TWO | $ONE_2 | при обращении strict() | $ONE$UND$TWO | 1_2 | все нормально | ${ONE}_$TWO | 1_2 | но так симпатичнее! | $$FOO | $foo | -- | $25,000 | $25,000 | -- | | А теперь попробуем! Этот скрипт-пример, построит HTML страницу, которая состоит из таблицы. В таблице будет состоять из трех пронумерованных строк. Определим ,какие шаблоны нам необходимы: для того, чтобы легче было изменить количество строк в таблице, сделаем отдельный шаблон для одной строки, еще один шаблон для таблицы, и еще один основной, куда будет вписана сама таблица. Вот, html коды этих шаблонов (каждый из них необходимо сохранить в отдельном файле) Шаблон 1: <!-- NAME: main.tpl --> <html> <head><title>$TITLE</title> </head> <body> $MAIN </body> </html> <!-- END: main.tpl --> Шаблон 2: <!-- NAME: table.tpl --> <table> $ROWS </table> <!-- END: table.tpl --> Шаблон 3: <!-- NAME: row.tpl --> <tr> <td>$NUMBER</td> <td>$BIG_NUMBER</td> </tr> <!-- END: row.tpl --> А теперь напишем скриптик... ## START ## use CGI::FastTemplate; my $tpl = new CGI::FastTemplate("/path/to/template/files"); $tpl->define( main => "main.tpl", table => "table.tpl", row => "row.tpl", ); $tpl->assign(TITLE => "FastTemplate Test"); for $n (1..3){ $tpl->assign( NUMBER => $n, BIG_NUMBER => $n*10); $tpl->parse(ROWS => ".row"); } $tpl->parse(MAIN => ["table", "main"]); $tpl->print(); ## END ## В результате работы скрипта мы получим такой код: <!-- NAME: main.tpl --> <html> <head><title>FastTemplate Test</title> </head> <body> <!-- NAME: table.tpl --> <table> <!-- NAME: row.tpl --> <tr> <td>1</td> <td>10</td> </tr> <!-- END: row.tpl --> <!-- NAME: row.tpl --> <tr> <td>2</td> <td>20</td> </tr> <!-- END: row.tpl --> <!-- NAME: row.tpl --> <tr> <td>3</td> <td>30</td> </tr> <!-- END: row.tpl --> </table> <!-- END: table.tpl --> </body> </html> <!-- END: main.tpl --> Возможно, вы после всего этого подумаете: "А зачем городить огород, когда можно просто вставить несколько HTML тегов прямо в код скрипта?" Да можно и так, только будет ли это проще? Вам, может быть, но что делать дизайнеру, которого не прельщают perl коды? А какая морока у вас будет при создании скрипта с поддержкой нескольких языков, или если понадобится выбор между текстовым и графическим дизайном для одного и того же сайта? Модуль FastTemplate позволяет вам полностью отделить дизайн от технического исполнения - разве это не здорово? |