Sablonok

A Nette a Latte sablonrendszert használja. A Latte-t azért használjuk, mert ez a legbiztonságosabb sablonrendszer a PHP számára, ugyanakkor a legintuitívabb rendszer. Nem kell sok újat tanulnod, csak ismerned kell a PHP-t és néhány Latte taget.

Az a szokásos, hogy az oldal az elrendezési sablonból + az akció sablonból készül el. Így nézhet ki egy layout sablon, figyeld meg a {block} blokkokat és a {include} címkét :

<!DOCTYPE html>
<html>
<head>
	<title>{block title}My App{/block}</title>
</head>
<body>
	<header>...</header>
	{include content}
	<footer>...</footer>
</body>
</html>

És ez lehet az akció sablon:

{block title}Homepage{/block}

{block content}
<h1>Homepage</h1>
...
{/block}

Meghatározza a content blokkot, amely az elrendezésben a {include content} helyére kerül, és újra definiálja a title blokkot is, amely felülírja az elrendezésben a {block title} blokkot. Próbálja meg elképzelni az eredményt.

Sablonok keresése

A sablonok elérési útvonalát egyszerű logika szerint vezetjük le. Megpróbálja megnézni, hogy létezik-e valamelyik sablonfájl ahhoz a könyvtárhoz képest, ahol a prezenter osztály található, ahol a <Presenter> az aktuális prezenter neve és <view> az aktuális művelet neve:

  • templates/<Presenter>/<view>.latte
  • templates/<Presenter>.<view>.latte

Ha a sablon nem található, a program megpróbál a templates könyvtárban keresni egy szinttel feljebb, azaz ugyanazon a szinten, mint a bemutató osztályt tartalmazó könyvtár.

Ha a sablon ott sem található, a válasz 404-es hiba.

A nézetet a $this->setView('otherView') segítségével is megváltoztathatja. Vagy a keresés helyett közvetlenül megadhatja a sablonfájl nevét a $this->template->setFile('/path/to/template.latte') segítségével.

formatTemplateFiles metódus felülbírálásával módosíthatja azokat az elérési utakat, ahol a sablonok keresése történik, amely a lehetséges fájl elérési utak tömbjét adja vissza.

Az elrendezés a következő fájlokban várható:

  • templates/<Presenter>/@<layout>.latte
  • templates/<Presenter>.@<layout>.latte
  • templates/@<layout>.latte több előadónál közös elrendezés

<Presenter> az aktuális előadó neve és <layout> az elrendezés neve, amely alapértelmezés szerint 'layout'. A név megváltoztatható a $this->setLayout('otherLayout') segítségével, így a @otherLayout.latte fájlokat próbálja meg.

Az elrendezéssablon fájlnevét közvetlenül is megadhatja a $this->setLayout('/path/to/template.latte') segítségével. A $this->setLayout(false) használata letiltja az elrendezés keresését.

formatLayoutTemplateFiles metódus felülbírálásával módosíthatja a sablonok keresési útvonalait, amely a lehetséges fájlútvonalak tömbjét adja vissza.

Változók a sablonban

A változókat a $this->template címre írva adjuk át a sablonba, majd a sablonban helyi változóként állnak rendelkezésre:

$this->template->article = $this->articles->getById($id);

Így könnyen átadhatunk bármilyen változót a sablonoknak. Robusztus alkalmazások fejlesztésénél azonban gyakran hasznosabb, ha korlátozzuk magunkat. Például úgy, hogy explicit módon definiáljuk a sablon által elvárt változók listáját és azok típusát. Ez lehetővé teszi a PHP számára a típusellenőrzést, az IDE számára a helyes automatikus kitöltést, a statikus elemzés számára pedig a hibák felderítését.

És hogyan definiáljunk egy ilyen felsorolást? Egyszerűen egy osztály és annak tulajdonságai formájában. A presenterhez hasonlóan nevezzük el, de a végén Template címmel:

/**
 * @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 egyéb változók
}

A $this->template objektum a prezenterben mostantól a ArticleTemplate osztály példánya lesz. A PHP tehát ellenőrizni fogja a deklarált típusokat íráskor. A PHP 8.2-től kezdve pedig figyelmeztetni fog a nem létező változóba való írásra is, a korábbi verziókban ugyanezt a Nette\SmartObject tulajdonsággal lehet elérni.

A @property-read annotáció az IDE és a statikus elemzés számára készült, ez teszi működőképessé az automatikus kitöltést, lásd PhpStorm és kódkiegészítés $this->template számára.

A sablonokban is megengedheted magadnak a suttogás luxusát, csak telepítsd a Latte plugint a PhpStormban, és add meg az osztály nevét a sablon elején, lásd a Latte: hogyan kell tipizálni a rendszert című cikket:

{templateType App\Presenters\ArticleTemplate}
...

Így működnek a sablonok a komponensekben is, csak kövesse a névadási konvenciót, és hozzon létre egy sablon osztályt FifteenTemplate a komponenshez pl. FifteenControl.

Ha a $template egy másik osztály példányaként kell létrehozni, használjuk 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 prezenterek és komponensek számos hasznos változót adnak át automatikusan a sablonoknak:

  • $basePath egy abszolút URL elérési útvonal a gyökérkönyvtárhoz (például /CD-collection).
  • $baseUrl egy abszolút URL cím a gyökérkönyvtárhoz (pl. http://localhost/CD-collection)
  • $user egy objektum, amely a felhasználót képviseli
  • $presenter az aktuális előadó
  • $control az aktuális komponens vagy bemutató
  • $flashes a módszer által küldött üzenetek listája flashMessage()

Ha egyéni sablonosztályt használ, ezeket a változókat akkor adja át, ha létrehoz egy tulajdonságot számukra.

A sablonban az alábbiak szerint hozunk létre linkeket más előadókra és műveletekre:

<a n:href="Product:show">detail</a>

A n:href attribútum nagyon hasznos a HTML címkékhez. <a>. Ha a linket máshol, például a szövegben akarjuk kiírni, akkor a {link}-t használjuk:

URL is: {link Home:default}

További információért lásd: Linkek létrehozása.

Egyéni szűrők, címkék stb.

A Latte templating rendszer kibővíthető egyéni szűrőkkel, függvényekkel, címkékkel stb. Ez közvetlenül a render<View> vagy a beforeRender() metódusban:

public function beforeRender(): void
{
	// szűrő hozzáadása
	$this->template->addFilter('foo', /* ... */);

	// vagy közvetlenül a Latte\Engine objektum konfigurálása
	$latte = $this->template->getLatte();
	$latte->addFilterLoader(/* ... */);
}

A Latte 3. verziója egy fejlettebb módszert kínál, amely minden egyes webes projekthez egy bővítményt hoz létre. Íme egy durva példa egy ilyen osztályra:

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()),
			// ...
		];
	}

	// ...
}

configuration segítségével regisztráljuk:

latte:
	extensions:
		- App\Templating\LatteExtension

Fordítás

Ha többnyelvű alkalmazást programoz, valószínűleg a sablonban lévő szöveg egy részét különböző nyelveken kell majd kiadnia. Ehhez a Nette Framework definiál egy fordítási felületet Nette\Localization\Translator, amelynek egyetlen metódusa a translate(). Ez elfogadja a $message üzenetet, amely általában egy karakterlánc, és bármilyen más paramétert. A feladat a lefordított karakterlánc visszaadása. A Nette-ben nincs alapértelmezett implementáció, a Componette-en található számos kész megoldás közül választhatunk igényeinknek megfelelően. A dokumentációjukból megtudhatjuk, hogyan kell a fordítót konfigurálni.

A sablonokat a setTranslator() metódus segítségével állíthatjuk be egy fordítóval, amelyet átadunk magunknak:

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator);
}

Alternatívaként a fordítót a konfiguráció segítségével is beállíthatjuk:

latte:
	extensions:
		- Latte\Essential\TranslatorExtension

A fordító ekkor például a |translate szűrőként használható, a translate() metódusnak átadott további paraméterekkel (lásd foo, bar):

<a href="basket">{='Basket'|translate}</a>
<span>{$item|translate}</span>
<span>{$item|translate, foo, bar}</span>

Vagy aláhúzáscímkeként:

<a href="basket">{_'Basket'}</a>
<span>{_$item}</span>
<span>{_$item, foo, bar}</span>

A sablonrészlet fordításához van egy párosított tag {translate} (a Latte 2.11 óta, korábban a {_} taget használták ):

<a href="order">{translate}Order{/translate}</a>
<a href="order">{translate foo, bar}Order{/translate}</a>

A fordítót alapértelmezés szerint futásidőben hívja meg a sablon renderelésekor. A Latte 3. verziója azonban képes lefordítani az összes statikus szöveget a sablon összeállítása során. Ez teljesítményt takarít meg, mivel minden egyes karakterláncot csak egyszer fordít le, és az így kapott fordítás a lefordított formába kerül. Ez a sablon több lefordított változatát hozza létre a gyorsítótárban, egyet-egyet minden nyelvhez. Ehhez csak a nyelvet kell megadni második paraméterként:

protected function beforeRender(): void
{
	// ...
	$this->template->setTranslator($translator, $lang);
}

Statikus szöveg alatt például a {_'hello'} vagy a {translate}hello{/translate} szöveget értjük. A nem statikus szövegek, például a {_$foo}, továbbra is menet közben kerülnek lefordításra.