Шаблони
Nette використовує систему шаблонів Latte. Latte використовується тому, що це найбезпечніша система шаблонів для PHP, і водночас найінтуїтивніша та найзрозуміліша. Вам не потрібно вивчати багато нового, достатньо знати PHP і кілька тегів Latte.
Зазвичай сторінка заповнюється з шаблону макета + шаблону дії. Ось як
може виглядати шаблон макета, зверніть увагу на блоки {block}
і тег
{include}
:
<!DOCTYPE html>
<html>
<head>
<title>{block title}Мое приложение{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
А це може бути шаблоном дій:
{block title}Главная страница{/block}
{block content}
<h1>Главная страница</h1>
...
{/block}
Він визначає блок content
, який вставляється замість
{include content}
у макеті, а також перевизначає блок title
, який
перезаписує {block title}
у макеті. Спробуйте уявити собі
результат.
Пошук шаблонів
Шлях до шаблонів визначається ведучим за допомогою простої логіки.
Він спробує перевірити, чи є один із цих файлів, розташований відносно
каталогу класу ведучого, де <Presenter>
це ім'я поточного
ведучого, а <view>
це ім'я поточної події:
templates/<Presenter>/<view>.latte
templates/<Presenter>.<view>.latte
Якщо шаблон не буде знайдено, він спробує виконати пошук у каталозі
templates
на один рівень вище, тобто на тому ж рівні, що і каталог з
класом presenter.
Якщо шаблон не буде знайдено і там, у відповідь буде видано помилку 404.
Ви також можете змінити вигляд за допомогою $this->setView('jineView')
.
Або, замість прямого пошуку, вкажіть ім'я файлу шаблону за допомогою
$this->template->setFile('/path/to/template.latte')
.
Файли, в яких здійснюється пошук шаблонів, можна змінити, наклавши метод formatTemplateFiles(), який повертає масив можливих імен файлів.
У цих файлах очікується компонування:
templates/<Presenter>/@<layout>.latte
templates/<Presenter>.@<layout>.latte
templates/@<layout>.latte
макет, спільний для кількох доповідачів
Де <Presenter>
це ім'я поточного ведучого і <layout>
це
ім'я макета, яке за замовчуванням дорівнює 'layout'
. Ім'я може бути
змінено за допомогою $this->setLayout('jinyLayout')
, тому будуть
випробувані файли @jinyLayout.latte
.
Ви також можете безпосередньо вказати ім'я файлу шаблону макета за
допомогою $this->setLayout('/path/to/template.latte')
. Використання
$this->setLayout(false)
відключає відстеження макета.
Файли, в яких здійснюється пошук шаблонів макета, можна змінити, наклавши метод formatLayoutTemplateFiles(), який повертає масив можливих імен файлів.
Змінні в шаблоні
Змінні передаються в шаблон шляхом запису їх у $this->template
, а
потім вони доступні в шаблоні як локальні змінні:
$this->template->article = $this->articles->getById($id);
Таким чином, ми можемо легко передавати будь-які змінні в шаблони. Однак при розробці надійних додатків часто корисніше обмежити себе. Наприклад, шляхом явного визначення списку змінних, які очікує шаблон, і їхніх типів. Це дозволить PHP перевіряти типи, IDE – правильно шепотіти, а статичний аналіз – виявляти помилки.
І як визначити таке перерахування? Просто у вигляді класу і його
властивостей. Ми назвемо його як presenter, але з Template
в кінці:
/**
* @property-read ArticleTemplate $template
*/
class ArticlePresenter extends Nette\Application\UI\Presenter
{
}
class ArticleTemplate extends Nette\Bridges\ApplicationLatte\Template
{
public Model\Article $article;
public Nette\Security\User $user;
// та інші змінні
}
Об'єкт $this->template
в presenter тепер буде екземпляром класу
ArticleTemplate
. Таким чином, PHP перевірятиме оголошені типи під час
запису. А починаючи з PHP 8.2, він також буде попереджати при записі в
неіснуючу змінну; в попередніх версіях цього можна домогтися за
допомогою властивості Nette\SmartObject.
Анотація @property-read
призначена для IDE і статичного аналізу, вона
змусить працювати шепіт, див. PhpStorm і завершення коду для
$this->template.

Ви також можете дозволити собі розкіш шепотіти в шаблонах, просто встановіть плагін Latte в PhpStorm і помістіть ім'я класу на початок шаблону, докладнішу інформацію дивіться в статті Latte: як набирати систему:
{templateType App\Presenters\ArticleTemplate}
...
Таким же чином шаблони працюють у компонентах, просто дотримуйтесь
угоди про іменування і створіть клас шаблону FifteenTemplate
для
компонента, наприклад, FifteenControl
.
Якщо вам потрібно створити $template
як екземпляр іншого класу,
використовуйте метод createTemplate()
:
public function renderDefault(): void
{
$template = $this->createTemplate(SpecialTemplate::class);
$template->foo = 123;
// ...
$this->sendTemplate($template);
}
Змінні за замовчуванням
Презентатори та компоненти автоматично передають шаблонам кілька корисних змінних:
$basePath
– абсолютний URL-шлях до кореневого каталогу (наприклад,/eshop
).$baseUrl
– це абсолютна URL-адреса кореневого каталогу (наприклад.http://localhost/eshop
)$user
– це об'єкт, що представляє користувача.$presenter
– нинішній ведучий$control
– поточний компонент або ведучий$flashes
– це масив повідомлень, надісланих функціямиflashMessage()
Якщо ви використовуєте користувацький клас шаблону, ці змінні будуть передані, якщо ви створите для них властивість.
Створення посилань
Шаблон створює таким чином посилання на інших ведучих і заходи:
<a n:href="Product:show">detail produktu</a>
Атрибут n:href
дуже зручний для HTML-тегів. <a>
. Якщо ми
хочемо вказати посилання в іншому місці, наприклад, у тексті, ми
використовуємо {link}
:
Adresa je: {link Home:default}
Додаткові відомості див. у розділі Створення посилань URL.
Користувацькі фільтри, теги тощо.
Система шаблонів Latte може бути розширена за допомогою користувацьких
фільтрів, функцій, тегів тощо. Це можна зробити безпосередньо в методі
render<View>
або beforeRender()
:
public function beforeRender(): void
{
// додати фільтр
$this->template->addFilter('foo', /* ... */);
// або налаштувати об'єкт Latte\Engine безпосередньо
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
Latte версії 3 пропонує більш просунутий спосіб створення розширення для кожного веб-проекту. Ось короткий приклад такого класу:
namespace App\Templating;
final class LatteExtension extends Latte\Extension
{
public function __construct(
private App\Model\Facade $facade,
private Nette\Security\User $user,
// ...
) {
}
public function getFilters(): array
{
return [
'timeAgoInWords' => $this->filterTimeAgoInWords(...),
'money' => $this->filterMoney(...),
// ...
];
}
public function getFunctions(): array
{
return [
'canEditArticle' =>
fn($article) => $this->facade->canEditArticle($article, $this->user->getId()),
// ...
];
}
// ...
}
Ми реєструємо його за допомогою конфігурації:
latte:
extensions:
- App\Templating\LatteExtension
Перекладати
Якщо ви програмуєте багатомовний додаток, вам, ймовірно, знадобиться
виводити частину тексту в шаблоні різними мовами. Для цього в Nette Framework
визначено інтерфейс перекладу Nette\Localization\Translator, який має
єдиний метод translate()
. Він приймає повідомлення $message
, яке
зазвичай є рядком, і будь-які інші параметри. Завдання полягає у
поверненні перекладеного рядка. У Nette немає реалізації за
замовчуванням, ви можете вибрати відповідно до своїх потреб з
декількох готових рішень, які можна знайти на Componette. Їх документація підкаже вам, як
налаштувати перекладач.
Шаблони можна налаштувати за допомогою перекладача, який нам передадуть, за допомогою
методу setTranslator()
:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
Крім того, перекладач можна встановити за допомогою конфігурації:
latte:
extensions:
- Latte\Essential\TranslatorExtension
Тоді перекладач можна використовувати, наприклад, як фільтр
|translate
, з додатковими параметрами, переданими методу
translate()
(див. foo, bar
):
<a href="basket">{='Basket'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Або як тег підкреслення:
<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
Для перекладу шаблонних розділів існує парний тег {translate}
(починаючи з версії Latte 2.11, раніше використовувався тег {_}
):
<a href="order">{translate}Order{/translate}</a>
<a href="order">{translate foo, bar}Order{/translate}</a>
Перекладач викликається за замовчуванням під час виконання шаблону під час рендерингу. Однак у версії 3 Latte може перекладати весь статичний текст під час компіляції шаблону. Це економить продуктивність, оскільки кожен рядок перекладається лише один раз, а результат перекладу записується до скомпільованої форми. Це створює кілька скомпільованих версій шаблону в кеш-пам'яті, по одній для кожної мови. Для цього вам потрібно лише вказати мову як другий параметр:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Під статичним текстом мається на увазі, наприклад, {_'hello'}
або
{translate}hello{/translate}
. Нестатичний текст, такий як {_$foo}
, буде
продовжувати компілюватися на льоту.