Практики розробки
Встановлення
Найкращий спосіб встановити Latte — за допомогою Composer:
composer require latte/latte
Підтримувані версії PHP (стосується останніх мінорних версій Latte):
версія | сумісна з PHP |
---|---|
Latte 3.0 | PHP 8.0 – 8.2 |
Як відобразити шаблон
Як відобразити шаблон? Для цього достатньо цього простого коду:
$latte = new Latte\Engine;
// каталог для кешу
$latte->setTempDirectory('/path/to/tempdir');
$params = [ /* змінні шаблону */ ];
// or $params = new TemplateParameters(/* ... */);
// відобразити у вивід
$latte->render('template.latte', $params);
// відобразити у змінну
$output = $latte->renderToString('template.latte', $params);
Параметри можуть бути масивом або, ще краще, об'єктом, який забезпечить перевірку типів та підказки в редакторах.
Приклади використання ви знайдете також у репозиторії Latte examples.
Продуктивність та кеш
Шаблони в Latte надзвичайно швидкі, оскільки Latte компілює їх безпосередньо в PHP-код і зберігає в кеші на диску. Тому вони не мають жодних додаткових витрат порівняно з шаблонами, написаними на чистому PHP.
Кеш автоматично регенерується щоразу, коли ви змінюєте вихідний файл. Таким чином, під час розробки ви зручно редагуєте шаблони в Latte, і зміни одразу бачите в браузері. Цю функцію можна вимкнути в робочому середовищі та заощадити трохи продуктивності:
$latte->setAutoRefresh(false);
При розгортанні на робочому сервері початкове генерування кешу, особливо для великих програм, зрозуміло, може зайняти деякий час. Latte має вбудований захист від Cache_stampede. Це ситуація, коли збігається велика кількість одночасних запитів, які запускають Latte, і оскільки кеш ще не існує, всі вони почали б генерувати його одночасно. Що непропорційно навантажило б сервер. Latte розумне і при кількох одночасних запитах генерує кеш лише перший потік, інші чекають, а потім використовують його.
Параметри як клас
Краще, ніж передавати змінні до шаблону як масив, — створити клас. Ви отримаєте типобезпечний запис, зручні підказки в IDE та спосіб реєстрації фільтрів і функцій.
class MailTemplateParameters
{
public function __construct(
public string $lang,
public Address $address,
public string $subject,
public array $items,
public ?float $price = null,
) {}
}
$latte->render('mail.latte', new MailTemplateParameters(
lang: $this->lang,
subject: $title,
price: $this->getPrice(),
items: [],
address: $userAddress,
));
Вимкнення автоекранування змінної
Якщо змінна містить рядок у HTML, ви можете позначити її так, щоб Latte
автоматично (і, отже, подвійно) не екранував її. Таким чином ви уникнете
необхідності вказувати в шаблоні |noescape
.
Найпростіший спосіб — обернути рядок в об'єкт Latte\Runtime\Html
:
$params = [
'articleBody' => new Latte\Runtime\Html($article->htmlBody),
];
Latte далі не екранує всі об'єкти, які реалізують інтерфейс
Latte\HtmlStringable
. Ви можете створити власний клас, метод
__toString()
якого повертатиме HTML-код, який не буде автоматично
екрануватися:
class Emphasis extends Latte\HtmlStringable
{
public function __construct(
private string $str,
) {
}
public function __toString(): string
{
return '<em>' . htmlspecialchars($this->str) . '</em>';
}
}
$params = [
'foo' => new Emphasis('hello'),
];
Метод __toString
повинен повертати коректний HTML і
забезпечувати екранування параметрів, інакше може виникнути
вразливість XSS!
Як розширити Latte фільтрами, тегами тощо.
Як додати до Latte власний фільтр, функцію, тег тощо? Про це йдеться в розділі розширюємо Latte. Якщо ви хочете повторно використовувати свої зміни в різних проєктах або ділитися ними з іншими, вам слід створити розширення.
Довільний код у шаблоні {php ...}
Всередині тегу {do}
можна
записувати лише PHP-вирази, тому ви не можете, наприклад, вставити
конструкції типу if ... else
або оператори, що закінчуються крапкою
з комою.
Однак ви можете зареєструвати розширення RawPhpExtension
, яке додає
тег {php ...}
. За допомогою нього можна вставляти будь-який PHP-код. На
нього не поширюються жодні правила режиму sandbox, тому використання
здійснюється на відповідальність автора шаблону.
$latte->addExtension(new Latte\Essential\RawPhpExtension);
Перевірка згенерованого коду
Latte компілює шаблони в PHP-код. Звичайно, він дбає про те, щоб
згенерований код був синтаксично валідним. Однак при використанні
розширень третіх сторін або RawPhpExtension
Latte не може гарантувати
правильність згенерованого файлу. Також можна написати в PHP код, який
хоч і синтаксично правильний, але заборонений (наприклад, присвоєння
значення змінній $this
) і спричинить PHP Compile Error. Якщо ви запишете
таку операцію в шаблоні, вона потрапить і в згенерований PHP-код.
Оскільки в PHP існує близько двох сотень різних заборонених операцій,
Latte не має на меті їх виявляти. На них вкаже саме PHP лише під час
відображення, що зазвичай нічому не заважає.
Але є ситуації, коли ви хочете знати вже під час компіляції шаблону,
що він не містить жодної PHP Compile Error. Особливо якщо шаблони можуть
редагувати користувачі, або ви використовуєте Sandbox. У такому випадку перевіряйте шаблони вже
під час компіляції. Цю функціональність вмикаєте методом
Engine::enablePhpLint()
. Оскільки для перевірки потрібно викликати
бінарний файл PHP, передайте шлях до нього як параметр:
$latte = new Latte\Engine;
$latte->enablePhpLinter('/path/to/php');
try {
$latte->compile('home.latte');
} catch (Latte\CompileException $e) {
// перехопить помилки в Latte, а також Compile Error в PHP
echo 'Error: ' . $e->getMessage();
}
Національне середовище
Latte дозволяє встановити національне середовище, яке впливає на
форматування чисел, дат та сортування. Воно налаштовується за
допомогою методу setLocale()
. Ідентифікатор середовища відповідає
стандарту IETF language tag, який використовує розширення PHP intl
. Він
складається з коду мови та, можливо, коду країни, напр. en_US
для
англійської в Сполучених Штатах, de_DE
для німецької в
Німеччині тощо.
$latte = new Latte\Engine;
$latte->setLocale('uk_UA');
Налаштування середовища впливає на фільтри localDate, sort, number та bytes.
Вимагає PHP-розширення intl
. Налаштування в Latte не впливає
на глобальні налаштування locale в PHP.
Строгий режим
У строгому режимі парсингу Latte перевіряє, чи не відсутні закриваючі
HTML-теги, а також забороняє використання змінної $this
. Вмикаєте
його так:
$latte = new Latte\Engine;
$latte->setStrictParsing();
Генерування шаблонів із заголовком declare(strict_types=1)
вмикаєте так:
$latte = new Latte\Engine;
$latte->setStrictTypes();
Переклад у шаблонах
За допомогою розширення TranslatorExtension
ви додасте до шаблону теги
{_...}
, {translate}
та фільтр translate
. Вони служать для
перекладу значень або частин шаблону на інші мови. Як параметр
вказуємо метод (PHP callable), що виконує переклад:
class MyTranslator
{
public function __construct(private string $lang)
{}
public function translate(string $original): string
{
// з $original створимо $translated відповідно до $this->lang
return $translated;
}
}
$translator = new MyTranslator($lang);
$extension = new Latte\Essential\TranslatorExtension(
$translator->translate(...), // [$translator, 'translate'] в PHP 8.0
);
$latte->addExtension($extension);
Перекладач викликається під час виконання при відображенні шаблону. Однак Latte може перекладати всі статичні тексти вже під час компіляції шаблону. Це заощаджує продуктивність, оскільки кожен рядок перекладається лише один раз, і результат перекладу записується в скомпільовану форму. У каталозі кешу таким чином створюється кілька скомпільованих версій шаблону, по одній для кожної мови. Для цього достатньо лише вказати мову як другий параметр:
$extension = new Latte\Essential\TranslatorExtension(
$translator->translate(...),
$lang,
);
Статичним текстом мається на увазі, наприклад, {_'hello'}
або
{translate}hello{/translate}
. Нестатичні тексти, наприклад, {_$foo}
,
надалі перекладатимуться під час виконання.
Перекладачу можна також передавати додаткові параметри з шаблону за
допомогою {_$original, foo: bar}
або {translate foo: bar}
, які він отримає як
масив $params
:
public function translate(string $original, ...$params): string
{
// $params['foo'] === 'bar'
}
Налагодження та Tracy
Latte намагається зробити розробку якомога приємнішою. Безпосередньо
для цілей налагодження існує трійка тегів {dump}
, {debugbreak}
та {trace}
.
Найбільший комфорт ви отримаєте, якщо ще встановите чудовий інструмент налагодження Tracy та активуєте доповнення для Latte:
// вмикає Tracy
Tracy\Debugger::enable();
$latte = new Latte\Engine;
// активує розширення для Tracy
$latte->addExtension(new Latte\Bridges\Tracy\TracyExtension);
Тепер усі помилки відображатимуться на зрозумілому червоному екрані, включаючи помилки в шаблонах з підсвічуванням рядка та стовпця (відео). Водночас у правому нижньому куті в так званому Tracy Bar з'явиться вкладка для Latte, де чітко видно всі відображувані шаблони та їхні взаємні зв'язки (включаючи можливість перейти до шаблону або скомпільованого коду), а також змінні:

Оскільки Latte компілює шаблони в зрозумілий PHP-код, ви можете зручно крокувати по них у своєму IDE.
Linter: валідація синтаксису шаблонів
Пройти всі шаблони та перевірити, чи не містять вони синтаксичних помилок, вам допоможе інструмент Linter. Він запускається з консолі:
vendor/bin/latte-lint <шлях>
Параметр --strict
активує строгий режим.
Якщо ви використовуєте власні теги, створіть також власну версію Linter,
напр. custom-latte-lint
:
#!/usr/bin/env php
<?php
// вкажіть реальний шлях до файлу autoload.php
require __DIR__ . '/vendor/autoload.php';
$path = $argv[1] ?? '.';
$linter = new Latte\Tools\Linter;
$latte = $linter->getEngine();
// тут додайте окремі свої розширення
$latte->addExtension(/* ... */);
$ok = $linter->scanDirectory($path);
exit($ok ? 0 : 1);
Альтернативно ви можете передати власний об'єкт Latte\Engine
в
Linter:
$latte = new Latte\Engine;
// тут ми конфігуруємо об'єкт $latte
$linter = new Latte\Tools\Linter(engine: $latte);
Завантаження шаблонів з рядка
Вам потрібно завантажувати шаблони з рядків замість файлів, наприклад, для цілей тестування? Вам допоможе StringLoader:
$latte->setLoader(new Latte\Loaders\StringLoader([
'main.file' => '{include other.file}',
'other.file' => '{if true} {$var} {/if}',
]));
$latte->render('main.file', $params);
Обробник винятків
Ви можете визначити власний обробник для очікуваних винятків. Йому
передаються винятки, що виникли всередині {try}
та в sandbox.
$loggingHandler = function (Throwable $e, Latte\Runtime\Template $template) use ($logger) {
$logger->log($e);
};
$latte = new Latte\Engine;
$latte->setExceptionHandler($loggingHandler);
Автоматичний пошук layout
За допомогою тегу {layout}
шаблон
визначає свій батьківський шаблон. Також можливо дозволити
автоматичний пошук layout, що спростить написання шаблонів, оскільки в
них не потрібно буде вказувати тег {layout}
.
Цього можна досягти наступним чином:
$finder = function (Latte\Runtime\Template $template) {
if (!$template->getReferenceType()) {
// повертає шлях до файлу з layout
return 'automatic.layout.latte';
}
};
$latte = new Latte\Engine;
$latte->addProvider('coreParentFinder', $finder);
Якщо шаблон не повинен мати layout, він повідомить про це тегом
{layout none}
.