Obsah
Hezčí šablony
Quick start momentálně probíhá bouřlivým vývojem – díl, který si právě prohlížíte, je provizorní a některé části chybí, případně se budou měnit.
V minulém díle jsme vytvořili základní model, s jeho použitím ale musíte vyčkat do dalšího dílu – tato část bude spíše teoretická, ale nebojte, na praktické použití nabraných znalostí – upravíme si šablony, které jsme vytvořili v díle „Vytvoření šablony“, aby byly více sexy a vypíšeme přehled úkolů do tabulky.
Teoretický úvod
Pamatujete si, jak jsme v šablonách používali konstrukce jako
{foreach $flashes as $flash}? Nette nám tento zápis umožňuje
prostřednictvím tzv. filtrů šablon. Jakmile se vykresluje šablona
(neplést s metodami presenteru!), aplikují se na ní všechny zaregistrované
filtry. Šablona se přeloží do čistého php souboru a ten se poté
kešuje – to vám umožní odstínit php od html a v šablonách používat
pouze syntax šablonových filtrů. Asi se ptáte, jak je možné, že jsme
použili zmíněnou konstrukci (která fungovala :-)), bez toho, aniž bychom
jakýkoliv filtr do šablon zaregistrovali. Je to proto, že Nette automaticky
zaregistruje tzv. Latte Filter, což je filtr, s kterým si v 99% případů
vystačíte.
Všem položkám za znakem { po následující mezeru se říká makro.
Pokud jste se nad uvedeným zamysleli, asi Vás napadá, že může nastat problém, pokud bychom chtěli v šabloně uvést CSS styl prostřednictvím tagu style či javascript v tagu script. Tomuto problému se budeme věnovat později.
Filtr Latte Filter je automaticky zaregistrovaný pouze na
šablonách presenterů a vykreslitelných komponent (control)! Pokud jej
přesto chcete používat, musíte si jej zaregistrovat manuálně řádkem
$template->registerFilter(new LatteFilter);.
Latte Filter ale umí daleko více, například dědičnost v šablonách – určitě jste se již dostali do situace, kdy bylo potřeba na nějaké konkrétní stránce přepsat něco, co sama neovlivňuje. Nejlepší bude asi příklad – v podstránce bude potřeba měnit titulek, který je uvedený v layoutu. Jak na to?
Dědičnost, bloky
V Nette lze vyřešit popsanou situaci dvěma způsoby:
Layout:
<title>{block title}{/block} | Todo list</title>
<title>{include title} | TodoList</title>
{block title}Smazání položky 1{/block}
Jaký je rozdíl mezi prvním a druhým stylem zápisu? Pokud bychom v potomkovi layoutu neuvedli blok title a v layoutu měli druhý způsob, Latté filter by vyhodil výjimku oznamující, že nemůže najít blok title. Rozdíl tedy tkví v tom, že prvním zápisem jsme definovali blok title (který poté přepisujeme), zatímco druhým zápisem jsme vložili blok title.
Nette automaticky zařídí, že všechny šablony view dědí
od layoutu. Pokud byste chtěli dědit od jiné šablony, musíte použít makro
{extends ...}.
Pokud přepisujeme blok, můžeme pomocí {include
#parent} vložit původní obsah. Pro rekurzivní vykreslování se hodí
{include #this}; jako parametr můžeme uvést seznam proměnných,
například {incude #parent, val => 2, val2 => 3}.
Proměnné
Do šablon předáme proměnnou z presenteru jednoduše – zápisem
$this->template->datum = new DateTime; (v render metodě) se
v šabloně zpřístupní proměnná $datum, pracovat s ní budeme
později.
Nejpoužívanější makra
Souhrn nezahrnuje makro block, které jsme si již vysvětlili. Nejčastěji se v šablonách používají následující makra:
{link}, {plink}
Generuje odkaz na jiný presenter dle rout v aplikaci. U těchto maker je dobré vědět, že:
- uvedením // na začátku cíle se se generuje absolutní odkaz
- uvedením : na začátku cíle se hledá rootu modulů – lze si to představit jako znak \ u namespace v PHP 5.3
Při použití v komponentě se {link} chová odlišně –
odkazuje v rámci dané komponenty.
{include}, {extends}
Makro include může sloužit dvěma způsoby – pokud je jeho parametr uzavřen v apostrofech, vkládá se soubor, v opačném případě se vloží blok. Makro extends nastavuje nadřazenou šablonu, není třeba ho uvádět, pokud šablona dědí od layoutu.
{if $cond} .. {else} .. {/if}, {foreach $foo as $bar} .. {/foreach}
Aliasy pro php zápis podmínky a iterace.
{snippet jmenosnippetu} .. {/snippet}
K snippetům se dostaneme v části, kde si vystvětlíme, jak integrovat AJAX.
{widget}, {control}
Vykreslování komponent a formulářů, více viz další díl quick startu. Makra se chovají totožně – control je alias pro widget.
Přehled všech maker naleznete v dokumentaci k Latte Filteru.
Nyní trochu odbočíme
Díky Latte Filteru máme možnost zapsat makra dvěma způsoby (následující dva kusy kódu jsou funkčně naprosto identické):
{foreach $flashes as $flash}
<div class="flash {$flash->type}">
{$flash->message}
</div>
{/foreach}
<div n:foreach="$flashes as $flash" class="flash {$flash->type}">
{$flash->message}
</div>
Více o tomto stylu zápisu si můžete přečíst ve vláknu na fóru.
Proměnné & helpery
Proměnnou obecně můžeme vypsat pomocí tohoto zápisu:
{$promenna}
V našem případě jsme si do šablony zkusili vložit proměnnou $datum, tu vypíšeme trochu jinak – formátovaně:
{$datum|date:'d.m.Y'}
Použili jsme tzv. helpery – více si o helperech můžete přečíst v jejich dokumentaci.
Zde přichází na scénu jedna z the most killer features – escapování. Kdykoliv vypíšete proměnnou, je automaticky escapovaná. Žádné XSS tedy nehrozí. Tato oblast Nette je dokonce natolik propracovaná, že escapuje dle kontextu – tedy například v javascriptu se escapuje jinak, než v html.
Pokud si jste naprosto jistí, že chcete zamezit escapování (například při výpisu obsahu článku v html podobě), stačí za znak { doplnit vykřičník (signalizující potenciální nebezpečí).
To mi připomíná, že Vám dlužím vysvětlení, jak zapsat javascript v šabloně:
Vypsání { v šabloně
Jednou z možností je uvést za znakem { mezeru – to způsobí nevyhodnocení konstrukce jako makra, stejně dobře poslouží apostrof (který se ale nedá použít všude). Nebo:
<script type="text/javascript" n:syntax="doubled">
$(function() {
$('.something').css({color:red});
alert({{$promenna}});
});
</script>
Zápis doubled způsobí, že Latte Filter bude jako makro brát oblast mezi {{ a první mezerou.
Praktická část
Nabrané znalosti nyní využijeme v praxi a vypíšeme si seznam všech úkolů do přehledné tabulky. Začneme drobným refaktoringem layoutu, poté si do presenteru přidáme privátní proměnnou obsahující objekt TodoManager, a getter, abychom pokažé nemuseli vytvářet novou instanci TodoManageru. Poslední úkon presenteru bude předání dat šabloně k vykreslení.
Na layoutu vylepšíme pouze konstrukci zabývající se flash zprávami:
<div n:foreach="$flashes as $flash" class="flash {$flash->type}">{$flash->message}</div>
Presenter:
<?php
final class TodolistPresenter extends BasePresenter
{
/** @var TodoManager */
private $todoManager = NULL;
public function actionShow($showDoneTasks = FALSE)
{
$this->template->todos = $this->model->findAllTodos($order = array(
'added' => 'ASC',
), $where = array(
'done' => $showDoneTasks ? 'yes' : 'no',
));
}
public function renderShow($showDoneTasks) {
$this->template->showDone = $showDoneTasks;
}
public function getModel() {
if(!isset($this->todoManager))
$this->todoManager = new TodoManager;
return $this->todoManager;
}
}
V šabloně vykreslíme tabulku úkolů následovně, zároveň vypíšeme odkaz pro přepínání dokončené úkoly < ⇒ nedokončené úkoly:
{block content}
<p>
Zobrazuji {if !$showDone}ne{/if}dokončené úkoly,
<a href="{link this, 'showDoneTasks' => !$showDone}">
přepnout na {if $showDone}ne{/if}dokončené úkoly.
</a>
</p>
<table n:ifset="$todos">
<tr><th>Popis</th><th>Přidáno</th></tr>
<tr n:foreach="$todos as $todo">
<td>{$todo->text}</td><td>{$todo->added|date:'H:i @ d.m.Y'}</td>
</tr>
</table>
Co si zapamatovat?
- co dělají která makra, je jich sice hodně, ale vyplatí se to ;)
- pár nejpoužívanějších helperů, jako date, nl2br
- html-style zápis maker
- jak se chová escapování v Nette
- jak zapsat { uvnitř šablony
TODO: doplnit pár dalších položek do Co si zapamatovat?
Upoutávka
V příštím z naší aplikace uděláme jako mávnutím proutku opravdový todo-list, dále ji budeme už jen vylepšovat (těsit se můžete například na stránkování, AJAX typu „přesunutí položky TODO do koše“ (drag & drop), poznáte, že tvorba aplikací v Nette nemá hranice).




Semik | 12. 3. 2010, 19:01 | question
Jak to vypadá s pokračováním tohoto quick startu ?