Sablonok
A Nette a Latte sablonrendszert használja. Egyrészt azért, mert ez a legbiztonságosabb sablonrendszer PHP-hoz, másrészt pedig a legintuitívabb rendszer. Nem kell sok újat tanulnia, elegendő a PHP ismerete és néhány tag.
Gyakori, hogy egy oldal egy layout sablonból + az adott akció sablonjából áll össze. Így nézhet ki például egy layout
sablon, figyelje meg a {block}
blokkokat és a {include}
taget:
<!DOCTYPE html>
<html>
<head>
<title>{block title}Saját Alkalmazás{/block}</title>
</head>
<body>
<header>...</header>
{include content}
<footer>...</footer>
</body>
</html>
És ez lesz az akció sablonja:
{block title}Kezdőlap{/block}
{block content}
<h1>Kezdőlap</h1>
...
{/block}
Ez definiálja a content
blokkot, amely a {include content}
helyére kerül a layoutban, és újra
definiálja a title
blokkot, amely felülírja a {block title}
-t a layoutban. Próbálja meg elképzelni
az eredményt.
Sablonok keresése
Nem kell a presenterekben megadnia, hogy melyik sablont kell renderelni, a keretrendszer maga vezeti le az utat, és megspórolja Önnek az írást.
Ha olyan könyvtárstruktúrát használ, ahol minden presenternek saját könyvtára van, egyszerűen helyezze el a sablont
ebben a könyvtárban az akció (ill. view) nevével, azaz a default
akcióhoz használja a
default.latte
sablont:
app/ └── Presentation/ └── Home/ ├── HomePresenter.php └── default.latte
Ha olyan struktúrát használ, ahol a presenterek egy könyvtárban vannak, a sablonok pedig a templates
mappában, mentse el vagy a <Presenter>.<view>.latte
vagy a
<Presenter>/<view>.latte
fájlba:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── Home.default.latte ← 1. változat └── Home/ └── default.latte ← 2. változat
A templates
könyvtár egy szinttel feljebb is elhelyezkedhet, azaz ugyanazon a szinten, mint a presenter
osztályokat tartalmazó könyvtár.
Ha a sablon nem található, a presenter 404 – page not found hibával válaszol.
A view-t a $this->setView('jineView')
segítségével változtathatja meg. Közvetlenül is megadhatja a
sablonfájlt a $this->template->setFile('/path/to/template.latte')
segítségével.
A fájlokat, ahol a sablonokat keresi, meg lehet változtatni a formatTemplateFiles() metódus felülírásával, amely visszaadja a lehetséges fájlnevek tömbjét.
Layout sablon keresése
A Nette automatikusan megkeresi a layout fájlt is.
Ha olyan könyvtárstruktúrát használ, ahol minden presenternek saját könyvtára van, helyezze el a layoutot vagy a presenter mappájában, ha csak rá specifikus, vagy egy szinttel feljebb, ha több presenter számára közös:
app/ └── Presentation/ ├── @layout.latte ← közös layout └── Home/ ├── @layout.latte ← csak a Home presenterhez ├── HomePresenter.php └── default.latte
Ha olyan struktúrát használ, ahol a presenterek egy könyvtárban vannak, a sablonok pedig a templates
mappában, a layoutot ezeken a helyeken várja:
app/ └── Presenters/ ├── HomePresenter.php └── templates/ ├── @layout.latte ← közös layout ├── Home.@layout.latte ← csak a Home-hoz, 1. változat └── Home/ └── @layout.latte ← csak a Home-hoz, 2. változat
Ha a presenter egy modulban található, akkor további könyvtárszinteken is keresni fog, a modul beágyazási mélységétől függően.
A layout nevét a $this->setLayout('layoutAdmin')
segítségével lehet megváltoztatni, és akkor a
@layoutAdmin.latte
fájlban várja. Közvetlenül is megadhatja a layout sablonfájlt a
$this->setLayout('/path/to/template.latte')
segítségével.
A $this->setLayout(false)
vagy a {layout none}
tag használatával a sablonon belül
kikapcsolható a layout keresése.
A fájlokat, ahol a layout sablonokat keresi, meg lehet változtatni a formatLayoutTemplateFiles() metódus felülírásával, amely visszaadja a lehetséges fájlnevek tömbjét.
Változók a sablonban
Változókat úgy adunk át a sablonnak, hogy beírjuk őket a $this->template
-be, és utána lokális
változókként érhetők el a sablonban:
$this->template->article = $this->articles->getById($id);
Így egyszerűen bármilyen változót átadhatunk a sablonoknak. Robusztus alkalmazások fejlesztésekor azonban hasznosabb korlátozni magunkat. Például úgy, hogy explicit módon definiáljuk a sablon által várt változók listáját és azok típusait. Ennek köszönhetően a PHP ellenőrizni tudja a típusokat, az IDE helyesen tud súgni, és a statikus analízis felfedezheti a hibákat.
És hogyan definiálunk egy ilyen listát? Egyszerűen egy osztály és annak property-jei formájában. Nevezzük el
hasonlóan a presenterhez, csak Template
végződéssel:
/**
* @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;
// és további változók
}
A $this->template
objektum a presenterben mostantól az ArticleTemplate
osztály példánya lesz.
Így a PHP ellenőrizni fogja a deklarált típusokat íráskor. És a PHP 8.2-es verziójától kezdve figyelmeztet a nem
létező változóba való írásra is, korábbi verziókban ugyanezt a Nette\SmartObject trait használatával lehet elérni.
Az @property-read
annotáció az IDE-nek és a statikus analízisnek szól, ennek köszönhetően működni fog a
súgó, lásd PhpStorm and code completion for
$this->template.

A súgó luxusát a sablonokban is élvezheti, csak telepíteni kell a PhpStorm-ba a Latte plugint, és a sablon elejére beírni az osztály nevét, további információk a Latte: hogyan a típusrendszerre cikkben:
{templateType App\Presentation\Article\ArticleTemplate}
...
Így működnek a sablonok a komponensekben is, csak be kell tartani a névkonvenciót, és például a
FifteenControl
komponenshez létrehozni egy FifteenTemplate
sablonosztályt.
Ha a $template
-et egy másik osztály példányaként kell létrehoznia, használja a
createTemplate()
metódust:
public function renderDefault(): void
{
$template = $this->createTemplate(SpecialTemplate::class);
$template->foo = 123;
// ...
$this->sendTemplate($template);
}
Alapértelmezett változók
A presenterek és komponensek automatikusan átadnak néhány hasznos változót a sablonoknak:
$basePath
az abszolút URL elérési út a gyökérkönyvtárhoz (pl./eshop
)$baseUrl
az abszolút URL a gyökérkönyvtárhoz (pl.http://localhost/eshop
)$user
a felhasználót reprezentáló objektum$presenter
az aktuális presenter$control
az aktuális komponens vagy presenter$flashes
aflashMessage()
függvénnyel küldött üzenetek tömbje
Ha saját sablonosztályt használ, ezek a változók átadódnak, ha létrehoz hozzájuk property-t.
Linkek létrehozása
A sablonban a linkek más presenterekhez & akciókhoz a következőképpen hozhatók létre:
<a n:href="Product:show">termék részletei</a>
Az n:href
attribútum nagyon praktikus a HTML <a>
tag-ekhez. Ha máshol szeretnénk kiírni a
linket, például szövegben, használjuk a {link}
-et:
A cím: {link Home:default}
További információkat az URL linkek létrehozása fejezetben talál.
Saját szűrők, tag-ek stb.
A Latte sablonrendszert ki lehet bővíteni saját szűrőkkel, függvényekkel, tag-ekkel stb. Ezt meg lehet tenni
közvetlenül a render<View>
vagy beforeRender()
metódusban:
public function beforeRender(): void
{
// szűrő hozzáadása
$this->template->addFilter('foo', /* ... */);
// vagy közvetlenül konfiguráljuk a Latte\Engine objektumot
$latte = $this->template->getLatte();
$latte->addFilterLoader(/* ... */);
}
A Latte 3-as verziója fejlettebb módszert kínál, mégpedig egy extension létrehozását minden webprojekthez. Egy ilyen osztály töredékes példája:
namespace App\Presentation\Accessory;
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()),
// ...
];
}
// ...
}
Regisztráljuk a konfiguráció segítségével:
latte:
extensions:
- App\Presentation\Accessory\LatteExtension
Fordítás
Ha többnyelvű alkalmazást programoz, valószínűleg szüksége lesz néhány szöveg lefordítására a sablonban
különböző nyelvekre. A Nette Framework erre a célra definiál egy interfészt a fordításhoz Nette\Localization\Translator, amelynek egyetlen
metódusa van, a translate()
. Ez fogadja az üzenetet $message
, ami általában egy string, és
tetszőleges további paramétereket. Feladata a lefordított string visszaadása. A Nette-ben nincs alapértelmezett
implementáció, választhat igényei szerint több kész megoldás közül, amelyeket a Componette oldalon talál. Dokumentációjukban megtudhatja, hogyan
konfigurálja a translatort.
A sablonoknak beállítható egy fordító, amelyet átkérünk, a setTranslator()
metódussal:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator);
}
A translatort alternatívaként be lehet állítani a konfiguráció segítségével is:
latte:
extensions:
- Latte\Essential\TranslatorExtension(@Nette\Localization\Translator)
Ezután a fordítót például használhatjuk |translate
szűrőként, beleértve a kiegészítő paramétereket
is, amelyek átadódnak a translate()
metódusnak (lásd foo, bar
):
<a href="basket">{='Kosár'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>
Vagy aláhúzásos tagként:
<a href="basket">{_'Kosár'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>
A sablon egy szakaszának fordításához létezik egy páros {translate}
tag (Latte 2.11-től, korábban a
{_}
tag volt használatos):
<a href="order">{translate}Rendelés{/translate}</a>
<a href="order">{translate foo, bar}Rendelés{/translate}</a>
A translator alapértelmezés szerint futásidőben hívódik meg a sablon renderelésekor. A Latte 3-as verziója azonban képes az összes statikus szöveget már a sablon fordítása során lefordítani. Ezzel teljesítményt takarítunk meg, mert minden string csak egyszer fordítódik le, és az eredményül kapott fordítás beíródik a lefordított formába. A cache könyvtárban így több lefordított sablonverzió jön létre, minden nyelvre egy. Ehhez elegendő csak a nyelvet második paraméterként megadni:
protected function beforeRender(): void
{
// ...
$this->template->setTranslator($translator, $lang);
}
Statikus szöveg alatt például a {_'hello'}
vagy {translate}hello{/translate}
értendő. A nem
statikus szövegek, mint például a {_$foo}
, továbbra is futásidőben fordítódnak.