====== Создание собственных фильтров WACT ======
Чтобы создать свой собственный фильтр, вы должны создать свой собственный класс, имеющий тип WactCompilerFilter (limb/wact/src/compiler/filter/WactCompilerFilter.class.php).
Файл вашего нового класса должен быть расположен в одной из директорий вида src/template/tags и иметь имя some_filter_name.filter.php. Обратите внимание на окончание .filter.php.
Рассмотрим пример простого фильтра, выполняющего операцию заключения строки в кавычки. Назовем нам фильтр QuoteFilter. В шаблоне мы предполагаем использовать синтаксис {$var|quote}.
===== Компиляция константных значений =====
Пример шаблона:
{$'A String'|quote}
За компиляцию константных значений отвечает метод **getValue()** фильтра.
В нашем случае это будет:
function getValue()
{
if ($this->isConstant()) {
return quote($this->base->getValue());
} else {
RaiseError('compiler', 'UNRESOLVED_BINDING');
}
}
(Здесь и далее мы подразумеваем, что функция quote($string) уже определена)
WACT компилирует такие шаблоны в полностью статический код, то есть в скомпилированном шаблоне вы получите следующее:
"A string"
Любой фильтр содержит ссылку на так называемую базу **$base**. **$base** - это обычно объект класса WactExpression или же WactDataBindingExpression, в зависимости от того, является ли база контстантным значением или же ее значение не может быть определено на этапе компиляции. В принципе, если к выражению применена целая цепочка фильтров (несколько фильтров сразу), то базой может быть другой фильтр.
База, впрочем как и параметры фильтров (см. ниже) поддерживают следующий набор методов:
* **isConstant()** - возвращает true, если параметр - статический.
* **getValue()** - возвращает значение статического параметра или генерит ошибку для динамического параметра.
* **generatePreStatement($code_writer)** - генерит код, необходимый для получения контейнера данных, из которого можно взять значение параметра на этапе выполнения шаблона.
* **generateExpression($code_writer)** - генерит код получающий значение параметра из контейнера данных.
* **generatePostStatement($code_writer)** - генерит завершающий код (реально редко не используется).
Фильтр считается константным, если его база и все его параметры также являются статическими. Только в этом случае будет вызван метод getValue() для фильтра.
===== Компиляция динамического фильтра =====
Пример шаблона:
{$variable|quote}
За компиляцию динамических значений отвечает метод **generateExpression($code_writer)** фильтра.
$code_writer - это экземпляр класса WactCodeWriter, который мы упоминали в разделе [[compiler|"Как работает компилятор WACT-шаблонов"]].
В нашем случае это будет:
function generateExpression($code_writer)
{
$code_writer->writePHP('quote(');
$this->base->generateExpression($code_writer);
$code_writer->writePHP(')');
}
WACT компилирует такие шаблоны в "динамический" код, то есть в скомпилированном шаблоне фильтр применяется "на лету".
Обратите внимание, что последний $code_writer->writePHP(')'); не содержит завершающей точки и запятой, так как фильтр может быть частью длинной цепочки.
===== Как избавиться от "статической" компиляции? =====
Для начала давайте выясним, зачем это вообще нужно? Ведь, казалось бы, при компиляции в "статику" мы получаем только экономию - на вызове той или иной функции (функций). Однако, может возникнуть ситуация, в которой функция будет возвращать свой результат в зависимости от некоего контекста. В нашем случае: возможно, при смене локали мы захотим применять другие кавычки. В таком случае нашему фильтру нужно будет "подменить" метод isConstant() родительского класса:
function isConstant()
{
return false;
}
Таким образом мы сообщаем компилятору WACT, что значение, которое проходит через фильтр - **не** константа и для него нужно сгенерировать код посредством generateExpression().
Если мы воспользуемся таким подходом, метод getValue() становится в нашем фильтре не нужен и его можно смело удалить!
Полный код получившегося фильтра будет выглядеть следующим образом:
/**
* @filter quote
*/
class QuoteFilter extends WactCompilerFilter
{
function isConstant()
{
return false;
}
function generateExpression($code_writer)
{
$code_writer->writePHP('quote((');
$this->base->generateExpression($code_writer);
$code_writer->writePHP(')');
}
}
Как видите, кроме самого кода класса фильтра, здесь имеется также мета-код регистрации нового фильтра в Словаре Фильтров WACT. В нашем случае это мета-тег @filter, которое указывает на имя фильтра, которое вы будете использовать в своих шаблонах.
===== Аннотации фильтров =====
Обратите внимание на использование следующего фрагмента кода в файле нашего QuoteFilter:
/**
* @filter quote
*/
Это так называемые аннотации. По этим аннотациям словарь фильтров формирует свое содержимое. Подробнее о словарях в разделе [[limb3:ru:packages:wact:dictionaries|"Словари элементов WACT-шаблона"]].
Полный список аннотация для фильтров:
* filter - название фильтра, которое используется в шаблоне.
* min_attributes - минимальное количество параметров фильтра (о параметрах чуть ниже).
* max_attributes - максимальное количество параметров фильтра.
Если максимальное и минимальное количество параметров фильтра не указано, соответствующие проверки не делаются.
===== Параметры фильтров =====
Фильтры могут принимать дополнительный параметры, которые в шаблоне следуют за названием фильтра и знака двоеточия, например, {$var|trim:"&"}. "&" - это параметр фильтра [[limb3:ru:packages:wact:filters:core_filters:trim_filter|trim]].
Параметры доступны в классе фильтра в виде атрибута **$parameters**.
Рассмотрим код класса WactTrimFilter:
parameters[0]) && $this->parameters[0]->getValue())
$characters = $this->parameters[0]->getValue();
else
$characters = '';
if (!$this->isConstant())
$this->raiseUnresolvedBindingError();
if($characters)
return trim($this->base->getValue(), $characters);
else
return trim($this->base->getValue());
}
function generateExpression($code)
{
$code->writePHP('trim(');
$this->base->generateExpression($code);
if(isset($this->parameters[0]) && $this->parameters[0]->getValue())
{
$code->writePHP(',');
$this->parameters[0]->generateExpression($code);
}
$code->writePHP(')');
}
}
?>
Параметры не имеют имен, поэтому приходится их получать по индексу.
Параметры поддерживают тот же самый набор методов, что и база.