Nette Documentation Preview

syntax
Sablon öröklődés és újrafelhasználhatóság
*****************************************

.[perex]
A sablonok újrafelhasználhatósága és az öröklési mechanizmusok azért vannak itt, hogy növeljék a termelékenységet, mivel minden sablon csak az egyedi tartalmát tartalmazza, és az ismétlődő elemek és struktúrák újrafelhasználásra kerülnek. Három fogalmat mutatunk be: az [elrendezés öröklést |#layout inheritance], a [horizontális újrafelhasználást |#horizontal reuse] és az [egység öröklést |#unit inheritance].

A Latte sablon öröklés koncepciója hasonló a PHP osztály örökléshez. Meghatározunk egy **szülő sablont**, amelyből más **gyermeksablonok** kiterjeszthetők, és felülírhatják a szülő sablon egyes részeit. Nagyszerűen működik, ha az elemek közös szerkezetűek. Bonyolultnak hangzik? Ne aggódjon, nem az.


Layout öröklődés `{layout}` .{toc: Layout Inheritance}
======================================================

Nézzük meg az elrendezési sablon öröklődését egy példával kezdve. Ez egy szülő sablon, amelyet például `layout.latte` -nak fogunk hívni, és egy HTML vázdokumentumot definiál.

```latte
<!doctype html>
<html lang="en">
<head>
	<title>{block title}{/block}</title>
	<link rel="stylesheet" href="style.css">
</head>
<body>
	<div id="content">
		{block content}{/block}
	</div>
	<div id="footer">
		{block footer}&copy; Copyright 2008{/block}
	</div>
</body>
</html>
```

A `{block}` címkék három blokkot határoznak meg, amelyeket a gyermek sablonok kitölthetnek. A blokkcímke csak annyit tesz, hogy közli a sablonmotorral, hogy a gyermek sablonok felülbírálhatják a sablon ezen részeit a saját, azonos nevű blokkjuk meghatározásával.

Egy gyermek sablon így nézhet ki:

```latte
{layout 'layout.latte'}

{block title}My amazing blog{/block}

{block content}
	<p>Welcome to my awesome homepage.</p>
{/block}
```

A `{layout}` címke itt a kulcs. Azt mondja a sablonmotornak, hogy ez a sablon egy másik sablont "bővít". Amikor a Latte rendereli ezt a sablont, először megkeresi a szülő sablont - ebben az esetben a `layout.latte`.

Ekkor a sablonmotor észreveszi a `layout.latte` három blokkcímkét, és ezeket a blokkokat a gyermek sablon tartalmával helyettesíti. Vegye figyelembe, hogy mivel a gyermek sablon nem definiálta a *footer* blokkot, helyette a szülő sablon tartalmát használja. A szülő sablon `{block}` címkén belüli tartalom mindig tartalékként kerül felhasználásra.

A kimenet így nézhet ki:

```latte
<!doctype html>
<html lang="en">
<head>
	<title>My amazing blog</title>
	<link rel="stylesheet" href="style.css">
</head>
<body>
	<div id="content">
		<p>Welcome to my awesome homepage.</p>
	</div>
	<div id="footer">
		&copy; Copyright 2008
	</div>
</body>
</html>
```

A gyermek sablonban a blokkok csak vagy a legfelső szinten, vagy egy másik blokkon belül helyezkedhetnek el, azaz:

```latte
{block content}
	<h1>{block title}Welcome to my awesome homepage{/block}</h1>
{/block}
```

A blokk mindig létrejön, függetlenül attól, hogy a környező `{if}` feltétel igaznak vagy hamisnak értékelődik-e ki. Ellentétben azzal, amit gondolhat, ez a sablon valóban definiál egy blokkot.

```latte
{if false}
	{block head}
		<meta name="robots" content="noindex, follow">
	{/block}
{/if}
```

Ha azt szeretné, hogy a blokkban lévő kimenet feltételesen jelenjen meg, használja helyette a következőt:

```latte
{block head}
	{if $condition}
		<meta name="robots" content="noindex, follow">
	{/if}
{/block}
```

A gyermek sablonban lévő blokkokon kívüli adatok a layout sablon megjelenítése előtt kerülnek végrehajtásra, így használhatja a `{var $foo = bar}` típusú változók definiálására és az adatok továbbítására az egész öröklési láncban:

```latte
{layout 'layout.latte'}
{var $robots = noindex}

...
```


Többszintű öröklés .[#toc-multilevel-inheritance]
-------------------------------------------------
Annyi szintű öröklést használhat, amennyire csak szüksége van. Az elrendezés öröklésének egyik gyakori módja a következő háromszintű megközelítés:

1) Hozzon létre egy `layout.latte` sablont, amely tartalmazza a webhely fő megjelenését.
2) Hozzon létre egy `layout-SECTIONNAME.latte` sablont a webhely minden egyes szakaszához. Például: `layout-news.latte`, `layout-blog.latte` stb. Ezek a sablonok mind a `layout.latte` bővítik, és tartalmazzák a szekció-specifikus stílusokat/designt.
3) Hozzon létre egyedi sablonokat minden egyes oldaltípushoz, például egy hírcikkhez vagy blogbejegyzéshez. Ezek a sablonok kiterjesztik a megfelelő szakaszsablont.


Dinamikus elrendezés öröklődése .[#toc-dynamic-layout-inheritance]
------------------------------------------------------------------
A szülő sablon neveként egy változót vagy bármilyen PHP-kifejezést használhat, így az öröklés dinamikusan viselkedhet:

```latte
{layout $standalone ? 'minimum.latte' : 'layout.latte'}
```

A Latte API-t használhatja az elrendezési sablon [automatikus |develop#automatic-layout-lookup] kiválasztására is.


Tippek .[#toc-tips]
-------------------
Íme néhány tipp az elrendezés örökléssel való munkához:

- Ha a `{layout}` címet használja egy sablonban, akkor annak a sablonban az első sabloncímkének kell lennie.

- Az elrendezés [automatikusan kereshető |develop#automatic-layout-lookup] (mint [az előadókban |application:templates#Template Lookup]). Ebben az esetben, ha a sablonban nem kell elrendezés, akkor ezt a `{layout none}` címkével jelzi.

- A `{layout}` címkének a `{extends}` aliasával rendelkezik.

- A kiterjesztett sablon fájlneve a [sablon betöltőjétől |extending-latte#Loaders] függ.

- Annyi blokkja lehet, amennyit csak akar. Ne feledje, hogy a gyermek sablonoknak nem kell minden szülői blokkot definiálniuk, így számos blokkban kitölthet ésszerű alapértelmezéseket, és csak azokat definiálhatja, amelyekre később szüksége van.


Blokkok `{block}` .{toc: Blocks}
================================

.[note]
Lásd még anonim [`{block}` |tags#block]

A blokk lehetőséget biztosít arra, hogy megváltoztassuk a sablon egy bizonyos részének megjelenítési módját, de semmilyen módon nem avatkozik bele a körülötte lévő logikába. A következő példával szemléltetjük, hogyan működik egy blokk, és ami még fontosabb, hogyan nem működik:

```latte .{file: parent.latte}
{foreach $posts as $post}
{block post}
	<h1>{$post->title}</h1>
	<p>{$post->body}</p>
{/block}
{/foreach}
```

Ha ezt a sablont rendereli, az eredmény pontosan ugyanaz lenne a blokkcímkékkel vagy azok nélkül. A blokkok hozzáférnek a külső hatókörök változóihoz. Ez csak egy módja annak, hogy egy gyermek sablon által felülbírálhatóvá tegye:

```latte .{file: child.latte}
{layout 'parent.Latte'}

{block post}
	<article>
		<header>{$post->title}</header>
		<section>{$post->text}</section>
	</article>
{/block}
```

Most a gyermek sablon megjelenítésekor a ciklus a `child.Latte` gyermek sablonban definiált blokkot fogja használni a `parent.Latte` alapsablonban definiált helyett ; a végrehajtott sablon ekvivalens a következővel:

```latte
{foreach $posts as $post}
	<article>
		<header>{$post->title}</header>
		<section>{$post->text}</section>
	</article>
{/foreach}
```

Ha azonban egy új változót hozunk létre egy megnevezett blokkban, vagy kicseréljük egy meglévő változó értékét, a változás csak a blokkban lesz látható:

```latte
{var $foo = 'foo'}
{block post}
	{do $foo = 'new value'}
	{var $bar = 'bar'}
{/block}

foo: {$foo}                  // prints: foo
bar: {$bar ?? 'not defined'} // prints: not defined
```

A blokk tartalma [szűrőkkel |syntax#filters] módosítható. A következő példa eltávolít minden HTML-t és címszavakat:

```latte
<title>{block title|stripHtml|capitalize}...{/block}</title>
```

A címke [n:attribútumként |syntax#n:attributes] is leírható:

```latte
<article n:block=post>
	...
</article>
```


Helyi blokkok .[#toc-local-blocks]
----------------------------------

Minden blokk felülírja az azonos nevű szülői blokk tartalmát. Kivéve a helyi blokkokat. Ezek olyanok, mint az osztály privát metódusai. Létrehozhatsz egy sablont anélkül, hogy aggódnod kellene, hogy - a blokknevek egybeesése miatt - a második sablon felülírja őket.

```latte
{block local helper}
	...
{/block}
```


Blokkok nyomtatása `{include}` .{toc: Printing Blocks}
------------------------------------------------------

.[note]
Lásd még [`{include file}` |tags#include]

Ha egy blokkot egy adott helyre szeretne kinyomtatni, használja a `{include blockname}` címkét:

```latte
<title>{block title}{/block}</title>

<h1>{include title}</h1>
```

A blokkot egy másik sablonból is megjelenítheti:

```latte
{include footer from 'main.latte'}
```

A nyomtatott blokk nem fér hozzá az aktív kontextus változóihoz, kivéve, ha a blokk ugyanabban a fájlban van definiálva, ahol szerepel. A globális változókhoz azonban hozzáférnek.

A változókat a következő módon adhatja át a blokknak:

```latte
{include footer, foo: bar, id: 123}
```

A blokk neveként használhat egy változót vagy bármilyen PHP-kifejezést. Ebben az esetben a változó elé írja a `block` kulcsszót, hogy már fordításkor tudható legyen, hogy egy blokkról van szó, és ne egy [insert template-ről |tags#include], amelynek a neve szintén szerepelhetne a változóban:

```latte
{var $name = footer}
{include block $name}
```

A blokk önmagán belül is kiírható, ami hasznos például egy fa struktúra megjelenítésekor:

```latte
{define menu, $items}
<ul>
	{foreach $items as $item}
		<li>
		{if is_array($item)}
			{include menu, $item}
		{else}
			{$item}
		{/if}
		</li>
	{/foreach}
</ul>
{/define}
```

A `{include menu, ...}` helyett írhatjuk azt is, hogy `{include this, ...}`, ahol a `this` az aktuális blokkot jelenti.

A kinyomtatott tartalom [szűrőkkel |syntax#filters] módosítható. A következő példa eltávolít minden HTML-t és címszavakat:

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


Szülői blokk .[#toc-parent-block]
---------------------------------

Ha ki kell nyomtatnia a blokk tartalmát a szülő sablonból, akkor a `{include parent}` utasítás megteszi a hatását. Ez akkor hasznos, ha a szülő blokk tartalmához szeretne hozzáadni ahelyett, hogy teljesen felülírná azt.

```latte
{block footer}
	{include parent}
	<a href="https://github.com/nette">GitHub</a>
	<a href="https://twitter.com/nettefw">Twitter</a>
{/block}
```


Definíciók `{define}` .{toc: Definitions}
-----------------------------------------

A blokkok mellett a Latte-ban "definíciók" is vannak. Ezek a hagyományos programozási nyelvek függvényeihez hasonlíthatók. Hasznosak a sablonrészletek újrafelhasználásához, hogy ne ismételje magát.

A Latte igyekszik a dolgokat egyszerűen tartani, ezért a definíciók alapvetően ugyanazok, mint a blokkok, és **minden, amit a blokkokról mondunk, a definíciókra is vonatkozik**. Abban különböznek a blokkoktól:

1) `{define}` címkékkel vannak körülvéve
2) csak akkor kerülnek megjelenítésre, amikor a következő módon kerülnek beillesztésre `{include}`
3) paramétereket definiálhatsz számukra, mint a PHP függvényeknél.

```latte
{block foo}<p>Hello</p>{/block}
{* prints: <p>Hello</p> *}

{define bar}<p>World</p>{/define}
{* prints nothing *}

{include bar}
{* prints: <p>World</p> *}
```

Képzeljük el, hogy van egy segédsablonunk, amely a HTML űrlapok rajzolásának definícióit tartalmazza.

```latte .{file: forms.latte}
{define input, $name, $value, $type = 'text'}
	<input type={$type} name={$name} value={$value}>
{/define}

{define textarea, $name, $value}
	<textarea name={$name}>{$value}</textarea>
{/define}
```

A definíciók argumentumai mindig opcionálisak, alapértelmezett értékük `null`, kivéve, ha alapértelmezett érték van megadva (itt a `'text'` az alapértelmezett érték a `$type` számára). A paramétertípusok is deklarálhatók: `{define input, string $name, ...}`.

A definíciókat tartalmazó sablon betöltése a [`{import}` |#horizontal-reuse]. Maguk a definíciók [ugyanúgy |#Printing Blocks] kerülnek megjelenítésre, mint [a blokkok |#Printing Blocks]:

```latte
<p>{include input, 'password', null, 'password'}</p>
<p>{include textarea, 'comment'}</p>
```

A definíciók nem férnek hozzá az aktív kontextus változóihoz, de a globális változókhoz igen.


Dinamikus blokknevek .[#toc-dynamic-block-names]
------------------------------------------------

A Latte nagy rugalmasságot biztosít a blokkok definiálásában, mivel a blokk neve bármilyen PHP kifejezés lehet. Ez a példa három blokkot definiál, amelyek neve `hi-Peter`, `hi-John` és `hi-Mary`:

```latte .{file: parent.latte}
{foreach [Peter, John, Mary] as $name}
	{block "hi-$name"}Hi, én vagyok {$name}.{/block}
{/foreach}
```

Egy gyermek sablonban például csak egy blokkot definiálhatunk újra:

```latte .{file: child.latte}
{block hi-John}Hello. Én vagyok {$name}.{/block}
```

Így a kimenet így fog kinézni:

```latte
Hi, I am Peter.
Hello. I am John.
Hi, I am Mary.
```


`{ifset}` .{toc: Checking Block Existence}
------------------------------------------

.[note]
Lásd még [`{ifset $var}` |tags#ifset-elseifset]

A `{ifset blockname}` teszt segítségével ellenőrizheti, hogy egy blokk (vagy több blokk) létezik-e az aktuális kontextusban:

```latte
{ifset footer}
	...
{/ifset}

{ifset footer, header, main}
	...
{/ifset}
```

A blokk neveként használhat egy változót vagy bármely PHP kifejezését. Ebben az esetben a változó elé írja be a `block` kulcsszót, hogy egyértelmű legyen, hogy nem a [változót |tags#ifset-elseifset] ellenőrzi:

```latte
{ifset block $name}
	...
{/ifset}
```

A blokkok meglétét szintén a [`hasBlock()` |functions#hasBlock]:

```latte
{if hasBlock(header) || hasBlock(footer)}
	...
{/if}
```


Tippek .[#toc-tips]
-------------------
Íme néhány tipp a blokkokkal való munkához:

- Az utolsó felső szintű blokknak nem kell záró taggel rendelkeznie (a blokk a dokumentum végével ér véget). Ez leegyszerűsíti a gyermek sablonok írását, amelyek egy elsődleges blokk.

- Az extra olvashatóság érdekében opcionálisan nevet adhat a `{/block}` tagnek, például `{/block footer}`. A névnek azonban meg kell egyeznie a blokk nevével. Nagyobb sablonoknál ez a technika segít abban, hogy lássa, mely blokkcímkéket zárja le.

- Egy sablonban közvetlenül nem definiálhat több azonos nevű blokkcímkét. Ez azonban [dinamikus blokknevek |#dynamic block names] használatával megvalósítható.

- Az [n:attribútumokat |syntax#n:attributes] használhatja a blokkok definiálására, mint például `<h1 n:block=title>Welcome to my awesome homepage</h1>`

- A blokkok nevek nélkül is használhatók, csak a [szűrők |syntax#filters] kimenetre történő alkalmazására: `{block|strip} hello {/block}`


Vízszintes újrafelhasználás `{import}` .{toc: Horizontal Reuse}
===============================================================

A horizontális újrafelhasználás a Latte harmadik újrafelhasználási és öröklési mechanizmusa. Lehetővé teszi a blokkok betöltését más sablonokból. Ez hasonló ahhoz, mintha PHP-ben létrehoznánk egy fájlt segédfüggvényekkel, majd betöltenénk a `require` segítségével.

Bár a sablonok elrendezésének öröklése a Latte egyik legerősebb funkciója, az egyszerű öröklésre korlátozódik - egy sablon csak egy másik sablont terjeszthet ki. A horizontális újrafelhasználás egy módja a többszörös öröklés elérésének.

Legyen egy sor blokkdefiníció:

```latte .{file: blocks.latte}
{block sidebar}...{/block}

{block menu}...{/block}
```

A `{import}` paranccsal importáljuk a `blocks.latte` alatt definiált összes blokkot és [definíciót |#definitions] egy másik sablonba:

```latte .{file: child.latte}
{import 'blocks.latte'}

{* oldalsáv és menü blokkok mostantól használhatók *}
```

Ha a blokkokat a szülő sablonba importálja (azaz a `{import}` parancsot használja a `layout.latte`), akkor a blokkok az összes gyermek sablonban is elérhetőek lesznek, ami nagyon praktikus.

Az importálni kívánt sablon (pl. `blocks.latte`) nem [bővíthet ki |#Layout Inheritance] egy másik sablont, azaz használja a `{layout}`. Más sablonokat azonban importálhat.

A `{import}` címkének kell lennie az első sabloncímkének a `{layout}` után. A sablon neve bármilyen PHP-kifejezés lehet:

```latte
{import $ajax ? 'ajax.latte' : 'not-ajax.latte'}
```

Annyi `{import}` utasítást használhat egy adott sablonban, amennyit csak akar. Ha két importált sablon ugyanazt a blokkot definiálja, akkor az első nyer. A legnagyobb prioritást azonban a fő sablon kapja, amely bármelyik importált blokkot felülírhatja.

A felülírt blokkok tartalma megőrizhető a blokknak a [szülő blokkhoz |#parent block] hasonló módon történő beillesztésével:

```latte
{layout 'layout.latte'}

{import 'blocks.latte'}

{block sidebar}
	{include parent}
{/block}

{block title}...{/block}
{block content}...{/block}
```

Ebben a példában a `{include parent}` helyesen hívja meg a `sidebar` blokkot a `blocks.latte` sablonból.


Egység öröklődése `{embed}` .{toc: Unit Inheritance}
====================================================

Az egység-öröklés az elrendezés öröklés gondolatát a tartalomrészletek szintjére viszi át. Míg az elrendezésöröklés "dokumentumvázakkal" dolgozik, amelyeket a gyermeksablonok hívnak életre, addig az egységöröklés lehetővé teszi, hogy kisebb tartalmi egységek vázait hozza létre, és azokat bárhol újra felhasználja.

Az egységöröklésben a `{embed}` címke a kulcs. Egyesíti a `{include}` és a `{layout}` viselkedését. Lehetővé teszi egy másik sablon vagy blokk tartalmának beépítését, és opcionálisan változók átadását, ahogyan a `{include}` is teszi. Azt is lehetővé teszi, hogy felülírja a bevont sablonon belül definiált blokkokat, mint a `{layout}`.

Példának okáért az összecsukható harmonika elemet fogjuk használni. Nézzük meg az elem vázát a `collapsible.latte` sablonban :

```latte
<section class="collapsible {$modifierClass}">
	<h4 class="collapsible__title">
		{block title}{/block}
	</h4>

	<div class="collapsible__content">
		{block content}{/block}
	</div>
</section>
```

A `{block}` címkék két blokkot határoznak meg, amelyeket a gyermek sablonok tölthetnek ki. Igen, mint a szülő sablon esetében az elrendezés öröklés sablonban. A `$modifierClass` változót is láthatja.

Használjuk az elemünket a sablonban. Itt jön a képbe a `{embed}`. Ez egy szuper erős készlet, amivel mindent megtehetünk: bevonhatjuk az elem sablonjának tartalmát, hozzáadhatunk változókat, és hozzáadhatunk blokkokat egyéni HTML-ekkel:

```latte
{embed 'collapsible.latte', modifierClass: my-style}
	{block title}
		Hello World
	{/block}

	{block content}
		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
		elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
	{/block}
{/embed}
```

A kimenet így nézhet ki:

```latte
<section class="collapsible my-style">
	<h4 class="collapsible__title">
		Hello World
	</h4>

	<div class="collapsible__content">
		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
		elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
	</div>
</section>
```

A beágyazási címkéken belüli blokkok a többi blokkoktól független, külön réteget alkotnak. Ezért lehet ugyanolyan nevük, mint a beágyazáson kívüli blokknak, és semmilyen módon nem befolyásolják őket. A `{embed}` címkéken belüli [include |#Printing Blocks] tag használatával beilleszthetünk itt létrehozott blokkokat, a beágyazott sablonból származó blokkokat (amelyek *nem* [lokálisak |#Local Blocks]), és a fő sablonból származó blokkokat is, amelyek *helyesek*. Más fájlokból is [importálhatsz blokkokat |#Horizontal Reuse]:

```latte
{block outer}…{/block}
{block local hello}…{/block}

{embed 'collapsible.latte', modifierClass: my-style}
	{import 'blocks.latte'}

	{block inner}…{/block}

	{block title}
		{include inner} {* működik, a blokk a beágyazáson belül van definiálva *}
		{include hello} {* működik, a blokk ebben a sablonban helyi *}
		{include content} {* működik, a blokk a beágyazott sablonban van definiálva *}
		{include aBlockDefinedInImportedTemplate} {* működik *}
		{include outer} {* nem működik! - a blokk a külső rétegben van *}
	{/block}
{/embed}
```

A beágyazott sablonok nem férnek hozzá az aktív kontextus változóihoz, de a globális változókhoz igen.

A `{embed}` segítségével nemcsak sablonokat, hanem más blokkokat is beilleszthetünk, így az előző példát így is meg lehetne írni:

```latte
{define collapsible}
<section class="collapsible {$modifierClass}">
	<h4 class="collapsible__title">
		{block title}{/block}
	</h4>
	...
</section>
{/define}


{embed collapsible, modifierClass: my-style}
	{block title}
		Hello World
	{/block}
	...
{/embed}
```

Ha átadunk egy kifejezést a `{embed}` címre, és nem egyértelmű, hogy az egy blokk vagy fájlnév, akkor adjuk hozzá a `block` vagy a `file` kulcsszót:

```latte
{embed block $name} ... {/embed}
```


Felhasználási esetek .[#toc-use-cases]
======================================

A Latte-ban az öröklésnek és a kód újrafelhasználásának különböző típusai vannak. Foglaljuk össze a főbb fogalmakat a nagyobb áttekinthetőség érdekében:


`{include template}`
--------------------

**Használati eset:** A `header.latte` & `footer.latte` használata a `layout.latte` oldalon belül.

`header.latte`

```latte
<nav>
   <div>Home</div>
   <div>About</div>
</nav>
```

`footer.latte`

```latte
<footer>
   <div>Copyright</div>
</footer>
```

`layout.latte`

```latte
{include 'header.latte'}

<main>{block main}{/block}</main>

{include 'footer.latte'}
```


`{layout}`
----------

**Használati eset**: A `layout.latte` kiterjesztése a `homepage.latte` és a `about.latte` oldalakon belül.

`layout.latte`

```latte
{include 'header.latte'}

<main>{block main}{/block}</main>

{include 'footer.latte'}
```

`homepage.latte`

```latte
{layout 'layout.latte'}

{block main}
	<p>Homepage</p>
{/block}
```

`about.latte`

```latte
{layout 'layout.latte'}

{block main}
	<p>About page</p>
{/block}
```


`{import}`
----------

**Használati eset**: `sidebar.latte` a `single.product.latte` és `single.service.latte` oldalon.

`sidebar.latte`

```latte
{block sidebar}<aside>This is sidebar</aside>{/block}
```

`single.product.latte`

```latte
{layout 'product.layout.latte'}

{import 'sidebar.latte'}

{block main}<main>Product page</main>{/block}
```

`single.service.latte`

```latte
{layout 'service.layout.latte'}

{import 'sidebar.latte'}

{block main}<main>Service page</main>{/block}
```


`{define}`
----------

**Használati eset**: Egy függvény, amely megkap néhány változót és kiad néhány jelölést.

`form.latte`

```latte
{define form-input, $name, $value, $type = 'text'}
	<input type={$type} name={$name} value={$value}>
{/define}
```

`profile.service.latte`

```latte
{import 'form.latte'}

<form action="" method="post">
	<div>{include form-input, username}</div>
	<div>{include form-input, password}</div>
	<div>{include form-input, submit, Submit, submit}</div>
</form>
```


`{embed}`
---------

**Használati eset**: A `pagination.latte` beágyazása a `product.table.latte` & `service.table.latte`.

`pagination.latte`

```latte
<div id="pagination">
	<div>{block first}{/block}</div>

	{for $i = $min + 1; $i < $max - 1; $i++}
		<div>{$i}</div>
	{/for}

	<div>{block last}{/block}</div>
</div>
```

`product.table.latte`

```latte
{embed 'pagination.latte', min: 1, max: $products->count}
	{block first}First Product Page{/block}
	{block last}Last Product Page{/block}
{/embed}
```

`service.table.latte`

```latte
{embed 'pagination.latte', min: 1, max: $services->count}
	{block first}First Service Page{/block}
	{block last}Last Service Page{/block}
{/embed}
```

Sablon öröklődés és újrafelhasználhatóság

A sablonok újrafelhasználhatósága és az öröklési mechanizmusok azért vannak itt, hogy növeljék a termelékenységet, mivel minden sablon csak az egyedi tartalmát tartalmazza, és az ismétlődő elemek és struktúrák újrafelhasználásra kerülnek. Három fogalmat mutatunk be: az elrendezés öröklést, a horizontális újrafelhasználást és az egység öröklést.

A Latte sablon öröklés koncepciója hasonló a PHP osztály örökléshez. Meghatározunk egy szülő sablont, amelyből más gyermeksablonok kiterjeszthetők, és felülírhatják a szülő sablon egyes részeit. Nagyszerűen működik, ha az elemek közös szerkezetűek. Bonyolultnak hangzik? Ne aggódjon, nem az.

Layout öröklődés {layout}

Nézzük meg az elrendezési sablon öröklődését egy példával kezdve. Ez egy szülő sablon, amelyet például layout.latte -nak fogunk hívni, és egy HTML vázdokumentumot definiál.

<!doctype html>
<html lang="en">
<head>
	<title>{block title}{/block}</title>
	<link rel="stylesheet" href="style.css">
</head>
<body>
	<div id="content">
		{block content}{/block}
	</div>
	<div id="footer">
		{block footer}&copy; Copyright 2008{/block}
	</div>
</body>
</html>

A {block} címkék három blokkot határoznak meg, amelyeket a gyermek sablonok kitölthetnek. A blokkcímke csak annyit tesz, hogy közli a sablonmotorral, hogy a gyermek sablonok felülbírálhatják a sablon ezen részeit a saját, azonos nevű blokkjuk meghatározásával.

Egy gyermek sablon így nézhet ki:

{layout 'layout.latte'}

{block title}My amazing blog{/block}

{block content}
	<p>Welcome to my awesome homepage.</p>
{/block}

A {layout} címke itt a kulcs. Azt mondja a sablonmotornak, hogy ez a sablon egy másik sablont „bővít“. Amikor a Latte rendereli ezt a sablont, először megkeresi a szülő sablont – ebben az esetben a layout.latte.

Ekkor a sablonmotor észreveszi a layout.latte három blokkcímkét, és ezeket a blokkokat a gyermek sablon tartalmával helyettesíti. Vegye figyelembe, hogy mivel a gyermek sablon nem definiálta a footer blokkot, helyette a szülő sablon tartalmát használja. A szülő sablon {block} címkén belüli tartalom mindig tartalékként kerül felhasználásra.

A kimenet így nézhet ki:

<!doctype html>
<html lang="en">
<head>
	<title>My amazing blog</title>
	<link rel="stylesheet" href="style.css">
</head>
<body>
	<div id="content">
		<p>Welcome to my awesome homepage.</p>
	</div>
	<div id="footer">
		&copy; Copyright 2008
	</div>
</body>
</html>

A gyermek sablonban a blokkok csak vagy a legfelső szinten, vagy egy másik blokkon belül helyezkedhetnek el, azaz:

{block content}
	<h1>{block title}Welcome to my awesome homepage{/block}</h1>
{/block}

A blokk mindig létrejön, függetlenül attól, hogy a környező {if} feltétel igaznak vagy hamisnak értékelődik-e ki. Ellentétben azzal, amit gondolhat, ez a sablon valóban definiál egy blokkot.

{if false}
	{block head}
		<meta name="robots" content="noindex, follow">
	{/block}
{/if}

Ha azt szeretné, hogy a blokkban lévő kimenet feltételesen jelenjen meg, használja helyette a következőt:

{block head}
	{if $condition}
		<meta name="robots" content="noindex, follow">
	{/if}
{/block}

A gyermek sablonban lévő blokkokon kívüli adatok a layout sablon megjelenítése előtt kerülnek végrehajtásra, így használhatja a {var $foo = bar} típusú változók definiálására és az adatok továbbítására az egész öröklési láncban:

{layout 'layout.latte'}
{var $robots = noindex}

...

Többszintű öröklés

Annyi szintű öröklést használhat, amennyire csak szüksége van. Az elrendezés öröklésének egyik gyakori módja a következő háromszintű megközelítés:

  1. Hozzon létre egy layout.latte sablont, amely tartalmazza a webhely fő megjelenését.
  2. Hozzon létre egy layout-SECTIONNAME.latte sablont a webhely minden egyes szakaszához. Például: layout-news.latte, layout-blog.latte stb. Ezek a sablonok mind a layout.latte bővítik, és tartalmazzák a szekció-specifikus stílusokat/designt.
  3. Hozzon létre egyedi sablonokat minden egyes oldaltípushoz, például egy hírcikkhez vagy blogbejegyzéshez. Ezek a sablonok kiterjesztik a megfelelő szakaszsablont.

Dinamikus elrendezés öröklődése

A szülő sablon neveként egy változót vagy bármilyen PHP-kifejezést használhat, így az öröklés dinamikusan viselkedhet:

{layout $standalone ? 'minimum.latte' : 'layout.latte'}

A Latte API-t használhatja az elrendezési sablon automatikus kiválasztására is.

Tippek

Íme néhány tipp az elrendezés örökléssel való munkához:

  • Ha a {layout} címet használja egy sablonban, akkor annak a sablonban az első sabloncímkének kell lennie.
  • Az elrendezés automatikusan kereshető (mint az előadókban). Ebben az esetben, ha a sablonban nem kell elrendezés, akkor ezt a {layout none} címkével jelzi.
  • A {layout} címkének a {extends} aliasával rendelkezik.
  • A kiterjesztett sablon fájlneve a sablon betöltőjétől függ.
  • Annyi blokkja lehet, amennyit csak akar. Ne feledje, hogy a gyermek sablonoknak nem kell minden szülői blokkot definiálniuk, így számos blokkban kitölthet ésszerű alapértelmezéseket, és csak azokat definiálhatja, amelyekre később szüksége van.

Blokkok {block}

Lásd még anonim {block}

A blokk lehetőséget biztosít arra, hogy megváltoztassuk a sablon egy bizonyos részének megjelenítési módját, de semmilyen módon nem avatkozik bele a körülötte lévő logikába. A következő példával szemléltetjük, hogyan működik egy blokk, és ami még fontosabb, hogyan nem működik:

{foreach $posts as $post}
{block post}
	<h1>{$post->title}</h1>
	<p>{$post->body}</p>
{/block}
{/foreach}

Ha ezt a sablont rendereli, az eredmény pontosan ugyanaz lenne a blokkcímkékkel vagy azok nélkül. A blokkok hozzáférnek a külső hatókörök változóihoz. Ez csak egy módja annak, hogy egy gyermek sablon által felülbírálhatóvá tegye:

{layout 'parent.Latte'}

{block post}
	<article>
		<header>{$post->title}</header>
		<section>{$post->text}</section>
	</article>
{/block}

Most a gyermek sablon megjelenítésekor a ciklus a child.Latte gyermek sablonban definiált blokkot fogja használni a parent.Latte alapsablonban definiált helyett ; a végrehajtott sablon ekvivalens a következővel:

{foreach $posts as $post}
	<article>
		<header>{$post->title}</header>
		<section>{$post->text}</section>
	</article>
{/foreach}

Ha azonban egy új változót hozunk létre egy megnevezett blokkban, vagy kicseréljük egy meglévő változó értékét, a változás csak a blokkban lesz látható:

{var $foo = 'foo'}
{block post}
	{do $foo = 'new value'}
	{var $bar = 'bar'}
{/block}

foo: {$foo}                  // prints: foo
bar: {$bar ?? 'not defined'} // prints: not defined

A blokk tartalma szűrőkkel módosítható. A következő példa eltávolít minden HTML-t és címszavakat:

<title>{block title|stripHtml|capitalize}...{/block}</title>

A címke n:attribútumként is leírható:

<article n:block=post>
	...
</article>

Helyi blokkok

Minden blokk felülírja az azonos nevű szülői blokk tartalmát. Kivéve a helyi blokkokat. Ezek olyanok, mint az osztály privát metódusai. Létrehozhatsz egy sablont anélkül, hogy aggódnod kellene, hogy – a blokknevek egybeesése miatt – a második sablon felülírja őket.

{block local helper}
	...
{/block}

Blokkok nyomtatása {include}

Lásd még {include file}

Ha egy blokkot egy adott helyre szeretne kinyomtatni, használja a {include blockname} címkét:

<title>{block title}{/block}</title>

<h1>{include title}</h1>

A blokkot egy másik sablonból is megjelenítheti:

{include footer from 'main.latte'}

A nyomtatott blokk nem fér hozzá az aktív kontextus változóihoz, kivéve, ha a blokk ugyanabban a fájlban van definiálva, ahol szerepel. A globális változókhoz azonban hozzáférnek.

A változókat a következő módon adhatja át a blokknak:

{include footer, foo: bar, id: 123}

A blokk neveként használhat egy változót vagy bármilyen PHP-kifejezést. Ebben az esetben a változó elé írja a block kulcsszót, hogy már fordításkor tudható legyen, hogy egy blokkról van szó, és ne egy insert template-ről, amelynek a neve szintén szerepelhetne a változóban:

{var $name = footer}
{include block $name}

A blokk önmagán belül is kiírható, ami hasznos például egy fa struktúra megjelenítésekor:

{define menu, $items}
<ul>
	{foreach $items as $item}
		<li>
		{if is_array($item)}
			{include menu, $item}
		{else}
			{$item}
		{/if}
		</li>
	{/foreach}
</ul>
{/define}

A {include menu, ...} helyett írhatjuk azt is, hogy {include this, ...}, ahol a this az aktuális blokkot jelenti.

A kinyomtatott tartalom szűrőkkel módosítható. A következő példa eltávolít minden HTML-t és címszavakat:

<title>{include heading|stripHtml|capitalize}</title>

Szülői blokk

Ha ki kell nyomtatnia a blokk tartalmát a szülő sablonból, akkor a {include parent} utasítás megteszi a hatását. Ez akkor hasznos, ha a szülő blokk tartalmához szeretne hozzáadni ahelyett, hogy teljesen felülírná azt.

{block footer}
	{include parent}
	<a href="https://github.com/nette">GitHub</a>
	<a href="https://twitter.com/nettefw">Twitter</a>
{/block}

Definíciók {define}

A blokkok mellett a Latte-ban „definíciók“ is vannak. Ezek a hagyományos programozási nyelvek függvényeihez hasonlíthatók. Hasznosak a sablonrészletek újrafelhasználásához, hogy ne ismételje magát.

A Latte igyekszik a dolgokat egyszerűen tartani, ezért a definíciók alapvetően ugyanazok, mint a blokkok, és minden, amit a blokkokról mondunk, a definíciókra is vonatkozik. Abban különböznek a blokkoktól:

  1. {define} címkékkel vannak körülvéve
  2. csak akkor kerülnek megjelenítésre, amikor a következő módon kerülnek beillesztésre {include}
  3. paramétereket definiálhatsz számukra, mint a PHP függvényeknél.
{block foo}<p>Hello</p>{/block}
{* prints: <p>Hello</p> *}

{define bar}<p>World</p>{/define}
{* prints nothing *}

{include bar}
{* prints: <p>World</p> *}

Képzeljük el, hogy van egy segédsablonunk, amely a HTML űrlapok rajzolásának definícióit tartalmazza.

{define input, $name, $value, $type = 'text'}
	<input type={$type} name={$name} value={$value}>
{/define}

{define textarea, $name, $value}
	<textarea name={$name}>{$value}</textarea>
{/define}

A definíciók argumentumai mindig opcionálisak, alapértelmezett értékük null, kivéve, ha alapértelmezett érték van megadva (itt a 'text' az alapértelmezett érték a $type számára). A paramétertípusok is deklarálhatók: {define input, string $name, ...}.

A definíciókat tartalmazó sablon betöltése a {import}. Maguk a definíciók ugyanúgy kerülnek megjelenítésre, mint a blokkok:

<p>{include input, 'password', null, 'password'}</p>
<p>{include textarea, 'comment'}</p>

A definíciók nem férnek hozzá az aktív kontextus változóihoz, de a globális változókhoz igen.

Dinamikus blokknevek

A Latte nagy rugalmasságot biztosít a blokkok definiálásában, mivel a blokk neve bármilyen PHP kifejezés lehet. Ez a példa három blokkot definiál, amelyek neve hi-Peter, hi-John és hi-Mary:

{foreach [Peter, John, Mary] as $name}
	{block "hi-$name"}Hi, én vagyok {$name}.{/block}
{/foreach}

Egy gyermek sablonban például csak egy blokkot definiálhatunk újra:

{block hi-John}Hello. Én vagyok {$name}.{/block}

Így a kimenet így fog kinézni:

Hi, I am Peter.
Hello. I am John.
Hi, I am Mary.

{ifset}

Lásd még {ifset $var}

A {ifset blockname} teszt segítségével ellenőrizheti, hogy egy blokk (vagy több blokk) létezik-e az aktuális kontextusban:

{ifset footer}
	...
{/ifset}

{ifset footer, header, main}
	...
{/ifset}

A blokk neveként használhat egy változót vagy bármely PHP kifejezését. Ebben az esetben a változó elé írja be a block kulcsszót, hogy egyértelmű legyen, hogy nem a változót ellenőrzi:

{ifset block $name}
	...
{/ifset}

A blokkok meglétét szintén a hasBlock():

{if hasBlock(header) || hasBlock(footer)}
	...
{/if}

Tippek

Íme néhány tipp a blokkokkal való munkához:

  • Az utolsó felső szintű blokknak nem kell záró taggel rendelkeznie (a blokk a dokumentum végével ér véget). Ez leegyszerűsíti a gyermek sablonok írását, amelyek egy elsődleges blokk.
  • Az extra olvashatóság érdekében opcionálisan nevet adhat a {/block} tagnek, például {/block footer}. A névnek azonban meg kell egyeznie a blokk nevével. Nagyobb sablonoknál ez a technika segít abban, hogy lássa, mely blokkcímkéket zárja le.
  • Egy sablonban közvetlenül nem definiálhat több azonos nevű blokkcímkét. Ez azonban dinamikus blokknevek használatával megvalósítható.
  • Az n:attribútumokat használhatja a blokkok definiálására, mint például <h1 n:block=title>Welcome to my awesome homepage</h1>
  • A blokkok nevek nélkül is használhatók, csak a szűrők kimenetre történő alkalmazására: {block|strip} hello {/block}

Vízszintes újrafelhasználás {import}

A horizontális újrafelhasználás a Latte harmadik újrafelhasználási és öröklési mechanizmusa. Lehetővé teszi a blokkok betöltését más sablonokból. Ez hasonló ahhoz, mintha PHP-ben létrehoznánk egy fájlt segédfüggvényekkel, majd betöltenénk a require segítségével.

Bár a sablonok elrendezésének öröklése a Latte egyik legerősebb funkciója, az egyszerű öröklésre korlátozódik – egy sablon csak egy másik sablont terjeszthet ki. A horizontális újrafelhasználás egy módja a többszörös öröklés elérésének.

Legyen egy sor blokkdefiníció:

{block sidebar}...{/block}

{block menu}...{/block}

A {import} paranccsal importáljuk a blocks.latte alatt definiált összes blokkot és definíciót egy másik sablonba:

{import 'blocks.latte'}

{* oldalsáv és menü blokkok mostantól használhatók *}

Ha a blokkokat a szülő sablonba importálja (azaz a {import} parancsot használja a layout.latte), akkor a blokkok az összes gyermek sablonban is elérhetőek lesznek, ami nagyon praktikus.

Az importálni kívánt sablon (pl. blocks.latte) nem bővíthet ki egy másik sablont, azaz használja a {layout}. Más sablonokat azonban importálhat.

A {import} címkének kell lennie az első sabloncímkének a {layout} után. A sablon neve bármilyen PHP-kifejezés lehet:

{import $ajax ? 'ajax.latte' : 'not-ajax.latte'}

Annyi {import} utasítást használhat egy adott sablonban, amennyit csak akar. Ha két importált sablon ugyanazt a blokkot definiálja, akkor az első nyer. A legnagyobb prioritást azonban a fő sablon kapja, amely bármelyik importált blokkot felülírhatja.

A felülírt blokkok tartalma megőrizhető a blokknak a szülő blokkhoz hasonló módon történő beillesztésével:

{layout 'layout.latte'}

{import 'blocks.latte'}

{block sidebar}
	{include parent}
{/block}

{block title}...{/block}
{block content}...{/block}

Ebben a példában a {include parent} helyesen hívja meg a sidebar blokkot a blocks.latte sablonból.

Egység öröklődése {embed}

Az egység-öröklés az elrendezés öröklés gondolatát a tartalomrészletek szintjére viszi át. Míg az elrendezésöröklés „dokumentumvázakkal“ dolgozik, amelyeket a gyermeksablonok hívnak életre, addig az egységöröklés lehetővé teszi, hogy kisebb tartalmi egységek vázait hozza létre, és azokat bárhol újra felhasználja.

Az egységöröklésben a {embed} címke a kulcs. Egyesíti a {include} és a {layout} viselkedését. Lehetővé teszi egy másik sablon vagy blokk tartalmának beépítését, és opcionálisan változók átadását, ahogyan a {include} is teszi. Azt is lehetővé teszi, hogy felülírja a bevont sablonon belül definiált blokkokat, mint a {layout}.

Példának okáért az összecsukható harmonika elemet fogjuk használni. Nézzük meg az elem vázát a collapsible.latte sablonban :

<section class="collapsible {$modifierClass}">
	<h4 class="collapsible__title">
		{block title}{/block}
	</h4>

	<div class="collapsible__content">
		{block content}{/block}
	</div>
</section>

A {block} címkék két blokkot határoznak meg, amelyeket a gyermek sablonok tölthetnek ki. Igen, mint a szülő sablon esetében az elrendezés öröklés sablonban. A $modifierClass változót is láthatja.

Használjuk az elemünket a sablonban. Itt jön a képbe a {embed}. Ez egy szuper erős készlet, amivel mindent megtehetünk: bevonhatjuk az elem sablonjának tartalmát, hozzáadhatunk változókat, és hozzáadhatunk blokkokat egyéni HTML-ekkel:

{embed 'collapsible.latte', modifierClass: my-style}
	{block title}
		Hello World
	{/block}

	{block content}
		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
		elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
	{/block}
{/embed}

A kimenet így nézhet ki:

<section class="collapsible my-style">
	<h4 class="collapsible__title">
		Hello World
	</h4>

	<div class="collapsible__content">
		<p>Lorem ipsum dolor sit amet, consectetuer adipiscing
		elit. Nunc dapibus tortor vel mi dapibus sollicitudin.</p>
	</div>
</section>

A beágyazási címkéken belüli blokkok a többi blokkoktól független, külön réteget alkotnak. Ezért lehet ugyanolyan nevük, mint a beágyazáson kívüli blokknak, és semmilyen módon nem befolyásolják őket. A {embed} címkéken belüli include tag használatával beilleszthetünk itt létrehozott blokkokat, a beágyazott sablonból származó blokkokat (amelyek nem lokálisak), és a fő sablonból származó blokkokat is, amelyek helyesek. Más fájlokból is importálhatsz blokkokat:

{block outer}…{/block}
{block local hello}…{/block}

{embed 'collapsible.latte', modifierClass: my-style}
	{import 'blocks.latte'}

	{block inner}…{/block}

	{block title}
		{include inner} {* működik, a blokk a beágyazáson belül van definiálva *}
		{include hello} {* működik, a blokk ebben a sablonban helyi *}
		{include content} {* működik, a blokk a beágyazott sablonban van definiálva *}
		{include aBlockDefinedInImportedTemplate} {* működik *}
		{include outer} {* nem működik! - a blokk a külső rétegben van *}
	{/block}
{/embed}

A beágyazott sablonok nem férnek hozzá az aktív kontextus változóihoz, de a globális változókhoz igen.

A {embed} segítségével nemcsak sablonokat, hanem más blokkokat is beilleszthetünk, így az előző példát így is meg lehetne írni:

{define collapsible}
<section class="collapsible {$modifierClass}">
	<h4 class="collapsible__title">
		{block title}{/block}
	</h4>
	...
</section>
{/define}


{embed collapsible, modifierClass: my-style}
	{block title}
		Hello World
	{/block}
	...
{/embed}

Ha átadunk egy kifejezést a {embed} címre, és nem egyértelmű, hogy az egy blokk vagy fájlnév, akkor adjuk hozzá a block vagy a file kulcsszót:

{embed block $name} ... {/embed}

Felhasználási esetek

A Latte-ban az öröklésnek és a kód újrafelhasználásának különböző típusai vannak. Foglaljuk össze a főbb fogalmakat a nagyobb áttekinthetőség érdekében:

{include template}

Használati eset: A header.latte & footer.latte használata a layout.latte oldalon belül.

header.latte

<nav>
   <div>Home</div>
   <div>About</div>
</nav>

footer.latte

<footer>
   <div>Copyright</div>
</footer>

layout.latte

{include 'header.latte'}

<main>{block main}{/block}</main>

{include 'footer.latte'}

{layout}

Használati eset: A layout.latte kiterjesztése a homepage.latte és a about.latte oldalakon belül.

layout.latte

{include 'header.latte'}

<main>{block main}{/block}</main>

{include 'footer.latte'}

homepage.latte

{layout 'layout.latte'}

{block main}
	<p>Homepage</p>
{/block}

about.latte

{layout 'layout.latte'}

{block main}
	<p>About page</p>
{/block}

{import}

Használati eset: sidebar.latte a single.product.latte és single.service.latte oldalon.

sidebar.latte

{block sidebar}<aside>This is sidebar</aside>{/block}

single.product.latte

{layout 'product.layout.latte'}

{import 'sidebar.latte'}

{block main}<main>Product page</main>{/block}

single.service.latte

{layout 'service.layout.latte'}

{import 'sidebar.latte'}

{block main}<main>Service page</main>{/block}

{define}

Használati eset: Egy függvény, amely megkap néhány változót és kiad néhány jelölést.

form.latte

{define form-input, $name, $value, $type = 'text'}
	<input type={$type} name={$name} value={$value}>
{/define}

profile.service.latte

{import 'form.latte'}

<form action="" method="post">
	<div>{include form-input, username}</div>
	<div>{include form-input, password}</div>
	<div>{include form-input, submit, Submit, submit}</div>
</form>

{embed}

Használati eset: A pagination.latte beágyazása a product.table.latte & service.table.latte.

pagination.latte

<div id="pagination">
	<div>{block first}{/block}</div>

	{for $i = $min + 1; $i < $max - 1; $i++}
		<div>{$i}</div>
	{/for}

	<div>{block last}{/block}</div>
</div>

product.table.latte

{embed 'pagination.latte', min: 1, max: $products->count}
	{block first}First Product Page{/block}
	{block last}Last Product Page{/block}
{/embed}

service.table.latte

{embed 'pagination.latte', min: 1, max: $services->count}
	{block first}First Service Page{/block}
	{block last}Last Service Page{/block}
{/embed}