Nette Documentation Preview

syntax
Rozšiřování Latte
*****************

.[perex]
Latte je navrženo s ohledem na rozšiřitelnost. Přestože jeho standardní sada tagů, filtrů a funkcí pokrývá mnoho případů použití, často potřebujete přidat vlastní specifickou logiku nebo pomocné nástroje. Tato stránka poskytuje přehled způsobů, jak rozšířit Latte tak, aby dokonale odpovídalo požadavkům vašeho projektu - od jednoduchých pomocníků až po komplexní novou syntaxi.


Způsoby rozšíření Latte
=======================

Zde je rychlý přehled hlavních způsobů, jak můžete přizpůsobit a rozšířit Latte:

- **[Vlastní filtry |Custom Filters]:** Pro formátování nebo transformaci dat přímo ve výstupu šablony (např. `{$var|myFilter}`). Ideální pro úlohy jako formátování datumů, úpravy textu nebo aplikování specifického escapování. Můžete je také použít k úpravě větších bloků HTML obsahu tak, že obsah obalíte anonymním [`{block}` |tags#block] a aplikujete na něj vlastní filtr.
- **[Vlastní funkce |Custom Functions]:** Pro přidání znovupoužitelné logiky, kterou lze volat v rámci výrazů v šabloně (např. `{myFunction($arg1, $arg2)}`). Užitečné pro výpočty, přístup k pomocným funkcím aplikace nebo generování malých částí obsahu.
- **[Vlastní tagy |Custom Tags]:** Pro vytváření zcela nových jazykových konstrukcí (`{mytag}...{/mytag}` nebo `n:mytag`). Tagy nabízejí nejvíce možností, umožňují definovat vlastní struktury, řídit parsování šablony a implementovat komplexní vykreslovací logiku.
- **[Kompilační průchody |Compiler Passes]:** Funkce, které upravují abstraktní syntaktický strom (AST) šablony po parsování, ale před generováním PHP kódu. Používají se pro pokročilé optimalizace, bezpečnostní kontroly (jako je Sandbox) nebo automatické úpravy kódu.
- **[Vlastní loadery |loaders]:** Pro změnu způsobu, jakým Latte vyhledává a načítá soubory šablon (např. načítání z databáze, šifrovaného úložiště atd.).

Výběr správné metody rozšíření je klíčový. Než vytvoříte složitý tag, zvažte, zda by nestačil jednodušší filtr nebo funkce. Ukažme si to na příkladu: implementace generátoru *Lorem ipsum*, který jako argument přijímá počet slov k vygenerování.

- **Jako tag?** `{lipsum 40}` - Možné, ale tagy jsou vhodnější pro řídicí struktury nebo generování složitých značek. Tagy nelze použít přímo ve výrazech.
- **Jako filtr?** `{=40|lipsum}` - Technicky to funguje, ale filtry jsou určeny k *transformaci* vstupní hodnoty. Zde je `40` *argument*, nikoli hodnota, která se transformuje. To působí sémanticky nesprávně.
- **Jako funkce?** `{lipsum(40)}` - Toto je nejpřirozenější řešení! Funkce přijímají argumenty a vracejí hodnoty, což je ideální pro použití v libovolném výrazu: `{var $text = lipsum(40)}`.

**Obecné doporučení:** Používejte funkce pro výpočty/generování, filtry pro transformaci a tagy pro nové jazykové konstrukce nebo složité značky. Průchody používejte pro manipulaci s AST a loadery pro získávání šablon.


Přímá registrace
================

Pro pomocné nástroje specifické pro projekt nebo rychlá rozšíření umožňuje Latte přímou registraci filtrů a funkcí do objektu `Latte\Engine`.

Pro registraci filtru použijte metodu `addFilter()`. Prvním argumentem vaší filtrační funkce bude hodnota před znakem `|` a následující argumenty jsou ty, které se předávají za dvojtečkou `:`.

```php
$latte = new Latte\Engine;

// Definice filtru (volatelný objekt: funkce, statická metoda atd.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Registrace
$latte->addFilter('truncate', $myTruncate);

// Použití v šabloně: {$text|truncate} nebo {$text|truncate:100}
```

Můžete také zaregistrovat **Filter Loader**, funkci, která dynamicky poskytuje volatelné objekty filtrů podle požadovaného názvu:

```php
$latte->addFilterLoader(fn(string $name) => /* vrátí volatelný objekt nebo null */);
```


Pro registraci funkce použitelné ve výrazech šablony použijte `addFunction()`.

```php
$latte = new Latte\Engine;

// Definice funkce
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Registrace
$latte->addFunction('isWeekend', $isWeekend);

// Použití v šabloně: {if isWeekend($myDate)}Víkend!{/if}
```

Více informací najdete v části [Vytváření vlastních filtrů |custom-filters] a [Funkcí |custom-functions].


Robustní způsob: Latte Extension .{toc: Latte Extension}
========================================================

Zatímco přímá registrace je jednoduchá, standardním a doporučeným způsobem, jak zabalit a distribuovat rozšíření Latte, je prostřednictvím tříd **Extension**. Extension slouží jako centrální konfigurační bod pro registraci více tagů, filtrů, funkcí, kompilačních průchodů a dalších prvků.

Proč používat Extensions?

- **Organizace:** Udržuje související rozšíření (tagy, filtry atd. pro konkrétní funkci) pohromadě v jedné třídě.
- **Znovupoužitelnost a sdílení:** Snadno zabalíte svá rozšíření pro použití v jiných projektech nebo pro sdílení s komunitou (např. přes Composer).
- **Plná síla:** Vlastní tagy a kompilační průchody *lze registrovat pouze* prostřednictvím Extensions.


Registrace Extension
--------------------

Extension se registruje v Latte pomocí metody `addExtension()` (nebo prostřednictvím [konfiguračního souboru |application:configuration#Šablony Latte]):

```php
$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);
```

Pokud zaregistrujete více rozšíření a ta definují stejně pojmenované tagy, filtry nebo funkce, má přednost naposledy přidané rozšíření. To také znamená, že vaše rozšíření mohou přepsat nativní tagy/filtry/funkce.

Kdykoli provedete změnu ve třídě a není vypnuté automatické obnovení, Latte automaticky překompiluje vaše šablony.


Vytvoření Extension
-------------------

Pro vytvoření vlastního rozšíření potřebujete vytvořit třídu, která dědí z [api:Latte\Extension]. Pro představu, jak takové rozšíření vypadá, podívejte se na vestavěné "CoreExtension":https://github.com/nette/latte/blob/master/src/Latte/Essential/CoreExtension.php.

Podívejme se na metody, které můžete implementovat:


beforeCompile(Latte\Engine $engine): void .[method]
---------------------------------------------------

Volá se před kompilací šablony. Metodu lze použít například pro inicializace související s kompilací.


getTags(): array .[method]
--------------------------

Volá se při kompilaci šablony. Vrací asociativní pole *název tagu => volatelný objekt*, což jsou funkce pro parsování tagů. [Více informací |custom-tags].

```php
public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}
```

Tag `n:baz` představuje čistý [n:atribut |syntax#n:atributy], tedy tag, který lze zapsat pouze jako atribut.

U tagů `foo` a `bar` Latte automaticky rozpozná, zda jde o párové tagy, a pokud ano, lze je automaticky zapisovat pomocí n:atributů, včetně variant s předponami `n:inner-foo` a `n:tag-foo`.

Pořadí vykonávání takových n:atributů je určeno jejich pořadím v poli vráceném metodou `getTags()`. Takže `n:foo` je vždy proveden před `n:bar`, i když jsou atributy v HTML tagu uvedeny v opačném pořadí jako `<div n:bar="..." n:foo="...">`.

Pokud potřebujete určit pořadí n:atributů napříč více rozšířeními, použijte pomocnou metodu `order()`, kde parametr `before` xor `after` určuje, které tagy jsou řazeny před nebo za tagem.

```php
public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}
```


getPasses(): array .[method]
----------------------------

Volá se při kompilaci šablony. Vrací asociativní pole *název průchodu => volatelný objekt*, což jsou funkce představující tzv. [kompilační průchody |compiler-passes], které procházejí a upravují AST.

I zde lze použít pomocnou metodu `order()`. Hodnota parametrů `before` nebo `after` může být `*` s významem před/po všech.

```php
public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}
```


beforeRender(Latte\Engine $engine): void .[method]
--------------------------------------------------

Volá se před každým vykreslením šablony. Metoda může být použita například k inicializaci proměnných používaných během vykreslování.


getFilters(): array .[method]
-----------------------------

Volá se před vykreslením šablony. Vrací filtry jako asociativní pole *název filtru => volatelný objekt*. [Více informací |custom-filters].

```php
public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}
```


getFunctions(): array .[method]
-------------------------------

Volá se před vykreslením šablony. Vrací funkce jako asociativní pole *název funkce => volatelný objekt*. [Více informací |custom-functions].

```php
public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}
```


getProviders(): array .[method]
-------------------------------

Volá se před vykreslením šablony. Vrací pole poskytovatelů, což jsou obvykle objekty, které používají tagy za běhu. Přistupuje se k nim přes `$this->global->...`. [Více informací |custom-tags#Představení poskytovatelů].

```php
public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}
```


getCacheKey(Latte\Engine $engine): mixed .[method]
--------------------------------------------------

Volá se před vykreslením šablony. Návratová hodnota se stává součástí klíče, jehož hash je obsažen v názvu souboru kompilované šablony. Pro různé návratové hodnoty tedy Latte vygeneruje různé cache soubory.

Rozšiřování Latte

Latte je navrženo s ohledem na rozšiřitelnost. Přestože jeho standardní sada tagů, filtrů a funkcí pokrývá mnoho případů použití, často potřebujete přidat vlastní specifickou logiku nebo pomocné nástroje. Tato stránka poskytuje přehled způsobů, jak rozšířit Latte tak, aby dokonale odpovídalo požadavkům vašeho projektu – od jednoduchých pomocníků až po komplexní novou syntaxi.

Způsoby rozšíření Latte

Zde je rychlý přehled hlavních způsobů, jak můžete přizpůsobit a rozšířit Latte:

  • Vlastní filtry: Pro formátování nebo transformaci dat přímo ve výstupu šablony (např. {$var|myFilter}). Ideální pro úlohy jako formátování datumů, úpravy textu nebo aplikování specifického escapování. Můžete je také použít k úpravě větších bloků HTML obsahu tak, že obsah obalíte anonymním {block} a aplikujete na něj vlastní filtr.
  • Vlastní funkce: Pro přidání znovupoužitelné logiky, kterou lze volat v rámci výrazů v šabloně (např. {myFunction($arg1, $arg2)}). Užitečné pro výpočty, přístup k pomocným funkcím aplikace nebo generování malých částí obsahu.
  • Vlastní tagy: Pro vytváření zcela nových jazykových konstrukcí ({mytag}...{/mytag} nebo n:mytag). Tagy nabízejí nejvíce možností, umožňují definovat vlastní struktury, řídit parsování šablony a implementovat komplexní vykreslovací logiku.
  • Kompilační průchody: Funkce, které upravují abstraktní syntaktický strom (AST) šablony po parsování, ale před generováním PHP kódu. Používají se pro pokročilé optimalizace, bezpečnostní kontroly (jako je Sandbox) nebo automatické úpravy kódu.
  • Vlastní loadery: Pro změnu způsobu, jakým Latte vyhledává a načítá soubory šablon (např. načítání z databáze, šifrovaného úložiště atd.).

Výběr správné metody rozšíření je klíčový. Než vytvoříte složitý tag, zvažte, zda by nestačil jednodušší filtr nebo funkce. Ukažme si to na příkladu: implementace generátoru Lorem ipsum, který jako argument přijímá počet slov k vygenerování.

  • Jako tag? {lipsum 40} – Možné, ale tagy jsou vhodnější pro řídicí struktury nebo generování složitých značek. Tagy nelze použít přímo ve výrazech.
  • Jako filtr? {=40|lipsum} – Technicky to funguje, ale filtry jsou určeny k transformaci vstupní hodnoty. Zde je 40 argument, nikoli hodnota, která se transformuje. To působí sémanticky nesprávně.
  • Jako funkce? {lipsum(40)} – Toto je nejpřirozenější řešení! Funkce přijímají argumenty a vracejí hodnoty, což je ideální pro použití v libovolném výrazu: {var $text = lipsum(40)}.

Obecné doporučení: Používejte funkce pro výpočty/generování, filtry pro transformaci a tagy pro nové jazykové konstrukce nebo složité značky. Průchody používejte pro manipulaci s AST a loadery pro získávání šablon.

Přímá registrace

Pro pomocné nástroje specifické pro projekt nebo rychlá rozšíření umožňuje Latte přímou registraci filtrů a funkcí do objektu Latte\Engine.

Pro registraci filtru použijte metodu addFilter(). Prvním argumentem vaší filtrační funkce bude hodnota před znakem | a následující argumenty jsou ty, které se předávají za dvojtečkou :.

$latte = new Latte\Engine;

// Definice filtru (volatelný objekt: funkce, statická metoda atd.)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);

// Registrace
$latte->addFilter('truncate', $myTruncate);

// Použití v šabloně: {$text|truncate} nebo {$text|truncate:100}

Můžete také zaregistrovat Filter Loader, funkci, která dynamicky poskytuje volatelné objekty filtrů podle požadovaného názvu:

$latte->addFilterLoader(fn(string $name) => /* vrátí volatelný objekt nebo null */);

Pro registraci funkce použitelné ve výrazech šablony použijte addFunction().

$latte = new Latte\Engine;

// Definice funkce
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;

// Registrace
$latte->addFunction('isWeekend', $isWeekend);

// Použití v šabloně: {if isWeekend($myDate)}Víkend!{/if}

Více informací najdete v části Vytváření vlastních filtrů a Funkcí.

Robustní způsob: Latte Extension

Zatímco přímá registrace je jednoduchá, standardním a doporučeným způsobem, jak zabalit a distribuovat rozšíření Latte, je prostřednictvím tříd Extension. Extension slouží jako centrální konfigurační bod pro registraci více tagů, filtrů, funkcí, kompilačních průchodů a dalších prvků.

Proč používat Extensions?

  • Organizace: Udržuje související rozšíření (tagy, filtry atd. pro konkrétní funkci) pohromadě v jedné třídě.
  • Znovupoužitelnost a sdílení: Snadno zabalíte svá rozšíření pro použití v jiných projektech nebo pro sdílení s komunitou (např. přes Composer).
  • Plná síla: Vlastní tagy a kompilační průchody lze registrovat pouze prostřednictvím Extensions.

Registrace Extension

Extension se registruje v Latte pomocí metody addExtension() (nebo prostřednictvím konfiguračního souboru):

$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);

Pokud zaregistrujete více rozšíření a ta definují stejně pojmenované tagy, filtry nebo funkce, má přednost naposledy přidané rozšíření. To také znamená, že vaše rozšíření mohou přepsat nativní tagy/filtry/funkce.

Kdykoli provedete změnu ve třídě a není vypnuté automatické obnovení, Latte automaticky překompiluje vaše šablony.

Vytvoření Extension

Pro vytvoření vlastního rozšíření potřebujete vytvořit třídu, která dědí z Latte\Extension. Pro představu, jak takové rozšíření vypadá, podívejte se na vestavěné CoreExtension.

Podívejme se na metody, které můžete implementovat:

beforeCompile(Latte\Engine $engine)void

Volá se před kompilací šablony. Metodu lze použít například pro inicializace související s kompilací.

getTags(): array

Volá se při kompilaci šablony. Vrací asociativní pole název tagu ⇒ volatelný objekt, což jsou funkce pro parsování tagů. Více informací.

public function getTags(): array
{
	return [
		'foo' => FooNode::create(...),
		'bar' => BarNode::create(...),
		'n:baz' => NBazNode::create(...),
		// ...
	];
}

Tag n:baz představuje čistý n:atribut, tedy tag, který lze zapsat pouze jako atribut.

U tagů foo a bar Latte automaticky rozpozná, zda jde o párové tagy, a pokud ano, lze je automaticky zapisovat pomocí n:atributů, včetně variant s předponami n:inner-foo a n:tag-foo.

Pořadí vykonávání takových n:atributů je určeno jejich pořadím v poli vráceném metodou getTags(). Takže n:foo je vždy proveden před n:bar, i když jsou atributy v HTML tagu uvedeny v opačném pořadí jako <div n:bar="..." n:foo="...">.

Pokud potřebujete určit pořadí n:atributů napříč více rozšířeními, použijte pomocnou metodu order(), kde parametr before xor after určuje, které tagy jsou řazeny před nebo za tagem.

public function getTags(): array
{
	return [
		'foo' => self::order(FooNode::create(...), before: 'bar'),
		'bar' => self::order(BarNode::create(...), after: ['block', 'snippet']),
	];
}

getPasses(): array

Volá se při kompilaci šablony. Vrací asociativní pole název průchodu ⇒ volatelný objekt, což jsou funkce představující tzv. kompilační průchody, které procházejí a upravují AST.

I zde lze použít pomocnou metodu order(). Hodnota parametrů before nebo after může být * s významem před/po všech.

public function getPasses(): array
{
	return [
		'optimize' => Passes::optimizePass(...),
		'sandbox' => self::order($this->sandboxPass(...), before: '*'),
		// ...
	];
}

beforeRender(Latte\Engine $engine)void

Volá se před každým vykreslením šablony. Metoda může být použita například k inicializaci proměnných používaných během vykreslování.

getFilters(): array

Volá se před vykreslením šablony. Vrací filtry jako asociativní pole název filtru ⇒ volatelný objekt. Více informací.

public function getFilters(): array
{
	return [
		'batch' => $this->batchFilter(...),
		'trim' => $this->trimFilter(...),
		// ...
	];
}

getFunctions(): array

Volá se před vykreslením šablony. Vrací funkce jako asociativní pole název funkce ⇒ volatelný objekt. Více informací.

public function getFunctions(): array
{
	return [
		'clamp' => $this->clampFunction(...),
		'divisibleBy' => $this->divisibleByFunction(...),
		// ...
	];
}

getProviders(): array

Volá se před vykreslením šablony. Vrací pole poskytovatelů, což jsou obvykle objekty, které používají tagy za běhu. Přistupuje se k nim přes $this->global->.... Více informací.

public function getProviders(): array
{
	return [
		'myFoo' => $this->foo,
		'myBar' => $this->bar,
		// ...
	];
}

getCacheKey(Latte\Engine $engine)mixed

Volá se před vykreslením šablony. Návratová hodnota se stává součástí klíče, jehož hash je obsažen v názvu souboru kompilované šablony. Pro různé návratové hodnoty tedy Latte vygeneruje různé cache soubory.