Работа с библиотекой CTPP
Оглавление
Введение
В этом документе речь пойдет о практическом использовании CTPP в проектах, написанных на PHP. Чтобы дальнейший материал не вызывал непонимания, внимательно прочтите главу "Перед тем, как начать". Примеры, дающиеся в этом руководстве, построены по принципу "от простого - к сложному". Поэтому, если вы пропустили какой-то материал, посчитав его слишком простым, а пример, который рассматриваете, непонятен, просто вернитесь назад и внимательно прочтите руководство.
Все файлы, относящиеся к учебнику, находятся в каталоге /examples/php. В руководстве рассматриваются только примеры, оформленные в процедурном стиле. Примеры, написанные в объектно-ориентированном стиле оставляются на самостоятельное изучение. Как правило, они незначительно отличаются от детально разобранных и доступны для понимания всем, кто знает основы ООП.
Перед тем, как начать
Любая работа с расширением должна начинаться с создания объекта шаблонизатора. Для этого служит вызов ctpp_new - для использования в процедурном стиле и new ctpp - для объектно-ориентированного:
$Template = ctpp_new();
Также как и некоторые другие шаблонизаторы, CTPP, кроме простого вывода данных, поддерживает циклы, ветвления и арифметические операции. Все данные задаются как набор "ключ => значение". Ключом является любое имя, содержащее в себе буквы латинского алфавита, цифры, знак подчеркивания и символ точки. Значением может являться число, как целое, так и с плавающей точкой, строка или массив данных.
Пример:
$Params = Array("number_one" => 1,
"number.pi" => 3.14,
"text" => "Hello, World!");
$WrongParams = Array("1one" => 1,
"number-pi" => 3.14,
"текст" => "Hello, World!");
Каждый параметр, заданный так, как показан выше, можно вывести в шаблонизаторе. Для этого следует вызвать функцию ctpp_emit_params или метод emit_params.
Пример:
ctpp_emit_params($Template, $Params);
ctpp_emit_params($Template, Array("param" => "Дополнительный параметр"));
Для контроля выводимых параметров может быть полезна функция ctpp_dump_params:
ctpp_dump_params($Template);
Если что-то идет не так, вы всегда можете удостовериться, что введенные данные - именно те, которые необходимы.
Архив с примерами можно найти по ссылке /examples/php/Getting_Started.
Там же можно найти пример объектно-ориентированного кода библиотеки.
Простой пример
В этом примере мы попробуем вывести хорошо известную всем программистам фразу "Hello, World!".
Для этого нам понадобится:
1) создать необходимый набор данных
2) загрузить шаблон
3) вывести результат
Итак, от слов - к делу:
<?php
$Params = Array("hello" => "Привет", "who" => "Мир");
$Template = ctpp_new();
$Bytecode = ctpp_parse_template($Template, "hello.tmpl");
ctpp_emit_params($Template, $Params);
echo ctpp_output_string($Template, $Bytecode);
?>
Вот и все.
Теперь нам осталось только создать файл шаблона и записать его под именем hello.tmpl.
<TMPL_var hello>, <TMPL_var who>!
Архив с примерами: /examples/php/Hello_World.
Пример посложнее
Мы уже знаем как выводить в шаблон простые данные. На этом уроке мы научимся работать с условиями внутри шаблона. Двайте представим, что мы делаем сайт, где пользователю необходимо делать проверку введенного возраста. В классическом PHP мы могли бы воспользоваться конструкцией вида
<?php
$Age = _GET['age'];
if ($Age < 18)
{
echo "Детям до 18 - только детские разделы сайта!";
}
else
{
echo "А вот взрослым - все, что угодно!";
}
?>
Понятно, что настолько простой случай несложно запрограммировать и в PHP, но если у нас много страниц, зависящих от возраста посетителя, может оказаться более удобным вынести все проверки в код шаблона.
Сказано - сделано! Выносим сравнение в шаблон:
<TMPL_if (age < 18)>
Вам меньше 18 лет!
<TMPL_else>
Вам больше 18 лет!
</TMPL_if>
А как быть если надо сделать несколько проверок? Очень просто: написать более сложное условие:
<TMPL_if (age < 7 || age > 18)>
Привет-привет!
<TMPL_else>
Вход только для школьников!
</TMPL_if>
Вообще, шаблонизатор поддерживает не только логические операции, но и арифметические и логические. Полное описание вы можете найти в разделе помощи Арифметические и логические выражения.
Более того, посредством шаблонизатора можно проверять несколько условий последовательно!
<TMPL_if (forum.posts < 100)>
Новичок
<TMPL_elsif (forum.posts < 300)>
Участник
<TMPL_elsif (forum.posts < 500)>
Активный участник
<TMPL_elsif (forum.posts < 1000)>
Старожил
<TMPL_elsif (forum.posts < 2000)>
Аксакал
<TMPL_elsif (forum.posts < 5000)>
Многописатель
<TMPL_else>
Гуру
</TMPL_if>
Условия проверяются последовательно, до тех пор, пока не будет найдено подходящее. Если такового нет, выполнится ветка <TMPL_else>. Если ветки ELSE нет, не выведется ничего.
Пример того как работают ветвления очень прост. Фактически, мы берем данные и загружаем их в шаблон.
<?php
$Age = $_GET['age'] * 1;
$Posts = $_GET['posts'] * 1;
$Params = Array("age" => $Age, "forum.posts" => $Posts);
$Template = ctpp_new();
$Bytecode = ctpp_parse_template($Template, "branches.tmpl");
ctpp_emit_params($Template, $Params);
echo ctpp_output_string($Template, $Bytecode);
?>
Архив с примерами: /examples/php/Branches.
Циклы и функции
Теперь, когда мы научилиcь выводить простые переменные, самое время задаться вопросом: что еще умеет CTPP? Неужели это все, что мы можем использовать?
К счастью, это далеко не весь доступный нам функционал. Итак, урок посвящен циклам и встроенным в библиотеку функциям.
Цикл в CTPP - набор итераций по определенной структуре данных. В понимании PHP, эта структура данных - обычный массив массивов:
<?php
$LoopBody = Array( Array("id" => 1, "iteration" => "первая"),
Array("id" => 2, "iteration" => "вторая"),
Array("id" => 3, "iteration" => "третья"),
Array("id" => 3, "iteration" => "четвертая") );
?>
Чтобы вывести эту структуру в шаблон, необходима инструкция вида
<TMPL_loop loop_body>
ID: <TMPL_var id>, итерация: <TMPL_var iteration>
</TMPL_loop>
Но как быть, если нам надо вывести более чем один цикл на страницу? Именно для этого и служит имя цикла. Его мы указываем в шаблоне: <TMPL_loop имя_цикла>, а в коде для этого служит имя ключа параметра:
<?php
ctpp_emit_params($Template, Array("loop_body" => $LoopBody) );
?>
Действуя подобным образом мы легко можем вывести цикл внутри цикла. Количество вложенных циклов не ограничено ничем, кроме, разве что, фантазии разработчика.
Для облегчения работы, у каждого цикла есть контекстные переменные. Всего переменных восемь, а их смысл пояснен ниже:
__FIRST__ - установлена в "1" во время первой итерации цикла. Во всех остальных случаях не определена.
__LAST__ - содержит номер последней итерации во время последней итерации цикла. Во всех остальных случаях не определена.
__INNER__ - содержит номер итерации со второй по предпоследнюю. Во всех остальных случаях не определена.
__ODD__ - установлена, когда номер итерации нечетен. Содержит номер итерации. Для четных итераций не определена.
__COUNTER__ - определена во всех итерациях и содержит текущий номер итерации. Нумерация в цикле начинается с единицы.
__EVEN__ - установлена, когда номер итерации четен. Содержит номер итерации. Для нечетных итераций не определена.
__SIZE__ - определена во всех итерациях внутри цикла и содержит полное количество итераций.
__CONTENT__ - определена во всех итерациях внутри цикла и содержит данные, находящиеся в текущей ячейке массива.
Выводимые переменные разделяются на локальные и глобальные. Локальные переменные - те, что определены в текущей итерации цикла. Глобальные переменные - переменные, видимые в любой точке шаблона. Порядок подстановки переменных следующий: сначала ищется локальная переменная с указанным именем. Если такой переменной нет, производится поиск глобальной переменной с таким же именем.
Подобное разделение переменных на локальные и глобальные может быть полезным при верстке лент новостей, списка товаров и прочих циклических структур, где часть URL или какого-либо другого параметра можно сформировать единообразно.
Вложенные циклы формируются аналогично:
<?php
$LoopBody = Array();
for ($i = 0; $i < 5; ++$i)
{
$inner_loop = Array();
for ($j = 0; $j < 5; ++$j)
{
$inner_loop[$j]["inner_id"] = $j;
}
$LoopBody[$i]["id"] = $i;
$LoopBody[$i]["inner_loop"] = $inner_loop;
}
ctpp_emit_params($Template, Array("loop_body" => $LoopBody) );
?>
Шаблон будет иметь следующий вид:
<TMPL_loop loop_body>
ID: <TMPL_var id>,
Внутренний цикл:
<TMPL_loop inner_loop>
<TMPL_var inner_id>
</TMPL_loop>
</TMPL_loop>
Архив с примерами: /examples/php/Loops.
Использование Include
Часто бывает так, что на разных страницах есть одни и те же элементы, например, блок меню, лента быстрого перехода к "горячим" новостям и т.п. Для упрощения верстки одинаковые элементы можно вынести в файлы шаблонов, а сами файлы подключить директивой <TMPL_include "имя_файла">.
Чтобы включать одни шаблоны в другие, особой доработки кода PHP не требуется, необходимо лишь указать каталоги, где искать подключаемые файлы. Делается это при помощи функции ctpp_include_dirs:
<?php
ctpp_include_dirs($Template,
Array("/usr/share/templates", "/home/myproject/tmpl") );
?>
Обработка ошибок
Если во время работы шаблонизатора произошла ошибка, об этом можно узнать проверив код, возвращаемый функцией или методом класса. Если знаение равно FALSE, следует вызвать функцию ctpp_get_last_error, которая вернет массив с описанием, что и где произошло.
<?php
$OutputHTML = ctpp_output_string($Template, $Bytecode);
if ($OutputHTML === false)
{
$ErrorDescr = ctpp_get_last_error($Template);
printf("Ошибка 0x%08X: %s\n", $ErrorDescr["error_code"],
htmlspecialchars($ErrorDescr["error_str"]));
printf("Файл %s: строка %d, позиция %d\n",
$ErrorDescr["template_name"],
$ErrorDescr["line"],
$ErrorDescr["pos"]);
}
?>
Блоки
Начиная с версии 2.4 шаблонизатор поддерживает блоки данных.
Блок - область шаблона, заключенная между операторами <TMPL_block имя_блока> и </TMPL_block>. Блоки вызываются по имени посредством оператора <TMPL_call имя_блока>. Данная конструкция полезна когда на странице есть несколько блоков, расположение которых невозможно задать при верстке шаблона.
Например, если требуется дать возможность пользователю самостоятельно указывать выводимый блок данных, конструкция будет следующей:
<?php
ctpp_emit_params($Template, Array("block_name" => "новости") );
?>
Описываем блоки
<TMPL_block "новости">
Новости
</TMPL_block>
<TMPL_block "голосование">
Новости
</TMPL_block>
Выводим тот блок, который требуется:
<TMPL_call block_name>
|