Расширение Latte
Latte разработано с учетом возможности расширения. Хотя стандартный набор тегов, фильтров и функций охватывает многие случаи использования, часто возникает необходимость добавить собственную специфическую логику или вспомогательные инструменты. Эта страница предоставляет обзор способов расширения Latte, чтобы оно идеально соответствовало требованиям вашего проекта — от простых помощников до сложного нового синтаксиса.
Способы расширения Latte
Вот краткий обзор основных способов настройки и расширения Latte:
- Пользовательские фильтры: Для
форматирования или преобразования данных непосредственно в выводе
шаблона (например,
{$var|myFilter}
). Идеально подходят для таких задач, как форматирование дат, редактирование текста или применение специфического экранирования. Вы также можете использовать их для изменения больших блоков HTML-содержимого, обернув содержимое анонимным{block}
и применив к нему пользовательский фильтр. - Пользовательские функции: Для
добавления повторно используемой логики, которую можно вызывать в
выражениях шаблона (например,
{myFunction($arg1, $arg2)}
). Полезны для вычислений, доступа к вспомогательным функциям приложения или генерации небольших фрагментов контента. - Пользовательские теги: Для создания
совершенно новых языковых конструкций (
{mytag}...{/mytag}
илиn:mytag
). Теги предлагают наибольшие возможности, позволяют определять собственные структуры, управлять парсингом шаблона и реализовывать сложную логику рендеринга. - Проходы компиляции: Функции, которые изменяют абстрактное синтаксическое дерево (AST) шаблона после парсинга, но до генерации PHP-кода. Используются для продвинутых оптимизаций, проверок безопасности (например, Sandbox) или автоматических изменений кода.
- Пользовательские загрузчики: Для изменения способа, которым Latte ищет и загружает файлы шаблонов (например, загрузка из базы данных, зашифрованного хранилища и т. д.).
Выбор правильного метода расширения является ключевым. Прежде чем создавать сложный тег, подумайте, не будет ли достаточно более простого фильтра или функции. Давайте рассмотрим это на примере: реализация генератора Lorem ipsum, который в качестве аргумента принимает количество слов для генерации.
- Как тег?
{lipsum 40}
– Возможно, но теги больше подходят для управляющих структур или генерации сложных тегов. Теги нельзя использовать непосредственно в выражениях. - Как фильтр?
{=40|lipsum}
– Технически это работает, но фильтры предназначены для преобразования входного значения. Здесь40
— это аргумент, а не значение, которое преобразуется. Это кажется семантически неправильным. - Как функция?
{lipsum(40)}
– Это самое естественное решение! Функции принимают аргументы и возвращают значения, что идеально подходит для использования в любом выражении:{var $text = lipsum(40)}
.
Общая рекомендация: Используйте функции для вычислений/генерации, фильтры для преобразования и теги для новых языковых конструкций или сложных тегов. Проходы используйте для манипуляции AST, а загрузчики для получения шаблонов.
Прямая регистрация
Для вспомогательных инструментов, специфичных для проекта, или
быстрых расширений Latte позволяет напрямую регистрировать фильтры и
функции в объекте Latte\Engine
.
Для регистрации фильтра используйте метод addFilter()
. Первым
аргументом вашей функции-фильтра будет значение перед символом
|
, а последующие аргументы — это те, которые передаются после
двоеточия :
.
Вы также можете зарегистрировать Загрузчик фильтров, функцию, которая динамически предоставляет вызываемые объекты фильтров по запрошенному имени:
Для регистрации функции, используемой в выражениях шаблона,
используйте addFunction()
.
Больше информации вы найдете в разделах Создание пользовательских фильтров и Функций.
Надежный способ: Расширение Latte
Хотя прямая регистрация проста, стандартным и рекомендуемым способом упаковки и распространения расширений Latte является использование классов Extension. Extension служит центральной точкой конфигурации для регистрации нескольких тегов, фильтров, функций, проходов компиляции и других элементов.
Зачем использовать Extensions?
- Организация: Сохраняет связанные расширения (теги, фильтры и т. д. для конкретной функции) вместе в одном классе.
- Повторное использование и обмен: Легко упаковывать свои расширения для использования в других проектах или для обмена с сообществом (например, через Composer).
- Полная мощь: Пользовательские теги и проходы компиляции можно регистрировать только через Extensions.
Регистрация Extension
Extension регистрируется в Latte с помощью метода addExtension()
(или через
файл конфигурации):
Если вы зарегистрируете несколько расширений, и они определяют теги, фильтры или функции с одинаковыми именами, приоритет будет иметь последнее добавленное расширение. Это также означает, что ваши расширения могут переопределять нативные теги/фильтры/функции.
Каждый раз, когда вы вносите изменения в класс и автоматическое обновление не отключено, Latte автоматически перекомпилирует ваши шаблоны.
Создание Extension
Для создания собственного расширения вам нужно создать класс, который наследуется от Latte\Extension. Чтобы представить, как выглядит такое расширение, посмотрите на встроенное CoreExtension.
Рассмотрим методы, которые вы можете реализовать:
beforeCompile (Latte\Engine $engine): void
Вызывается перед компиляцией шаблона. Метод можно использовать, например, для инициализаций, связанных с компиляцией.
getTags(): array
Вызывается при компиляции шаблона. Возвращает ассоциативный массив имя тега ⇒ вызываемый объект, который представляет собой функции для парсинга тегов. Подробнее.
Тег n:baz
представляет собой чистый n:атрибут, то есть тег, который можно
записать только как атрибут.
Для тегов foo
и bar
Latte автоматически распознает, являются
ли они парными, и если да, то их можно автоматически записывать с
помощью n:атрибутов, включая варианты с префиксами n:inner-foo
и
n:tag-foo
.
Порядок выполнения таких n:атрибутов определяется их порядком в
массиве, возвращаемом методом getTags()
. Таким образом, n:foo
всегда выполняется перед n:bar
, даже если атрибуты в HTML-теге
указаны в обратном порядке, например <div n:bar="..." n:foo="...">
.
Если вам нужно определить порядок n:атрибутов между несколькими
расширениями, используйте вспомогательный метод order()
, где
параметр before
xor after
указывает, какие теги сортируются до
или после тега.
getPasses(): array
Вызывается при компиляции шаблона. Возвращает ассоциативный массив имя прохода ⇒ вызываемый объект, который представляет собой функции, представляющие так называемые проходы компиляции, которые проходят и изменяют AST.
Здесь также можно использовать вспомогательный метод order()
.
Значение параметров before
или after
может быть *
, что
означает до/после всех.
beforeRender (Latte\Engine $engine): void
Вызывается перед каждым рендерингом шаблона. Метод может быть использован, например, для инициализации переменных, используемых во время рендеринга.
getFilters(): array
Вызывается перед рендерингом шаблона. Возвращает фильтры как ассоциативный массив имя фильтра ⇒ вызываемый объект. Подробнее.
getFunctions(): array
Вызывается перед рендерингом шаблона. Возвращает функции как ассоциативный массив имя функции ⇒ вызываемый объект. Подробнее.
getProviders(): array
Вызывается перед рендерингом шаблона. Возвращает массив
поставщиков, которые обычно являются объектами, используемыми тегами
во время выполнения. Доступ к ним осуществляется через
$this->global->...
. Подробнее.
getCacheKey (Latte\Engine $engine): mixed
Вызывается перед рендерингом шаблона. Возвращаемое значение становится частью ключа, хеш которого содержится в имени файла скомпилированного шаблона. Таким образом, для разных возвращаемых значений Latte сгенерирует разные файлы кеша.