Розширення 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()
. Першим
аргументом вашої функції фільтра буде значення перед знаком |
, а
наступні аргументи – ті, що передаються після двокрапки :
.
$latte = new Latte\Engine;
// Визначення фільтра (callable об'єкт: функція, статичний метод тощо)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);
// Реєстрація
$latte->addFilter('truncate', $myTruncate);
// Використання в шаблоні: {$text|truncate} або {$text|truncate:100}
Ви також можете зареєструвати Filter Loader, функцію, яка динамічно надає callable об'єкти фільтрів за потрібною назвою:
$latte->addFilterLoader(fn(string $name) => /* повертає callable об'єкт або null */);
Для реєстрації функції, що використовується у виразах шаблону,
використовуйте addFunction()
.
$latte = new Latte\Engine;
// Визначення функції
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;
// Реєстрація
$latte->addFunction('isWeekend', $isWeekend);
// Використання в шаблоні: {if isWeekend($myDate)}Вихідний!{/if}
Більше інформації знайдете в розділі Створення власних фільтрів та Функцій.
Надійний спосіб: Latte Extension
Хоча пряма реєстрація проста, стандартним і рекомендованим способом пакування та розповсюдження розширень Latte є використання класів Extension. Extension служить центральною точкою конфігурації для реєстрації кількох тегів, фільтрів, функцій, проходів компіляції та інших елементів.
Чому використовувати Extensions?
- Організація: Зберігає пов'язані розширення (теги, фільтри тощо для конкретної функції) разом в одному класі.
- Повторне використання та спільне використання: Легко пакуйте свої розширення для використання в інших проектах або для спільного використання зі спільнотою (наприклад, через Composer).
- Повна сила: Власні теги та проходи компіляції можна реєструвати лише через Extensions.
Реєстрація Extension
Extension реєструється в Latte за допомогою методу addExtension()
(або через
конфігураційний файл):
$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);
Якщо ви зареєструєте кілька розширень, і вони визначають теги, фільтри або функції з однаковими назвами, перевагу має останнє додане розширення. Це також означає, що ваші розширення можуть перевизначати нативні теги/фільтри/функції.
Щоразу, коли ви вносите зміни до класу і автоматичне оновлення не вимкнено, Latte автоматично перекомпілює ваші шаблони.
Створення Extension
Для створення власного розширення вам потрібно створити клас, який успадковує від Latte\Extension. Щоб уявити, як виглядає таке розширення, подивіться на вбудоване CoreExtension.php.
Розглянемо методи, які ви можете реалізувати:
beforeCompile (Latte\Engine $engine): void
Викликається перед компіляцією шаблону. Метод можна використовувати, наприклад, для ініціалізації, пов'язаної з компіляцією.
getTags(): array
Викликається під час компіляції шаблону. Повертає асоціативний масив назва тегу ⇒ callable об'єкт, що є функціями для парсингу тегів. Більше інформації.
public function getTags(): array
{
return [
'foo' => FooNode::create(...),
'bar' => BarNode::create(...),
'n:baz' => NBazNode::create(...),
// ...
];
}
Тег 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
визначає, які теги сортуються перед або
після тегу.
public function getTags(): array
{
return [
'foo' => self::order(FooNode::create(...), before: 'bar'),
'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
];
}
getPasses(): array
Викликається під час компіляції шаблону. Повертає асоціативний масив назва проходу ⇒ callable об'єкт, що є функціями, які представляють так звані компіляційні проходи, що проходять і змінюють AST.
Тут також можна використовувати допоміжний метод order()
.
Значення параметрів before
або after
може бути *
зі
значенням перед/після всіх.
public function getPasses(): array
{
return [
'optimize' => Passes::optimizePass(...),
'sandbox' => self::order($this->sandboxPass(...), before: '*'),
// ...
];
}
beforeRender (Latte\Engine $engine): void
Викликається перед кожним рендерингом шаблону. Метод може бути використаний, наприклад, для ініціалізації змінних, що використовуються під час рендерингу.
getFilters(): array
Викликається перед рендерингом шаблону. Повертає фільтри як асоціативний масив назва фільтра ⇒ callable об'єкт. Більше інформації.
public function getFilters(): array
{
return [
'batch' => $this->batchFilter(...),
'trim' => $this->trimFilter(...),
// ...
];
}
getFunctions(): array
Викликається перед рендерингом шаблону. Повертає функції як асоціативний масив назва функції ⇒ callable об'єкт. Більше інформації.
public function getFunctions(): array
{
return [
'clamp' => $this->clampFunction(...),
'divisibleBy' => $this->divisibleByFunction(...),
// ...
];
}
getProviders(): array
Викликається перед рендерингом шаблону. Повертає масив провайдерів,
які зазвичай є об'єктами, що використовують теги під час виконання.
Доступ до них здійснюється через $this->global->...
. Більше інформації.
public function getProviders(): array
{
return [
'myFoo' => $this->foo,
'myBar' => $this->bar,
// ...
];
}
getCacheKey (Latte\Engine $engine): mixed
Викликається перед рендерингом шаблону. Повернене значення стає частиною ключа, хеш якого міститься в назві файлу скомпільованого шаблону. Отже, для різних повернених значень Latte згенерує різні файли кешу.