Latte tagy (makra)

Přehled a popis všech tagů (neboli značek či maker) šablonovacího systému Latte, které jsou vám standardně k dispozici.

Vypisování
{$var}, {expr} nebo {=expr} vypíše escapovanou proměnnou nebo výraz
{$var|filter} vypíše s použitím filtrů
{_string} vypíše překlad
{l} nebo {r} vypíše znak { nebo }
Podmínky
{if}{elseif}{else}{/if} podmínka if
{ifset}{elseifset}{/ifset} podmínka ifset
{ifchanged}{/ifchanged} test jestli došlo ke změně
{switch} {case} {default} {/switch} podmínka switch
Cykly
{foreach}{/foreach} foreach
{for}{/for} for
{while}{/while} while
{continueIf $cond} pokračovat další iterací
{skipIf $cond} přeskočit iteraci
{breakIf $cond} přerušení cyklu
{first}{/first} jde o první průchod?
{last}{/last} jde o poslední průchod?
{sep}{/sep} bude ještě následovat průchod?
$iterator speciální proměnná uvnitř foreach
Načítání dalších šablon
{include 'file.latte'} načte šablonu z dalšího souboru
{sandbox 'file.latte'} načte šablonu v sandbox režimu
Bloky, layouty, dědičnost šablon
{block} anonymní blok
{block block} definuje blok
{define block} definuje blok pro pozdější použití
{include block} vykreslení bloku
{import 'file.latte'} načte bloky ze šablony
{layout 'file.latte'} / {extends} určuje soubor s layoutem
{embed 'file.latte'} načte šablonu a umožní přepsat bloky
{ifset block}{/ifset} podmínka, zda existuje blok
Řízení výjimek
{try}{else}{/try} zachycení výjimek
{rollback} zahození bloku try
Proměnné
{var $foo = value} vytvoří proměnnou
{default $foo = value} vytvoří proměnnou, pokud neexistuje
{capture $var}{/capture} zachytí blok do proměnné
Typy
{varType type $var} deklaruje typ proměnné
{varPrint [all]} navrhne typy proměnných
{templateType ClassName} deklaruje typy proměnných podle třídy
{templatePrint} navrhne třídu s typy proměnných
Ostatní
{contentType $type} přepne escapování a pošle HTTP hlavičku
{debugbreak $cond} umístí do kódu breakpoint
{do expression} vykoná kód, ale nic nevypíše
{dump $variable} dumpuje proměnné do Tracy Bar
{spaceless}{/spaceless} odstraní nadbytečné mezery
{syntax mode} změna syntaxe za běhu
Pomocníci HTML kodéra
n:class dynamický zápis HTML atributu class
n:attr dynamický zápis jakýchkoliv HTML atributů
n:ifcontent Vynechá prázdný HTML tag
Dostupné pouze v Nette Frameworku
n:href odkaz používaný v HTML elementech <a>
{link Presenter:action} vygeneruje odkaz
{plink Presenter:action} vygeneruje odkaz na presenter
{control loginForm} vykreslí komponentu
{snippet name}{/snippet} výstřižek, který lze odeslat AJAXem
{snippetArea name} obálka pro výstřižky
{cache $key}{/cache} cachuje část šablony
Dostupné pouze s Nette Forms
{form formName}{/form} vykreslí značky formuláře
{label fieldName}{/label} vykreslí popisku formulářového prvku
{input fieldName} vykreslí formulářový prvek
{inputError fieldName} vypíše chybovou hlášku formulářového prvku
n:name oživí formulářový prvek
{formPrint} navrhne Latte kód pro formulář
{formContext formName}{/formContext} částečné kreslení formuláře

Vypisování

{$var} {expr} {=expr}

V Latte se používá značka {=...} pro výpis jakéhokoliv výrazu na výstup. Latte záleží na vašem pohodlí, takže pokud výraz začíná proměnnou nebo voláním funkce, není potřeba rovnítko psát. Což v praxi znamená, že ho není potřeba psát téměř nikdy:

Jméno: {$name} {$surname}<br>
Věk: {date('Y') - $birth}<br>

Jako výraz můžete zapsat cokoliv, co znáte z PHP. Nemusíte se zkrátka učit nový jazyk. Tak třeba:

{='0' . ($num ?? $num * 3) . ', ' . PHP_VERSION}

Prosím, nehledejte v předchozím příkladu žádný smysl, ale kdybyste tam nějaký našli, napište nám :-)

Escapování výstupu

Jaký je nejdůležitější úkol šablonovacího systému? Zamezit bezpečnostním dírám. A přesně tohle dělá Latte vždy, když něco vypisujete. Automaticky to escapuje:

<p>{='one < two'}</p>   {* vypíše: '<p>one &lt; two</p>' *}

Abychom byli přesní, Latte používá kontextově sensitivně escapování, což je tak důležitá a unikátní věc, že jsme tomu věnovali samostatnou kapitolu.

A co když vypisujte obsah kódovaný v HTML z ověřeného zdroje? Pak lze snadno escapování vypnout:

{$trustedHtmlString|noescape}

Filtry

Vypsaný výraz může být upraven filtrem. Takto třeba řetězec převedeme na velká písmena a zkrátíme na maximálně 30 znaků:

{$string|upper|truncate:30}

Filtry můžete používat i na dílčí části výrazu tímto způsobem:

{$left . ($middle|upper) . $right}

{_string}

Pokud používate Nette, odkážeme vás spíš na kapitolu lokalizace.

Značka usnadňuje automatizované překlady v šablonách. Interně k tomu používá filtr s názvem translate, tedy oba tyto zápisy fungují shodně:

{_$variable}
{$variable|translate}

Inicializace filtru se očekává od vás. K dispozici je široká škála knihoven, které řeší překlad řetězců a lze je tímto způsobem propojit s Latte:

$latte->addFilter('translate', function ($original) {
	// tady z $original vytvoříme $translated
	return $translated;
});

Podmínky

{if} {elseif} {else}

Podmínky se chovají stejně, jako jejich protějšky v PHP. Můžete v nich používat i stejné výrazy, jaké znáte z PHP, nemusíte se učit nový jazyk.

{if $product->inStock > Stock::MINIMUM}
	Skladem
{elseif $product->isOnWay()}
	Na cestě
{else}
	Není dostupné
{/if}

Jako každou párovou značku, tak i dvojici {if} ... {/if} lze zapisovat i v podobě n:attributu, například:

<p n:if="$count > 0">Skladem {$count} kusů</p>

Víte, že k n:atributům můžete připojit prefix tag-? Pak se bude podmínka vztahovat jen na vypsání HTML značek a obsah mezi nimi se vypíše vždycky:

<a href="..." n:tag-if="$clickable">Hello</a>

{* vypíše 'Hello' když $clickable je nepravdivá *}
{* vypíše '<a href="...">Hello</a>' když $clickable je pravdivá *}

Boží.

{/if $cond}

Možná vás překvapí, že výraz v podmínce {if} lze uvést také v ukončovací značce. To se hodí v situacích, kdy při otevírání podmínky ještě jeho hodnotu neznáme. Říkejme tomu odložené rozhodnutí.

Například začneme vypisovat tabulku se záznamy z databáze a teprve po dokončení výpisu si uvědomíme, že v databázi žádný záznam nebyl. Tak dáme na to podmínku do koncové značky {/if} a pokud žádný záznam nebude, nic z toho se nevypíše:

{if}
	<h1>Výpis řádků z databáze</h1>

	<table>
	{foreach $resultSet as $row}
		...
	{/foreach}
	</table>
{/if isset($row)}

Šikovné, že?

V odložené podmínce lze použít i {else}, ale nikoliv {elseif}.

{ifset} {elseifset}

Pomocí podmínky {ifset $var} zjistíme, zda proměnná (nebo více proměnných) existuje a má nenullovou hodnotu. Vlastně jde o totéž, jako if (isset($var)) v PHP. Jako každou párovou značku ji lze zapisovat i v podobě n:attributu, tak si to ukažme jako příklad:

<meta name="robots" content="{$robots}" n:ifset="$robots">

Kromě kontrolování existence proměnných se {ifset} používá také k ověření existence bloků.

{ifchanged}

{ifchanged} zkontroluje, zda se hodnota proměnné změnila od poslední iterace ve smyčce (foreach, for nebo while).

Pokud ve značce uvedeme jednu či více proměnných, bude kontrolovat, zda se nějaká z nich změnila, a podle toho vypíše obsah. Například následující příklad vypíše první písmenko jména jako nadpis pokaždé, když se při výpisu jmen změní:

{foreach ($names|sort) as $name}
    {ifchanged $name[0]} <h2>{$name[0]}</h2> {/ifchanged}

	<p>{$name}</p>
{/foreach}

Pokud však neuvedeme žádný argument, bude se kontrolovat vykreslený obsah oproti jeho předchozímu stavu. To znamená, že v předchozím příkladě můžeme klidně argument ve značce vynechat. A samozřejmě také můžeme použít n:attribut:

{foreach ($names|sort) as $name}
    <h2 n:ifchanged>{$name[0]}</h2>

	<p>{$name}</p>
{/foreach}

Uvnitř {ifchanged} lze také uvést klauzuli {else}.

{switch} {case} {default}

Porovnává hodnotu s více možnostmi. Jde o obdobu podmíněnému příklazu switch, který znáte z PHP. Nicméně Latte jej vylepšuje:

  • používá striktní porovnání (===)
  • nepotřebuje break

Je to tedy přesný ekvivalent struktury match se kterou přichází PHP 8.0.

{switch $transport}
	{case train}
		Vlakem
	{case plane}
		Letecky
	{default}
		Jinak
{/switch}

Klauzule {case} může obsahovat více hodnot oddělených čárkami:

{switch $status}
{case $status::NEW}<b>nová položka</b>
{case $status::SOLD, $status::UNKNOWN}<i>není dostupná</i>
{/switch}

Cykly

V Latte najdete všechny cykly, které znáte z PHP: foreach, for a while.

{foreach}

Cyklus zapíšeme úplně stejně jako v PHP:

{foreach $langs as $code => $lang}
	<span>{$lang}</span>
{/foreach}

Navíc má několik šikovných vychytávek, o kterých si nyní povíme.

Latte třeba kontroluje, zda vytvořené proměnné omylem nepřepisují globální proměnné téhož jména. Zachrání to situace, kdy počítáte s tím, že v $lang je aktuální jazyk stránky, a neuvědomíte si, že foreach $langs as $lang vám tu proměnnou přepsalo.

Cyklus foreach lze také velmi elegantně a úsporně zapsat pomocí n:attributu:

<ul>
	<li n:foreach="$items as $item">{$item->name}</li>
</ul>

Víte, že k n:atributům můžete připojit prefix inner-? Pak se bude ve smyčce opakovat pouze vnitřek elementu:

<div n:inner-foreach="$items as $item">
	<h4>{$item->title}</h4>
	<p>{$item->description}</p>
</div>

Takže se vypíše něco jako:

<div>
	<h4>Foo</h4>
	<p>Lorem ipsum.</p>
	<h4>Bar</h4>
	<p>Sit dolor.</p>
</div>

{else}

Uvnitř cyklu foreach může uvést klauzuli {else}, jejíž obsah se zobrazí, pokud je cyklus prázdný:

<ul>
    {foreach $people as $person}
        <li>{$person->name}</li>
    {else}
        <li><em>Litujeme, v tomto seznamu nejsou žádní uživatelé</em></li>
    {/foreach}
</ul>

$iterator

Uvnitř cyklu foreach vytvoří Latte proměnnou $iterator, pomocí které můžeme zjišťovat užitečné informace o probíhajícím cyklu:

  • $iterator->first – prochází se cyklem poprvé?
  • $iterator->last – jde o poslední průchod?
  • $iterator->counter – kolikátý je to průchod počítáno od jedné?
  • $iterator->counter0 – kolikátý je to průchod počítáno od nuly?
  • $iterator->odd – jde o lichý průchod?
  • $iterator->even – jde o sudý průchod?
  • $iterator->parent – iterátor obklopující ten aktuální
{foreach $rows as $row}
	{if $iterator->first}<table>{/if}

	<tr id="row-{$iterator->counter}">
		<td>{$row->name}</td>
		<td>{$row->email}</td>
	</tr>

	{if $iterator->last}</table>{/if}
{/foreach}

Latte je mazané a $iterator->last funguje nejen u polí, ale i když cyklus probíhá nad obecným iterátorem, kde není dopředu znám počet položek.

{first} {last} {sep}

Tyto značky lze používat uvnitř cyklu {foreach}. Obsah {first} se vykreslí, pokud jde o první průchod. Obsah {last} se vykreslí … jestlipak to uhádnete? Ano, pokud jde o poslední průchod. Jde vlastně o zkratky pro {if $iterator->first} a {if $iterator->last}.

{foreach $rows as $row}
	{first}<table>{/first}

	<tr id="row-{$iterator->counter}">
		<td>{$row->name}</td>
		<td>{$row->email}</td>
	</tr>

	{last}</table>{/last}
{/foreach}

Obsah značky {sep} se vykreslí, pokud průchod není poslední, hodí se tedy pro vykreslování oddělovačů, například čárek mezi vypisovanými položkami:

{foreach $items as $item} {$item} {sep}, {/sep} {/foreach}

To je docela praktické, že?

{for}

Cyklus zapisujeme úplně stejně jako v PHP:

{for $i = 0; $i < 10; $i++}
	<span>Položka {$i}</span>
{/for}

{while}

Cyklus opět zapisujeme úplně stejně jako v PHP:

{while $row = $result->fetch()}
	<span>{$row->title}</span>
{/while}

Je možná i varianta s podmínkou v koncové značce, která odpovídá v PHP cyklu do-while:

{while}
	<span>{$item->title}</span>
{/while $item = $item->getNext()}

{continueIf} {skipIf} {breakIf}

Pro řízení jakéhokoliv cyklu lze používat značky {continueIf ?} a {breakIf ?}, které přejdou na další prvek resp. ukončí cyklus při splnění podmínky:

{foreach $rows as $row}
	{continueIf $row->date < $now}
	{breakIf $row->parent === null}
	...
{/foreach}

Značka {skipIf} je velmi podobná jako {continueIf}, ale nezvyšuje počítadlo $iterator->counter, takže pokud jej vypisujeme a zároveň přeskočíme některé položky, nebudou v číslování díry.

A také klauzule {else} se vykreslí, když přeskočíme všechny položky.

<ul>
    {foreach $people as $person}
		{skipIf $person->age < 18}
        <li>{$iterator->counter}. {$person->name}</li>
    {else}
        <li><em>Litujeme, v tomto seznamu nejsou žádní dospělí</em></li>
    {/foreach}
</ul>

Načítání šablon

{include}

Značka {include} říká Latte, aby vypsalo uvedenou šablonu. Pokud bychom se bavili v řeči našeho oblíbeného jazyka PHP, je to něco jako:

<?php include('file.php'); ?>

Kromě vkládání souborů se značka {include} používá také k vkládání bloků.

Vložené šablony nemají přístup k proměnným aktivního kontextu, mají přístup jen ke globálním proměnným.

Další proměnné můžete předávat tímto způsobem:

{* od Latte 2.9 *}
{include 'template.latte', foo: 'bar', id: 123}

{* před Latte 2.9 *}
{include 'template.latte', foo => 'bar', id => 123}

Název šablony může být jakákoliv výraz v PHP:

{include $someVar}
{include $ajax ? 'ajax.latte' : 'not-ajax.latte'}

Vložený obsah lze upravit pomocí filtrů. Následující příklad odebere všechno HTML a upraví velikost písmen:

<title>{include 'heading.latte' |stripHtml|capitalize}</title>

Defaultně dědičnost šablon v tomto případě nijak nefiguruje. I když v inkludované šabloně můžeme používat bloky, nedojde k nahrazení odpovídajících bloků v šabloně, do které se inkluduje. Přemýšlejte o inkludovaných šabloných jako samostatných odstíněných částech stránek nebo modulů. Toto chování se dá změnit pomocí modifikátoru with blocks (od Latte 2.9.1):

{include 'template.latte' with blocks}

Vztah mezi názvem souboru uvedeným ve značce a souborem na disku je věcí loaderu.

{sandbox}

Při vkládání šablony vytvořené koncovým uživatelem byste měli zvážit sandbox režim (více informací v dokumentaci sandboxu).

Sandboxovanou obdobou {include} je:

{sandbox 'untrusted.latte', level: 3, data: $menu}

{block}

Pojmenované bloky jsou základní stavební jednotkou dědičnosti a znovupoužitelnost šablon. Avšak bloky bez jména slouží jako způsob jak aplikovat filtry na část šablony. Například takto lze aplikovat filtr strip, který odstraní zbytečné mezery:

{block|strip}
<ul>
	<li>Hello World</li>
</ul>
{/block}

Řízení výjimek

{try}

Díky této značce je extrémně snadné vytvářet robustní šablony.

Pokud při vykreslování bloku {try} dojde k výjimce, celý blok se zahodí a vykreslování bude pokračovat až po něm:

{try}
	<ul>
		{foreach $twitter->loadTweets() as $tweet}
  			<li>{$tweet->text}</li>
		{/foreach}
	</ul>
{/try}

Obsah ve volitelné klauzuli {else} se vykreslí jen když nastane výjimka:

{try}
	<ul>
		{foreach $twitter->loadTweets() as $tweet}
  			<li>{$tweet->text}</li>
		{/foreach}
	</ul>
	{else}
	<p>Je nám líto, nepodařilo se načíst tweety.</p>
{/try}

Je také možné definovat vlastní obslužný handler pro výjimky, například kvůli logování.

{rollback}

Blok {try} lze zastavit a přeskočit také ručně pomocí {rollback}. Díky tomu nemusíte předem kontrolovat všechna vstupní data a až během vykreslování se můžete rozhodnout, že objekt nechcete vůbec vykreslit:

{try}
<ul>
    {foreach $people as $person}
 		{skipIf $person->age < 18}
       <li>{$person->name}</li>
    {else}
		{rollback}
    {/foreach}
</ul>
{/try}

Proměnné

{var} {default}

Nové proměnné vytvoříme v šabloně značkou {var}:

{var $name = 'John Smith'}
{var $age = 27}

{* Vícenásobná deklarace *}
{var $name = 'John Smith', $age = 27}

Značka {default} funguje podobně s tím rozdílem, že vytváří proměnné jen tehdy, pokud neexistují:

{default $lang = 'cs'}

Od Latte 2.7 můžete uvádět i typy proměnných.

{var string $name = $article->getTitle()}

{capture}

Zachytí výstup do proměnné:

{capture $var}
<ul>
	<li>Hello World</li>
</ul>
{/capture}

<p>Captured: {$var}</p>

Ostatní

{contentType}

Značkou určíte, jaký typ obsahu šablona představuje. Možnosti jsou:

  • html (výchozí typ)
  • xhtml
  • xml
  • javascript
  • css
  • calendar (iCal)
  • text

Její použití je důležité, protože nastaví kontextově sensitivní escapování a jen tak může escapovat správně. Například {contentType xml} přepne do režimu XML, {contentType text} escapování zcela vypne.

Pokud je parametrem plnohodnotný MIME type, jako například application/xml, tak ještě navíc odešle HTTP hlavičku Content-Type do prohlížeče:

{contentType application/xml}
<?xml version="1.0"?>
<rss version="2.0">
	<channel>
		<title>RSS feed</title>
		<item>
			...
		</item>
	</channel>
</rss>

{debugbreak}

Označuje místo, kde dojde k pozastavení běhu programu a spuštění debuggeru, aby mohl programátor provést inspekci běhového prostředí a zjistit, zda program funguje podle očekávání. Podporuje Xdebug. Lze doplnit podmínku, která určuje, kdy má být program pozastaven.

{debugbreak}                {* pozastaví program *}

{debugbreak $counter == 1}  {* pozastaví program při splnění podmínky *}

{do}

Vykoná kód a nic nevypisuje.

{do $num++}

V Latte 2.7 a starších se používalo {php}.

{dump}

Vypíše proměnnou nebo aktuální kontext. Vyžaduje Tracy.

{dump $name} {* Vypíše proměnnou $name *}

{dump}       {* Vypíše všechny aktuálně definované proměnné *}

{spaceless}

Odstraní zbytečné bílé místo z výstupu. Funguje podobně jako filtr strip.

{spaceless}
	<ul>
		<li>Hello</li>
	</ul>
{/spaceless}

Vygeneruje

<ul> <li>Hello</li> </ul>

{syntax}

Latte značky nemusejí být ohraničeny pouze do jednoduchých složených závorek. Můžeme si zvolit i jiný oddělovač a to dokonce za běhu. Slouží k tomu {syntax …}, kde jako parametr lze uvést:

  • latte: {...}
  • double: {{...}}
  • off: zcela vypne zpracování Latte značek

S využitím n:atributů lze vypnout Latte třeba jen jednomu bloku JavaScriptu:

<script n:syntax="off">
	var obj = {var: 123}; // tohle už není tag
</script>

Latte lze velmi pohodlně používat i uvnitř JavaScriptu, jen se stačí vynout konstrukcím jako v tomto příkladě, kdy následuje písmeno hned za {. Buď tak, že mezi ně vložíme mezeru či odřádkování ({ var: 123}) nebo použitím uvozovek kolem klíče ({'var': 123}).

Pokud Latte vypnete pomocí {syntax off} (tj. značkou, nikoliv n:atributem), bude důsledně ignorovat všechny značky až do {/syntax}

Pomocníci HTML kodéra

n:class

Díky n:class velice snadno vygenerujete HTML atribut class přesně podle představ.

Příklad: potřebuji, aby aktivní prvek měl třídu active:

{foreach $items as $item}
	<a n:class="$item->isActive() ? active">...</a>
{/foreach}

A dále, aby první prvek měl třídu first:

{foreach $items as $item}
	<a n:class="$item->isActive() ? active, $iterator->first ? first">...</a>
{/foreach}

A všechny prvky mají mít třídu main-item:

{foreach $items as $item}
	<a n:class="$item->isActive() ? active, $iterator->first ? first, main-item">...</a>
{/foreach}

Úžasně jednoduché, že?

n:attr

Atribut n:attr umí se stejnou elegancí jako má n:class generovat libovolné HTML atributy.

{foreach $data as $item}
	<input type="checkbox" n:attr="value: $item->getValue(), checked: $item->isActive()">
{/foreach}

V závislosti na vrácených hodnotách vypíše např.:

<input type="checkbox">

<input type="checkbox" value="Hello">

<input type="checkbox" value="Hello" checked>

n:ifcontent

Předchází tomu, aby se vypsal prázdný HTML element, tj. element neobsahující nic než mezery.

<div>
	<div class="error" n:ifcontent>{$error}</div>
</div>

Vypíše v závislosti na hodnotě proměnné $error:

{* $error = '' *}
<div>
</div>

{* $error = 'Required' *}
<div>
	<div class="error">Required</div>
</div>
Vylepšit tuto stránku