====== Создание собственных фильтров 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(')'); } } ?> Параметры не имеют имен, поэтому приходится их получать по индексу. Параметры поддерживают тот же самый набор методов, что и база.