Dědičnost a znovupoužitelnost šablon
Mechanismy dědičnosti a znovupoužitelnosti šablon v Latte významně zvyšují produktivitu vývojářů. Každá šablona tak může obsahovat pouze svůj jedinečný obsah, zatímco opakující se prvky a struktury se efektivně znovupoužívají. V této kapitole představíme tři klíčové koncepty: layoutovou dědičnost, horizontální znovupoužití a jednotkovou dědičnost.
Koncept dědičnosti šablon v Latte je analogický k dědičnosti tříd v PHP. Definujete nadřazenou šablonu, od které mohou další podřízené šablony dědit a případně přepisovat její části. Tento přístup je zvláště účinný, když různé prvky sdílejí společnou strukturu. Ačkoli to může znít složitě, v praxi jde o velmi intuitivní a snadno použitelný systém.
Layoutová dědičnost {layout}
Podívejme se na layoutovou dědičnost na konkrétním příkladu. Následující ukázka představuje nadřazenou šablonu,
kterou můžeme nazvat například layout.latte
. Tato šablona definuje základní kostru HTML dokumentu:
Značky {block}
zde vymezují tři bloky, které mohou podřízené šablony naplnit vlastním obsahem. Blok
v tomto kontextu jednoduše označuje místo, které může podřízená šablona přepsat definováním vlastního bloku se
stejným názvem.
Podřízená šablona pak může vypadat například takto:
Klíčovým prvkem je zde značka {layout}
. Ta Latte sděluje, že tato šablona „rozšiřuje“ jinou šablonu.
Při vykreslování této šablony Latte nejprve nalezne nadřazenou šablonu – v tomto případě
layout.latte
.
V tomto okamžiku Latte identifikuje tři blokové značky v layout.latte
a nahradí tyto bloky obsahem
z podřízené šablony. Vzhledem k tomu, že podřízená šablona nedefinovala blok footer, použije se pro tento blok
obsah z nadřazené šablony. Obsah uvnitř značky {block}
v nadřazené šabloně vždy slouží jako výchozí,
pokud není přepsán.
Výsledný výstup může vypadat následovně:
V podřízené šabloně mohou být bloky umístěny pouze na nejvyšší úrovni nebo uvnitř jiného bloku, tj.:
Je důležité si uvědomit, že blok bude vždy vytvořen bez ohledu na to, zda je okolní {if}
podmínka
vyhodnocena jako pravdivá nebo nepravdivá. Takže i když to tak na první pohled nevypadá, následující šablona blok
skutečně definuje:
Pokud chcete, aby se obsah uvnitř bloku zobrazoval podmíněně, použijte místo toho následující přístup:
Prostor mimo bloky v podřízené šabloně se zpracovává před vykreslením šablony layoutu. Můžete jej tedy využít
k definování proměnných pomocí {var $foo = bar}
a k šíření dat do celého řetězce dědičnosti:
Víceúrovňová dědičnost
Latte umožňuje použít tolik úrovní dědičnosti, kolik potřebujete. Běžný způsob využití layoutové dědičnosti je následující tříúrovňový přístup:
- Vytvořte šablonu
layout.latte
, která obsahuje hlavní kostru vzhledu webu. - Vytvořte šablonu
layout-SECTIONNAME.latte
pro každou sekci vašeho webu. Napříkladlayout-news.latte
,layout-blog.latte
atd. Všechny tyto šablony rozšiřujílayout.latte
a zahrnují styly a design specifické pro jednotlivé sekce. - Vytvořte individuální šablony pro každý typ stránky, například novinový článek nebo položku blogu. Tyto šablony rozšiřují příslušnou šablonu sekce.
Dynamická dědičnost
Jako název nadřazené šablony lze použít proměnnou nebo jakýkoli výraz PHP, což umožňuje dynamické chování dědičnosti:
Latte API také nabízí možnost automatického výběru šablony layoutu.
Tipy pro práci s layoutovou dědičností
Zde je několik užitečných tipů pro efektivní práci s layoutovou dědičností:
- Pokud v šabloně použijete
{layout}
, musí to být první značka šablony. - Layout lze dohledávat automaticky (např. v presenterech). V takovém případě, pokud šablona
nemá mít layout, oznámí to značkou
{layout none}
. - Značka
{layout}
má alias{extends}
. - Název souboru layoutu závisí na použitém loaderu.
- Můžete definovat libovolný počet bloků. Pamatujte, že podřízené šablony nemusí definovat všechny nadřazené bloky, takže můžete nastavit vhodné výchozí hodnoty v několika blocích a později definovat pouze ty, které potřebujete upravit.
Bloky {block}
Viz také anonymní {block}
Blok představuje způsob, jak změnit způsob vykreslování určité části šablony, aniž by to ovlivnilo logiku kolem něj. Následující příklad ilustruje, jak blok funguje a také jeho omezení:
Při vykreslení této šablony bude výsledek identický s verzí bez značek {block}
i s nimi. Bloky mají
přístup k proměnným z vnějších oborů. Jejich hlavním účelem je poskytnout možnost přepsání obsahu v podřízené
šabloně:
Nyní při vykreslování podřízené šablony bude smyčka používat blok definovaný v child.Latte
místo
bloku v parent.Latte
. Výsledná šablona je ekvivalentní následujícímu kódu:
Je důležité si uvědomit, že pokud vytvoříte novou proměnnou uvnitř pojmenovaného bloku nebo změníte hodnotu existující proměnné, tato změna bude viditelná pouze uvnitř daného bloku:
Obsah bloku lze upravit pomocí filtrů. Následující příklad odstraní všechny HTML značky a změní velikost písmen:
Značku lze také zapsat jako n:attribut:
Lokální bloky
Každý blok standardně přepisuje obsah nadřazeného bloku se stejným názvem – s výjimkou lokálních bloků. Ty fungují podobně jako privátní metody ve třídách. Díky nim můžete vytvářet šablonu bez obav, že by kvůli shodě jmen bloků došlo k nechtěnému přepsání z jiné šablony.
Vykreslení bloků {include}
Viz také {include file}
Pro vypsání bloku na určitém místě použijte značku {include blockname}
:
Můžete také vypsat blok z jiné šablony:
Vykreslovaný blok nemá přístup k proměnným aktivního kontextu, s výjimkou případů, kdy je blok definován ve stejném souboru, kde je i vložen. Má však přístup ke globálním proměnným.
Proměnné můžete do bloku předávat tímto způsobem:
Jako název bloku lze použít proměnnou nebo jakýkoli výraz v PHP. V takovém případě před proměnnou doplníme
klíčové slovo block
, aby Latte vědělo, že jde o blok, a nikoli o vkládání
šablony, jejíž název by také mohl být v proměnné:
Blok lze vykreslit i uvnitř sebe samého, což je užitečné například při vykreslování stromové struktury:
Místo {include menu, ...}
můžeme také napsat {include this, ...}
, kde this
odkazuje
na aktuální blok.
Vykreslovaný blok lze upravit pomocí filtrů. Následující příklad odstraní všechny HTML značky a změní velikost písmen:
Rodičovský blok
Pokud potřebujete vypsat obsah bloku z nadřazené šablony, použijte {include parent}
. To je užitečné,
pokud chcete pouze doplnit obsah nadřazeného bloku místo jeho úplného přepsání.
Definice {define}
Kromě bloků existují v Latte také „definice". V běžných programovacích jazycích by se daly přirovnat k funkcím. Jsou užitečné pro opakované použití fragmentů šablony, čímž se vyhnete duplikaci kódu.
Latte se snaží zjednodušovat věci, takže v zásadě jsou definice stejné jako bloky a vše, co platí pro bloky, platí také pro definice. Liší se od bloků v následujících aspektech:
- jsou uzavřeny ve značkách
{define}
- vykreslí se teprve, až když je vložíte přes
{include}
- lze jim definovat parametry podobně jako funkcím v PHP
Představte si, že máte pomocnou šablonu s kolekcí definic pro vykreslování HTML formulářů:
Argumenty jsou vždy volitelné s výchozí hodnotou null
, pokud není uvedena explicitní výchozí hodnota (zde
'text'
je výchozí hodnota pro $type
). Můžete také deklarovat typy parametrů:
{define input, string $name, ...}
.
Šablonu s definicemi načteme pomocí {import}
. Samotné definice
se vykreslují stejným způsobem jako bloky:
Definice nemají přístup k proměnným aktivního kontextu, ale mají přístup ke globálním proměnným.
Dynamické názvy bloků
Latte nabízí velkou flexibilitu při definování bloků, protože název bloku může být jakýkoli výraz PHP. Tento
příklad definuje tři bloky s názvy hi-Peter
, hi-John
a hi-Mary
:
V podřízené šabloně pak můžeme předefinovat například jen jeden blok:
Výstup bude vypadat takto:
Kontrola existence bloků {ifset}
Viz také {ifset $var}
Pomocí testu {ifset blockname}
můžete zkontrolovat, zda v aktuálním kontextu existuje blok (nebo více
bloků):
Jako název bloku lze použít proměnnou nebo jakýkoli výraz v PHP. V takovém případě před proměnnou doplníme
klíčové slovo block
, aby bylo jasné, že nejde o test existence proměnných:
Existenci bloků ověřuje také funkce hasBlock()
:
Tipy pro práci s bloky
Několik užitečných tipů pro efektivní práci s bloky:
- Poslední blok nejvyšší úrovně nemusí mít uzavírací značku (blok končí koncem dokumentu). To zjednodušuje psaní podřízených šablon, které obsahují jeden primární blok.
- Pro lepší čitelnost můžete název bloku uvést ve značce
{/block}
, například{/block footer}
. Název se však musí shodovat s názvem bloku. Ve větších šablonách vám tato technika pomůže snadno identifikovat, které bloky se uzavírají. - Ve stejné šabloně nemůžete přímo definovat více značek bloků se stejným názvem. Toho však lze dosáhnout pomocí dynamických názvů bloků.
- Můžete použít n:atributy k definování bloků,
například:
<h1 n:block=title>Vítejte na mé úžasné domovské stránce</h1>
- Bloky lze také použít bez názvů pouze k aplikaci filtrů:
{block|strip} hello {/block}
Horizontální znovupoužití {import}
Horizontální znovupoužití je v Latte třetím mechanismem pro opětovné použití a dědičnost. Umožňuje načítat
bloky z jiných šablon. Je to podobné, jako když si v PHP vytvoříme soubor s pomocnými funkcemi, který potom načítáme
pomocí require
.
I když je layoutová dědičnost šablony jednou z nejsilnějších funkcí Latte, je omezena na jednoduchou dědičnost – šablona může rozšířit pouze jednu další šablonu. Horizontální znovupoužití je způsob, jak dosáhnout vícenásobné dědičnosti.
Mějme soubor s definicemi bloků:
Pomocí příkazu {import}
naimportujeme všechny bloky a definice definované v
blocks.latte
do jiné šablony:
Pokud bloky importujete v nadřazené šabloně (tj. použijete {import}
v layout.latte
), budou
bloky k dispozici i ve všech podřízených šablonách, což je velmi praktické.
Šablona, která je určena k importování (např. blocks.latte
), nesmí rozšiřovat další šablonu, tj. používat {layout}
. Může však importovat
další šablony.
Značka {import}
by měla být první značkou šablony po {layout}
. Název šablony může být
jakýkoli výraz PHP:
V šabloně můžete použít tolik {import}
příkazů, kolik potřebujete. Pokud dvě importované šablony
definují stejný blok, má přednost první z nich. Nejvyšší prioritu má ale hlavní šablona, která může přepsat
jakýkoli importovaný blok.
Obsah přepsaných bloků se dá zachovat tak, že blok vložíme stejně, jako se vkládá rodičovský blok:
V tomto příkladu {include parent}
zavolá blok sidebar
ze šablony blocks.latte
.
Jednotková dědičnost {embed}
Jednotková dědičnost rozšiřuje koncept layoutové dědičnosti na úroveň fragmentů obsahu. Zatímco layoutová dědičnost pracuje s „kostrou dokumentu“, kterou oživují podřízené šablony, jednotková dědičnost vám umožňuje vytvářet znovupoužitelné kostry pro menší jednotky obsahu a používat je kdekoli potřebujete.
Klíčovým prvkem jednotkové dědičnosti je značka {embed}
. Ta kombinuje funkčnost {include}
a
{layout}
. Umožňuje vložit obsah jiné šablony či bloku a volitelně předat proměnné, stejně jako
v případě {include}
. Zároveň umožňuje přepsat libovolný blok definovaný uvnitř vložené šablony,
podobně jako při použití {layout}
.
Podívejme se na příklad s prvkem akordeon. Nejprve definujeme kostru prvku v šabloně collapsible.latte
:
Značky {block}
definují dva bloky, které mohou podřízené šablony naplnit. Fungují stejně jako
v případě nadřazené šablony v layoutové dědičnosti. Všimněte si také proměnné $modifierClass
.
Nyní použijeme náš prvek v šabloně. Zde přichází ke slovu {embed}
. Tato výkonná značka nám
umožňuje provést několik věcí najednou: vložit obsah šablony prvku, přidat do něj proměnné a definovat bloky
s vlastním HTML:
Výstup může vypadat takto:
Bloky uvnitř vložených značek tvoří samostatnou vrstvu nezávislou na ostatních blocích. Proto mohou mít stejný
název jako blok mimo vložení a nejsou jím nijak ovlivněny. Pomocí značky include
uvnitř značek {embed}
můžete vložit bloky zde vytvořené, bloky z vložené šablony (které nejsou lokální) a také bloky z hlavní šablony, které naopak jsou lokální. Můžete také importovat bloky z jiných souborů:
Vložené šablony nemají přístup k proměnným aktivního kontextu, ale mají přístup ke globálním proměnným.
Pomocí {embed}
lze vkládat nejen šablony, ale i jiné bloky. Předchozí příklad by se dal zapsat tímto
způsobem:
Pokud do {embed}
předáme výraz a není zřejmé, jestli jde o název bloku nebo souboru, doplníme klíčové
slovo block
nebo file
:
Případy použití
V Latte existují různé typy dědičnosti a opětovného použití kódu. Pojďme si shrnout hlavní koncepty pro lepší pochopení:
{include template}
Případ použití: Použití header.latte
a footer.latte
uvnitř
layout.latte
.
header.latte
footer.latte
layout.latte
{layout}
Případ použití: Rozšíření layout.latte
uvnitř homepage.latte
a
about.latte
.
layout.latte
homepage.latte
about.latte
{import}
Případ použití: Použití sidebar.latte
v single.product.latte
a
single.service.latte
.
sidebar.latte
single.product.latte
single.service.latte
{define}
Případ použití: Funkce, kterým předáme proměnné a něco vykreslí.
form.latte
profile.service.latte
{embed}
Případ použití: Vložení pagination.latte
do product.table.latte
a
service.table.latte
.
pagination.latte
product.table.latte
service.table.latte
Tyto příklady ilustrují, jak různé mechanismy dědičnosti a znovupoužitelnosti v Latte spolupracují, aby umožnily vytváření flexibilních, modulárních a snadno udržovatelných šablon. Každý z těchto přístupů má své specifické použití:
{include template}
je užitečný pro vkládání menších, opakujících se částí stránek, jako jsou hlavičky a patičky.{layout}
umožňuje vytvářet konzistentní strukturu napříč různými stránkami webu, přičemž jednotlivé stránky mohou upravovat specifické části.{import}
je skvělý pro sdílení bloků kódu mezi různými šablonami, což podporuje princip DRY (Don't Repeat Yourself).{define}
je ideální pro vytváření znovupoužitelných komponent, které přijímají parametry, jako jsou formulářové prvky.{embed}
kombinuje flexibilitu vkládání s možností přepisovat části vloženého obsahu, což je užitečné pro komplexnější komponenty jako je stránkování.
Použitím těchto technik můžete vytvářet vysoce modulární, flexibilní a snadno udržovatelné šablony pro vaše webové aplikace. Latte tak nabízí pokročilé možnosti pro strukturování šablon, které uspokojí potřeby i těch nejnáročnějších projektů.