Šablony
Nette používá šablonovací systém Latte. Jednak proto, že jde o nejlépe zabezpečený šablonovací systém pro PHP, a zároveň také systém nejintuitivnější. Nemusíte se učit mnoho nového, vystačíte si se znalostí PHP a několika značek.
Je obvyklé, že stránka se složí ze šablony layoutu + šablony dané akce. Takhle třeba může vypadat šablona layoutu,
všimněte si bloků {block}
a značky {include}
:
<!DOCTYPE html>
<html>
<head>
<title>{block title}My App{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
A tohle bude šablona akce:
{block title}Homepage{/block}
{block content}
<h1>Homepage</h1>
...
{/block}
Ta definuje blok content
, který se vloží na místo {include content}
v layoutu, a také
re-definuje blok title
, kterým přepíše {block title}
v layoutu. Zkuste si představit
výsledek.
Hledání šablon
Cestu k šablonám odvodí presenter podle jednoduché logiky. Zkusí, zda existuje jeden z těchto souborů umístěných
relativně od adresáře s třídou presenteru, kde <Presenter>
je název aktuálního presenteru a
<view>
je název aktuální akce:
templates/<Presenter>/<view>.latte
templates/<Presenter>.<view>.latte
Pokud šablonu nenajde, zkusí hledat ještě v adresáři templates
o úroveň výš, tj. na stejné úrovni,
jako je adresář s třídou presenteru.
Pokud ani tam šablonu nenajde, je odpovědí chyba 404.
Můžete také změnit view pomocí $this->setView('jineView')
. Nebo místo dohledávání přímo určit
jméno souboru se šablonou pomocí $this->template->setFile('/path/to/template.latte')
.
Soubory, kde se dohledávají šablony, lze změnit překrytím metody formatTemplateFiles(), která vrací pole možných názvů souborů.
Layout se očekává v těchto souborech:
templates/<Presenter>/@<layout>.latte
templates/<Presenter>.@<layout>.latte
templates/@<layout>.latte
layout společný pro více presenterů
Kde <Presenter>
je název aktuálního presenteru a <layout>
je název layoutu, což je
standardně 'layout'
. Název lze změnit pomocí $this->setLayout('jinyLayout')
, takže se budou
zkoušet soubory @jinyLayout.latte
.
Můžete také přímo určit jméno souboru se šablonou layoutu pomocí
$this->setLayout('/path/to/template.latte')
. Pomocí $this->setLayout(false)
se dohledávání
layoutu vypne.
Soubory, kde se dohledávají šablony layoutu, lze změnit překrytím metody formatLayoutTemplateFiles(), která vrací pole možných názvů souborů.
Proměnné v šabloně
Proměnné do šablony předáváme tak, že je zapíšeme do $this->template
a potom je máme k dispozici
v šabloně jako lokální proměnné:
$this->template->article = $this->articles->getById($id);
Takto jednoduše můžeme do šablon předat jakékoliv proměnné. Při vývoji robustních aplikací ale bývá užitečnější se omezit. Například tak, že explicitně nadefinujeme výčet proměnných, které šablona očekává, a jejich typů. Díky tomu nám bude moci PHP kontrolovat typy, IDE správně našeptávat a statická analýza odhalovat chyby.
A jak takový výčet nadefinujeme? Jednoduše v podobě třídy a její properties. Pojmenujeme ji podobně jako presenter,
jen s Template
na konci:
/**
* @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;
// a další proměnné
}
Objekt $this->template
v presenteru bude nyní instancí třídy ArticleTemplate
. Takže PHP bude
při zápisu kontrolovat deklarované typy. A počínaje verzí PHP 8.2 upozorní i na zápis do neexistující proměnné,
v předchozích verzích lze téhož dosáhnout použitím traity Nette\SmartObject.
Anotace @property-read
je určená pro IDE a statickou analýzu, díky ní bude fungovat našeptávání, viz PhpStorm and code completion for
$this->template.

Luxusu našeptávání si můžete dopřát i v šablonách, stačí do PhpStorm nainstalovat plugin pro Latte a uvést na začátek šablony název třídy, více v článku Latte: jak na typový systém:
{templateType App\Presenters\ArticleTemplate}
...
Takto fungují i šablony v komponentách, stačí jen dodržet jmennou konvenci a pro komponentu např.
FifteenControl
vytvořit třídu šablony FifteenTemplate
.
Pokud potřebujete vytvořit $template
jako instanci jiné třídy, využijte metodu
createTemplate()
:
public function renderDefault(): void
{
$template = $this->createTemplate(SpecialTemplate::class);
$template->foo = 123;
// ...
$this->sendTemplate($template);
}
Výchozí proměnné
Presentery a komponenty předávají do šablon několik užitečných proměnných automaticky:
$basePath
je absolutní URL cesta ke kořenovému adresáři (např./eshop
)$baseUrl
je absolutní URL ke kořenovému adresáři (např.http://localhost/eshop
)$user
je objekt reprezentující uživatele$presenter
je aktuální presenter$control
je aktuální komponenta nebo presenter$flashes
pole zpráv zaslaných funkcíflashMessage()
Pokud používáte vlastní třídu šablony, tyto proměnné se předají, pokud pro ně vytvoříte property.
Vytváření odkazů
V šabloně se vytvářejí odkazy na další presentery & akce tímto způsobem:
<a n:href="Product:show">detail produktu</a>
Atribut n:href
je velmi šikovný pro HTML značky <a>
. Chceme-li odkaz vypsat jinde,
například v textu, použijeme {link}
:
Adresa je: {link Home:default}
Více informací najdete v kapitole Vytváření odkazů URL.
Vlastní filtry, značky apod.
Šablonovací systém Latte lze rozšířit o vlastní filtry, funkce, značky apod. Lze tak učinit přímo v metodě
render<View>
nebo beforeRender()
:
public function beforeRender(): void
{
// přidání filtru
$this->template->addFilter('foo', /* ... */);
// nebo konfigurujeme přímo objekt Latte\Engine
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
Latte ve verzi 3 nabízí pokročilejší způsob a to vytvoření si extension pro každý webový projekt. Kusý příklad takové třídy:
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()),
// ...
];
}
// ...
}
Zaregistrujeme ji pomocí konfigurace:
latte:
extensions:
- App\Templating\LatteExtension
Překládání
Pokud programujete vícejazyčnou aplikaci, budete nejspíš potřebovat některé texty v šabloně vypsat v různých
jazycích. Nette Framework k tomuto účelu definuje rozhraní pro překlad Nette\Localization\Translator, které má jedinou
metodu translate()
. Ta přijímá zprávu $message
, což zpravidla bývá řetězec, a libovolné
další parametry. Úkolem je vrátit přeložený řetězec. V Nette není žádná výchozí implementace, můžete si vybrat
podle svých potřeb z několika hotových řešeních, které najdete na Componette. V jejich dokumentaci se dozvíte, jak translator
konfigurovat.
Šablonám lze nastavit překladač, který si necháme předat, metodou
setTranslator()
:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
Translator je alternativně možné nastavit pomocí konfigurace:
latte:
extensions:
- Latte\Essential\TranslatorExtension
Poté lze překladač používat například jako filtr |translate
, a to včetně doplňujících parametrů,
které se předají metodě translate()
(viz foo, bar
):
<a href="basket">{='Košík'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Nebo jako podtržítkovou značku:
<a href="basket">{_'Košík'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
Pro překlad úseku šablony existuje párová značka {translate}
(od Latte 2.11, dříve se používala značka
{_}
):
<a href="order">{translate}Objednávka{/translate}</a>
<a href="order">{translate foo, bar}Objednávka{/translate}</a>
Translator se standardně volá za běhu při vykreslování šablony. Latte verze 3 ovšem umí všechny statické texty překládat už během kompilace šablony. Tím se ušetří výkon, protože každý řetězec se přeloží jen jednou a výsledný překlad se zapíše do zkompilované podoby. V adresáři s cache tak vznikne více zkompilovaných verzí šablony, jedna pro každý jazyk. K tomu stačí pouze uvést jazyk jako druhý parametr:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Statickým textem je myšleno třeba {_'hello'}
nebo {translate}hello{/translate}
. Nestatické texty,
jako třeba {_$foo}
, se nadále budou překládat za běhu.