16 KiB
Расширение Fenom
Добавление тегов
В шаблонизаторе принято различать два типа тегов: компиляторы и функции. Компиляторы вызываются во время преобразования кода шаблона в PHP код и возвращяют PHP код который будет вставлен вместо тега. А функции вызываются непременно в момент выполнения шаблона и возвращают непосредственно данные которые будут отображены. Среди тегов, как и в HTML, есть строчные и блоковые теги.
Линейные функции
Добавление функции можно осуществить следующим образом:
$fenom->addFunction(string $function_name, callable $callback[, callable $parser]);
В данном случае запускается стандартный парсер, который автоматически разберет аргументы тега (которые должны быть в формате HTML атрибутов) и отдаст их в функцию ассоциативным массивом:
$fenom->addFunction("some_function", function (array $params) { /* ... */ });
При необходимости можно переопределить парсер:
$fenom->addFunction("some_function", $some_function, function (Fenom\Tokenizer $tokenizer, Fenom\Template $template) { /* parse tag */});
Существует более простой способ добавления произвольной функции:
$fenom->addFunctionSmart(string $function_name, callable $callback);
В данном случае парсер сканирует список аргументов коллбека и попробует сопоставить с аргументами тега.
class XYCalcs {
public static function calc($x, $y = 5) {
return $x + $y;
}
}
// ...
$fenom->addFunctionSmart('calc', 'XYCalcs::calc');
пример выше позволяет объявить тег {calc}
и использовать его:
{calc x=$top y=50} или {calc y=50 x=$top} вызовет XYCalcs::calc($top, 50)
{calc x=$top} или {calc $top} вызовет XYCalcs::calc($top)
Таким образом Вы легко можете добавлять свои функции или методы.
Блоковые функции
Добавление блоковой функции аналогично добавлению строковой, за исключением того, что есть возможность указать парсер для закрывающего тега.
$fenom->addBlockFunction(string $function_name, callable $callback[, callable $parser_open[, callable $parser_close]]);
Сам коллбек принимает первым аргументом контент между открывающим и закрывающим тегом, а вторым аргументом - ассоциативный массив из аргуметов тега:
$fenom->addBlockFunction('some_block_function', function ($content, array $params) { /* ... */ });
Линейный компилятор
Добавление строчного компилятора осуществляется очень просто:
$fenom->addCompiler(string $compiler, callable $parser);
Парсер должен принимать Fenom\Tokenizer $tokenizer
, Fenom\Template $template
и возвращать PHP код.
Компилятор так же можно импортировать из класса автоматически
$fenom->addCompilerSmart(string $compiler, $storage);
$storage
может быть как именем класса, так и объектом. В данном случае шаблонизатор будет искать метод tag{$compiler}
и взят в качестве парсера тега.
Блоковый компилятор
Добавление блочного компилятора осуществяется двумя способами. Первый:
$fenom->addBlockCompiler(string $compiler, array $parsers, array $tags);
где $parser
ассоциативный массив ["open" => parser, "close" => parser]
, сождержащий парсер на открывающий и на закрывающий тег, а $tags
содержит список внутренних тегов в формате ["tag_name"] => parser
, которые могут быть использованы только с этим компилятором.
Второй способ добавления парсера через импортирование из класса или объекта методов:
$fenom->addBlockCompilerSmart(string $compiler, $storage, array $tags, array $floats);
Добавление модификаторов
$fenom->addModifier(string $modifier, callable $callback);
$modifier
- название модификатора, которое будет использоваться в шаблоне$callback
- коллбек, который будет вызван для изменения данных
Например:
{$variable|my_modifier:$param1:$param2}
$fenom->addModifier('my_modifier', function ($variable, $param1, $param2) {
// изменение $variable
return $variable;
});
Расширение тестового оператора
$fenom->addTest(string $name, string $code);
$code
- PHP код для условия с маркером для замены на значение или переменную.
Например, тест на целое число is int
можно добавить как $fenom->addTest('int', 'is_int(%s)')
.
В шаблоне тест выглядит как {$a is int}
, а после компиляции - is_int($a)
.
Расширение глобальной переменной
Fenom обладает определенным набором глобальных переменных.
Однако, их может не хватать для удобной работы и в этом случае потребуется добавить свои или переопределить/удалить существующие.
Метод Fenom::addAccessor(string $name, callable $parser)
позволяет добавить свой обработчик-парсер $parser
,
который будет вызван при встрече с глобальной переменной $name
во время компиляции шаблона.
$fenom->addAccessor('project', function (Fenom\Tokenizer $tokens) { /* ... */ });
Указанный вторым аргументом, парсер будет вызван при встречи компилятором конструкции $.project
.
Парсер сам должен разобрать все токены из набора токенов $tokens
до того момента пока не посчитает что ему их хватит для
интерпретации. Возвращает парсер PHP код, который должен представлять значение восле выполенения, то есть его можно втавить в if()
.
Через метод Fenom::addAccessor($name, $parser)
можно переопределить уже любую другую существующую глобальную переменную.
Метод Fenom::removeAccessor($name)
позволяет удалить любую определенную глобальную переменную или функцию по ее имени.
Готовые решения
Орпеделить парсер для глобальной переменной весьма трудозатратно и требует полного понимания как работают парсеры в Fenom. Это не удобно. Поэтому есть несколько предзаготовленных (умных) парсеров, которые берут рутину на себя, а пользователю остается указать ключевые параметры.
Умные парсеты добавляются через метод Fenom::addAccessorSmart(string $name, string $accessor, string $parser)
,
где $name
имя глобальной переменной, $accessor
— параметр к парсеру, $parser
— предопределенный парсер.
Доступ к свойству
Парсер Fenom::ACCESSOR_PROPERTY
позволит обратится к указанному свойству шаблонизатора из шаблона.
Параметр $accessor
выступает как имя свойства:
$fenom->addAccessorSmart("site", "data", Fenom::ACCESSOR_PROPERTY);
$fenom->data = [
"domain" => 'example.ru',
"support" => 'support@example.ru'
];
В шаблоне появится глобальная переменная $.site
:
<div class="copyright">© <a href="//{$.site.domain}">{$.site.domain}</a></div>
<div class="support">Support <a href="mailto:{$.site.support}">{$.site.support}</a></div>
Свойством может быть любое значение — масиив, объект и т.д.
Доступ к методу
Парсер Fenom::ACCESSOR_METHOD
позволит обратится к указанному методу шаблонизатора из шаблона.
Параметр $accessor
выступает как имя метода:
$fenom->addAccessorSmart("fetch", "fetch", Fenom::ACCESSOR_METHOD);
В шаблоне появится глобальная функция $.fetch
:
{set $menu = $.fetch("site/menu.tpl")} {* $menu = $fenom->fetch("site/menu.tpl") *}
Шаблонизатор не проверят количество и тип параметров которые передает в метод.
Доступ к значению
Парсер Fenom::ACCESSOR_VAR
позволит обратится к указанному значению из шаблона.
Параметр $accessor
выступает как PHP выражение, описывающее значение:
$fenom->addAccessorSmart("storage", "App::getInstance()->storage", Fenom::ACCESSOR_VAR);
В шаблоне появится глобальная переменная $.storage
:
{set $st = $.storage.di.stamp} {* $st = App::getInstance()->storage['di']['stamp'] *}
Доступ к callable
Парсер Fenom::ACCESSOR_CALL
позволит вызвать указанную финкцию или метод из шаблона.
Параметр $accessor
выступает как PHP выражение, описывающее название функции или метод:
$fenom->addAccessorSmart("di", "App::getInstance()->di->get", Fenom::ACCESSOR_CALL);
App::getInstance()->di->get
должно быть callable, то есть:
is_callable([App::getInstance()->di, "get"]) === true;
В шаблоне появится глобальная переменная $.di
:
{set $st = $.di("stamp")} {* $st = App::getInstance()->di->get("stamp") *}
Шаблонизатор не проверят количество и тип параметров которые передает в метод или функцию.
Источники шаблонов
Шаблоны можно получать из самых разных источников.
Когда вы отображаете или вызываете шаблон, либо когда вы подключаете один шаблон к другому, вы указываете источник,
вместе с соответствующим путём и названием шаблона. Если источник явно не задан, то используется источник Fenom\Provider
,
который считывает шаблоны из указанной директории.
Источник шаблонов должен реализовать интерфейс Fenom\ProviderInterface
.
Используйте метод $fenom->setProvider(...)
что бы добавить источник в шаблонизатор, указав название источника и, если есть необходимость,
задать директорию кеша для шаблонов из этого источника. Рассмотрим на примере, реализуем источник шаблонов из базы данных.
Создадим источник:
class DbProvider implements Fenom\ProviderInterface {
// ...
}
Добавляем источник, указав удобное имя.
$provider = new DbProvider();
$fenom->setProvider("db", $provider, "/tmp/cached/db");
Теперь источник можно использовать:
$fenom->display("db:index.tpl", $vars);
{include "db:menu.tpl"}
Расширение кеша (эксперементальное)
Изначально Fenom не рассчитывался на то что кеш скомпиленых шаблонов может располагаться не на файловой системе.
Однако, в теории, есть возможность реализовать свое кеширование для скомпиленых шаблонов без переопределения шаблонизатора.
Речь идет о своем протоколе, отличным от file://
, который можно определить в PHP.
Ваш протокол должен иметь класс реализации как указано в документации Stream Wrapper. Класс протокола может иметь не все указанные в документации методы. Вот список методов, необходимых шаблонизатору:
- CacheStreamWrapper::stream_open
- CacheStreamWrapper::stream_write
- CacheStreamWrapper::stream_close
- CacheStreamWrapper::rename
Для работы через include
:
Note
(On 2014-05-13) Zend OpCacher кроме file://
и phar://
не поддерживает другие протоколы.
Пример работы кеша:
$this->setCacheDir("redis://hash/compiled/");
$cache = fopen("redis://hash/compiled/XnsbfeDnrd.php", "w");
fwrite($cache, "... <template content> ...");
fclose($cache);
rename("redis://hash/compiled/XnsbfeDnrd.php", "redis://hash/compiled/main.php");