Zavináčová magie v praxi

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Panda
Člen | 569
+
0
-

Protože spousta lidí, převážně těch začínajících, má problémy s pochopením a aplikací zavináčové magie, rozhodl jsem se sepsat tento krátký textík, který, doufám, alespoň některé mýty kolem zavináčů kousek poodhalí a mnohým usnadní bádání.

Nejprve krátký „teoretický“ úvod.

Co to vlastně je zavináč v šabloně? K čemu slouží?

Pokud nepoužíváme AJAX, nemá pro nás zavináč žádný význam. S prvním AJAXovým požadavkem ale přichází otázka: co budě vlastně při takovém požadavku potřeba vykreslovat? Na tuto otázku odpovídají snippety a k tomu jim napomáhají zavináče.

Zavináč umožňuje vykonání příkazu v šabloně nezávisle na tom, zda se šablona vykresluje pro normální požadavek, nebo pro AJAXový. Při AJAXovém požadavku šablona bez zavináčů a snippetů nevykreslí vůbec nic – její obsah se v podstatě přeskočí. Pokud přidáme snippet, tak se jeho obsah bude vykreslovat v závislosti na tom, zda je invalidován (Control::invalidateControl), případně zda je invalidována komponenta, které šablona náleží (v takovém případě se tedy vykreslují všechny snippety z šablony).

Každá šablona se překládá do PHP kódu. Všechny struktury a vymoženosti, které nám poskytuje CurlyBracketsFilter, lze tedy zapsat pomocí klasického PHP (ovšem kdo by se s tím psal, že?). Snippet v podstatě není nic jiného, než podmínka, která kontroluje, zda se snippet má nebo nemá vykreslit. Ale pokud se při AJAXovém požadavku obsah šablony v podstatě přeskočí, jak se PHP dostane k podmínce? Pokud je snippet zapsaný přímo v šabloně, tak to není žádný problém, snippet si zajistí sám, aby ho bylo vidět. Jak ho ale PHP najde, pokud bude uzavřený do nějaké podmínky, bloku, cyklu nebo komponenty? Nijak, musí se mu pomoci. A nyní vstupují na scénu zavináče a vychutnávají si svůj moment slávy…

Jak již bylo řečeno, zavináče umožní vykonání příkazu nezávisle na tom, zda se jedná o AJAXový požadavek, nebo normální. Příkaz se vykoná vždy. A právě to slouží k tomu, aby se PHP parser „probojoval“ až ke snippetu. V podstatě v tom tedy žádná magie není, stačí dát zavináč kolem všech řídicích struktur, bloků, komponent a vkládání šablon, ve kterých máme snippety. Jednoduché, že?

O generování kódu šablony jsem již psal. Pokud jste tedy zvědaví na některé podrobnosti o tom, co se děje za CurlyBracketsFilterem, podívejte se do jiného vlákna: https://forum.nette.org/…iewtopic.php?….

Kam tedy zavináč patří?

  • Před {include}, který vkládá obsah se snippety, ať už se jedná o blok nebo šablonu. Jeden takový bývá v šabloně s layoutem, většinou {include $content}, případně {include #content} u nových šablon. Zavináč se vždy píše před první složenou závorku: @{include #content}.
  • Před vykreslení komponenty, která obsahuje snippety, ať už pomocí makra {control ...} (popř. {control ...}, které je aliasem pro {widget}), nebo přímého volání vykreslovací funkce: {!$myControl->render()}, {!$control['myControl']->render()}.
  • Před řídící struktury, ve kterých se nacházejí snippety. Pokud má struktura více částí, například {if} ... {else} ... {/if}, musí se zavináč vložit před každou její část. Zavináče se týkají následujících maker: {if}, {elseif}, {else}, {/if}, {ifset}, {elseifset}, {/ifset}, {ifCurrent}, {foreach}, {/foreach}, {for}, {/for}, {while}, {/while}, {continueIf}, {breakIf}, {cache}, {/cache}. Při vnořování struktur je potřeba vložit zavináč na každou úroveň.
  • Před definice bloků se snippety: {block ...} ... {/block}. Platí stejné pravidlo jako pro řídicí struktury – zavináč patří před všechny části. Pokud se jedná o poslední blok v šabloně a za jeho obsahem už nic není, můžeme ukončení {/block} vypustit, takže zavináč bude pouze na jeho začátku.
  • Před příkazy, které nějakým způsobem ovlivňují obsah, který ve snippetu vykreslujeme. Jedná se například o makra {assign} a {default}, ve kterých nastavujeme proměnné pro snippet. Může se také jednat o PHP kód vložený v {? ...} nebo volání funkcí s vedlejšími účinky.

Kam naopak zavináč nepatři?

  • Před součásti makra {snippet ...} ... {/snippet}. Pokud se PHP probojuje až k snippetu, řídí si snippet své vykreslování už sám na základě zmíněné invalidace.
  • Do obsahu snippetu. Uvedení zavináče ve snippetu může způsobit vygenerování kódu s úplně jinou logikou, než která byla původně zamýšlena.
  • Před vykreslení komponent, jejichž vykreslování není založeno na Nette šablonách. Zavináč před takovým vykreslováním by způsobil, že se nám komponenta bude vykreslovat vždy. Jednou takovou komponentou je i Form s ConventionalRenderer nebo rendererem od něj odvozeným..

Příklad

Pro názornost jeden lehce komentovaný příklad. Jsou použity nové šablony a jakákoliv podobnost příkladu se skutečností je čistě náhodná.

@layout.phtml:

{* ... *}
<div id="content">
	@{include #content}
</div>
{* ... *}

<presenter>/<action>.phtml:

{* nastavujeme titulek stránky pro layout
   - není potřeba zavináč                 *}
{assign title => 'Nadpis'}

{* definujeme blok se snippety - @ *}
@{block #content}

{* komponenta používá šablonu se snippety - @ *}
@{control actionList}

{* před snippet zavináč nepatří *}
{snippet info}
	{ifset $showInfo}
		{* komponenta sice používá šablonu se snippety,
		   ale uvnitř snippetu nepoužíváme zavináče!    *}
		{control infoBar}
	{/if}
{/snippet}

@{if count($items) > 0}
	<ul>

	{* vytváříme proměnnou, kterou použijeme ve snippetu - @
	   v cyklu foreach můžeme sice použít objekt $iterator,
	   ale toto je pouze demonstrace myšlenky                *}
	@{assign counter => 0}
	@{foreach $items as $item}
		@{if $item->visible}
			{snippet item$item->id li} {* <li id="item$item->id"> *}
				{* každý snippet musí mít jedinečné jméno,
				   proto do jeho názvu vkládáme $item->id  *}

				{= ++$counter}: {$item->title}
			{snippet} {* </li> *}
		@{/if}
	@{/foreach}
	</ul>

	{* v této podmínce nemáme snippety,
	   zavináče nejsou potřeba          *}
	{if $orderingAllowed}
		<div class="foo">
			<a href="{link editPositions}">Upravit pořadí položek</a>
		</div>
	{/if}
@{/if}

{* formulář s ConventionalRenderer - bez zavináče! *}
{control createNewItemForm}

{* koncový @{/block} vypouštíme *}

Na závěr bych si dovolil jedno malé upozornění: špatné umístění zavináčů může vést k velmi nepříjemným komplikacím, od neškodného nepřekreslování snippetu, přes vykreslení snippetu na samotný začátek stránky až po vygenerování kódu s úplně jinou logikou, než bylo původně zamýšleno. Proto buďte při jejich používání opatrní a pokud si s něčím nebudete jisti, nebojte se zeptat. Minimálně já vždy rád pomohu…

Pokud jsem na něco zapomněl, tak se omlouvám. Ozvěte se – doplníme, upravíme, poladíme.

pmg
Člen | 372
+
0
-

Tomuto návodu zbývá už jen popřát, aby co nejrychleji zastaral. :-)

crempa
Člen | 198
+
0
-

Diky za navod, ale nema uz byt nahodou zavinacova magie pohrbena? Osobne porad jeste cekam na nejakou finalni verzi novych sablon + dokumentaci od Davida.. neprehlidnul sem to nekde? :-)

Panda
Člen | 569
+
0
-

Zavináče ještě potřeba jsou a minimálně do další stabilní verze to bude aktuální. Ale asi by to chtělo vyjádření Davida, jak to s nimi je a bude.

JakubKohout
Člen | 92
+
0
-

No co sem koukal na záznam z (před)poslední soboty o těch šablonách, tak bylo řečeno že je to mrtvá technologie a co sem z toho vyvodil, tak v novejch šablonách by to mělo bejt vyřešený jinak než prerušováním ifu(@) při vykreslování

Panda
Člen | 569
+
0
-

Mno nové šablony pravděpodobně ještě nejsou úplně hotové, protože zavináče nám ve zdrojáku stále straší, bez nich AJAX nefunguje a žádnou alternativu jsem nenašel. Pokud jsem něco přehlédl, opravte mě…

jasir
Člen | 746
+
0
-

Zavináče jsou stále potřeba. Díky za článek, je to moc pěkný souhrn.

rokerkony
Člen | 122
+
0
-

něco takového tu opravdu chybělo!!! moc děkujem :-) konečně ucelenej pohled na zavináče :-)

Jakub Šulák
Člen | 222
+
0
-

Zdravím s pár měsíčním odstupem, bych se rád zeptal, jak to vypadá s odstraněním „zavináčové magie“ z Nette? Je to moje malá noční můra. Mám aplikaci, ke které kodéři píší jen templates. Zavináče jim ale dělají stále problémy…

Honza Marek
Člen | 1664
+
0
-

David má silnou motivaci dodělat to před 17. říjnem, aby o zavináčích nemusel přednášet.

A také se podíváme na několik žhavých novinek v Nette Frameworku.

Editoval Honza M. (5. 10. 2009 17:17)

Jakub Šulák
Člen | 222
+
0
-

:-)
Tak to se těším, zda se mu to podaří.

Matúš Matula
Člen | 256
+
0
-

ahoj, mam nasledovnu sablonu komponenty

{snippet content}
{if $count > 0}
	{foreach $jokes as $joke}
		{control rating:thumb $joke->rating, $joke->id, $joke->user_rated}
	{/foreach}
{/if}
{/snippet}

sablona subkomponenty rating je obaleny v {snippet} znacke. problemom zrejme je, ze sa program nedostane k prekresleniu komponenty rating, pretoze rodicovsky snippet content nie je invalidovany. signal subkomponenty sa spracuje, akurat sa neprekresli obsah.

Podla vyssie uvedeneho navodu, by to malo fungovat, nie?

Vdaka za odpoved

redhead
Člen | 1313
+
0
-
  1. u ifu a foreache by tak měl být zavináč. //EDIT (tedy uvnitř snipetu ne, ale viz dále)
  2. vnořené snippety bohužel nefungují (viz zde)

Editoval redhead (4. 1. 2010 21:54)

Panda
Člen | 569
+
0
-

K moderátorům: snippety stále nejsou pořádně vyřešené, nestálo by za zvážení klepnout tomuto tématu „sticky“ (zvárazněno)?

Majkl578
Moderator | 1364
+
0
-

Panda napsal(a):

K moderátorům: snippety stále nejsou pořádně vyřešené, nestálo by za zvážení klepnout tomuto tématu „sticky“ (zvárazněno)?

Dobrý nápad, hotovo.

v6ak
Člen | 206
+
0
-

Pro atributy n: (např. n:if) tu asi nejsou zavináče, že?

Jan Tvrdík
Nette guru | 2595
+
0
-

O ničem takovém bohužel nevím.

Majkl578
Moderator | 1364
+
0
-

Pokud je mi známo, zavináčový problém by měl být vyřešen do vydání bety 1.0 (19. září 2010).

na1k
Člen | 288
+
0
-

Co takhle dát tohle téma (odkaz na něj?) jako „sticky“ i do sekce AJAX?

Jan Tvrdík
Nette guru | 2595
+
0
-

Spíš ho chce zahrnout do dokumentace pro Nette 0.9.x-

neznalek
Člen | 60
+
0
-

Co delam spatne kdyz mam:

´@{include $foo}´

A zavinac se mi vykresli pred include?

Editoval neznalek (8. 3. 2011 16:34)

bojovyletoun
Člen | 667
+
0
-

tady 7.10.2009 zavináče se už nepoužívají