Sablony – ako dostat definovanu premennu do nadradenej vrstvy?

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

Ahojte,

narazil som na problem, ako dostat definiciu premennej do „nadradenej vrstvy“. Asi nie je vylucene, ze som objavil BUG, alebo prinajmensom nedokumentovanu feature… Tento problem sa prejavuje vo verzii 0.9.2 (Stable).

Problem:

ako dokazem definovat premennu vnutri bloku/includovanej sablony tak, aby bola vidiet v „nadradenom celku“ (ktorym moze byt nadradeny blok, ktory includuje dany blok alebo sablonu, alebo na najvyssej urovni sablona @layout.phtml)?

Problem skusim ilustrovat opat na drobne upravenom Skeletone, ktory je v distribucii Nette:

Pri zobrazeni homepage stranky sa pouziva takato hierarchia:

@layout.phtml
 +-> Homepage/default.phtml
      +-> (block #content}

V sablone @template.phtml sa v hlavicke testuje definovanost premennej $robots

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

Kazdy logicky ocakava, ze premennu $robots mame moznost si definovat v sablone view a podla jej hodnoty sa potom upravi vygenerovane HTML zo sablony @layout-u – co je prave ona problematicka funkcionalita „spristupnenia premennej v nadradenom celku“. Presne toto ocakavane chovanie sa vyuziva napr. v sablone Error/404.phtml, kde sa nachadza kod:

{assign robots => noindex}

V tomto pripade to nejakym sposobom funguje, problemom je, ze to funguje len obcas a nie vo vsetkych (beznych) situaciach.

Skusme teda preskumat, za akych okolnosti tato funkcionalita funguje a za akych nie. Pridame teda deklaraciu {assign ...} na zaciatok subora Homepage/default.phtml a otestujme, kedy sa nam spravne vo vygenerovanej stranke objavi pozadovany meta-noindex tag.

varianta 1:

{* sablona Homepage/default.phtml *}

{assign robots => noindex}

{block content}
<div id="header">
	<h1>It works!</h1>
...

Vysledok: funguje.

varianta 2:

{* sablona Homepage/default.phtml *}

{block content}
{assign robots => noindex}

<div id="header">
	<h1>It works!</h1>
...

Vysledok: nefunguje

varianta 3:

Definujme subor include.phtml s obsahom:

{* sablona Homepage/include.phtml *}

{assign robots => noindex}
Toto je includovany obsah zo suboru include.phtml

a v subore default.phtml majme:

{* sablona Homepage/default.phtml *}

{include include.phtml}
{block content}
<div id="header">
	<h1>It works!</h1>
...

Vysledok: nefunguje

varianta 4:

Majme subor include.phtml ako v predoslom kroku a v subore default.phtml majme:

{* sablona Homepage/default.phtml *}

{block content}
{include include.phtml}

<div id="header">
	<h1>It works!</h1>
...

Vysledok: nefunguje

Pre uplnost este uvediem, ze „spristupnenie premennej v nadradenom celku“ funguje aj pre retaz dedicnosti, pokial je dana premenna definovana v „roote“ danej sablony (tj. mimo akykolvek blok alebo includovany subor).

Vypozorovany zaver: zda sa, ze spristupnenie premennej je blokovane ‚prechodom‘ cez blok alebo cez include.

Preto moj dotaz znie – ako sa da definovat globalna premenna, ktoru mozem definovat na akejkolvek urovni v bloku alebo v includovanom subore tak, aby bola dostupna na vsetkych urovniach (specialne teda aj v najvyssej urovni v @layout.phtml)?

Vopred diky za rady, lamal som si hlavu nad tym niekolko hodin, v dokumentacii ani na fore som k tomu ziadnu radu nenasiel (ale mozno som len nevedel, co presne mam hladat).

Ondřej Mirtes
Člen | 1536
+
0
-

Jednoduše: V jakémkoli Presenteru.

Podle mě se to chová dle očekávání – pokud zavoláš assign uvnitř block #content, tak je k dispozici jen uvnitř block #content.

K tomu, co chceš ty, přesně v šablonách slouží samotné blocky.

{* @layout.phtml *}
<meta name="robots" content="{block #robots}index,follow{/block #robots}">
{* Homepage.default.phtml *}
{* Změní se obsah meta tagu robots *}
{block #robots}index,nofollow{/block}
{block #content}
...
{* Homepage.default.phtml *}
{* Změní se obsah meta tagu robots v layoutu a zároveň se vypíše do contentu v šabloně*}
{block #content}
{block #robots}index,nofollow{/block}
...

Doporučuju přednášku o nových šablonách.

Editoval Ondřej Mirtes (18. 12. 2009 11:14)

falkon
Člen | 17
+
0
-

To ale nefunguje v includovanych sablonach, ktore obsahuju fragment HTML kodu, ktory sa includuje dovnutra ineho bloku.

Priklad:
v sablone A definujem blok #content, ktory je vyzadovany v @layout.phtml.

{* A.phtml *}

{block #content}
	bla bla bla...
	{include 'B.phtml'}
....

V pripade, ze sablona B.phtml rozhodne, ze potrebuje definovat robots s hodnotou noindex, tak to nema ako vyjadrit. Nemozem tam definovat {block #robots}{/block}, pretoze by bol vnoreny (ale ja pritom nechcem jeho obsah vypisat na aktualne miesto) a je vnoreny v bloku #content. Obecne, sablona B.phtml nevie, kde vsade bude includovana – ona len vie, ze zobrazuje nejaky obsah, ktory nechce, aby bol zaindexovany, tak potrebuje nastavit blok/premennu robots.

Ano, v prezenteri by nejaka premenna nastavit sla, do ktorej si budu sablony sahat, ale mne tato varianta neprisla priliz ‚cista‘, pretoze Presenter apriori nevie, ktore vsetky premenne budu sablony potrebovat… jedina moznost je definovat uplne vsetky taketo ‚globalne premenne‘ v BasePresenteri, aby boli dostupna vsade… co ale nepovazujem za vhodne riesenie :(

Preto by som rad zistil sposob, ako to rozfungovat aj napriec blokmi, nie len napriec @layout ↔ ‚root oblastou view sablony‘. Najma, ked presne tento mechanizmus uz funguje (bohuzial ale len na obmedzenej podmnozine pripadov).

So, any other idea?

redhead
Člen | 1313
+
0
-

Možná si špatně pochopil blocky. Ono totiž pokud ho jednou definuješ pod nějakým názvem a poté v jakékoliv jiné šabloně (jakoliv hluboko vnořené) se ten block dá přepsat (stejným způsobem jako při definici), ale nevypíše se na to místo kde je uveden, ale na to místo kde byl poprvé definován.

falkon
Člen | 17
+
0
-

No tento princip myslim chapem – problemom je, ze sa neda(?) (pre)definovat blok X vnutri ineho bloku Y.
Priklad:

@layout.phtml:

...
{block #blockForOverride}defaultny obsah - ma byt predefinovatelny v sablone{/block}
...
{include #content}
...

default.phtml:

{block #content}
 ... nejaky obsah na zaciatku ...

  {block #blockForOverride}
	TU by som chcel predefinovat obsah bloku #blockForOverride
	(pripadne vyuzit {include #parent}, to je fuk)
  {/block}

... nejaky obsah na konci ...

Tak toto sa sprava tak, ze sice obsah bloku #blockForOverride sa prepise (funguje aj {include #parent}), ale obsah bloku sa zobrazi na tom mieste medzi ... nejaky obsah na zaciatku ... a ... nejaky obsah na konci ....

Druha varianta, ked to bude refaktorovane pomocou {include }, nefunguje vobec:

@layout.phtml:

...
{block #blockForOverride}defaultny obsah - ma byt predefinovatelny v sablone{/block}
...
{include #content}
...

default.phtml:

{block #content}
 ... nejaky obsah na zaciatku ...

  {include 'include.phtml'}

... nejaky obsah na konci ...

a include.phtml:

[ toto je obsah na zaciatku include.phtml ]

  {block #blockForOverride}
	{include #parent}
	TU by som chcel predefinovat obsah bloku #blockForOverride
  {/block}

[ toto je obsah na zaciatku include.phtml ]

Pokus pouzitia {include #parent} sposobi vynimku: Call to undefined parent block 'blockForOverride'. Bez {include } direktivy sa to sice skompiluje, ale robi to nieco uplne ine:

  • blok #blockForOverride v sablone @layout.phtml zostane s povodnym obsahom
  • obsah bloku #blockForOverride v include.phtml sa vlozi medzi [ toto je obsah na zaciatku include.phtml ] a [ toto je obsah na zaciatku include.phtml ].
Ondřej Mirtes
Člen | 1536
+
0
-

To, co chceš ty, asi nepůjde. Řešením by bylo asi uvádět {block #robots}index,follow{/block} v šabloně (nad block #content), do které teprv includuješ sablonaB.phtml.

redhead
Člen | 1313
+
0
-

Možná to pude, zkoušel sis hrát ještě s makrem extends?

{*nějaká includovana sablona*}

{extends $layout}

{block #blockForOverride}předefinujeme{/block}

obsah šablony, bla, bla
falkon
Člen | 17
+
0
-

To sa sprava uplne nejak divne… uplne inak, nez by clovek predpokladal.

Ale skusme sa vratit k povodnej otazke: da sa nejak definovat globalna premenna v sablone? (globalna napriec vsetkymi pouzitymi sablonami v danom zivotnom cykle requestu)

Ak ano, ako? Ak nie, preco? Je to BUG alebo feature?

despiq
Člen | 320
+
0
-

co

{? $presenter->template->promenna = 'sdfsdf'}

to by me zajimalo co to vyhodi za error :D

Editoval despiq (18. 12. 2009 23:46)

Filip Procházka
Moderator | 4668
+
0
-

despiq napsal(a):

{? $presenter->template->promenna = 'sdfsdf'}

No fuj :D

Editoval HosipLan (19. 12. 2009 13:21)

redhead
Člen | 1313
+
0
-

Hele, mám trochu pocit, že to teď David commitnul:

https://github.com/…f69affed9f6b