Macro {embed} a scope proměnných

CliffhAnger
Člen | 3
+
0
-

Nějak jsem asi nepochopil, k čemu je vlastně dobrý makro embed. Z dokumentace člověk nabyl dojmu, že se jedná o mechanismus k řešení podobných problémů, které bych např. ve Vue řešil pomocí tzv. slotů. Zde jsem ale asi úplně mimo, protože ačkoliv mám pocit, že to má řešit podobný use-cases (a to především i díky příkladu v dokumentaci), tak ve finále je to na takové případy těžko použitelné, a to kvůli jedné jediné věci, a tou je rozsah platnosti proměnných. Možná něco dělám blbě, ale spíš asi ne, a tak se chci zeptat, proč je to naimplementováno zrovna tak, jak to je a proč to není tak, jak bych očekával já.

Příklad:

{* Soubor importující a embedující nějaký blok. *}

{var $promenna = 25}

{embed nejakyBlok, promenna: 35}
	{block prepisovanyBlokUvnitrEmbedovanehoBloku}
		{$promenna} {* Hodnota je 35 místo 25 ...proč? *}
	{/block}
{/embed}

Tohle chování mi přijde jako solidní prostor pro hodně divný bugy, který vzniknou pokaždý, pokud se někdo, kdo vytvořil definici embedovaného bloku, rozhodne, že nějakou svoji dočasnou proměnou (uvnitř tý svojí definice) pojmenuje úplně stejně, jako já svojí proměnnou v šabloně, kde chci otevřenou část (přepisovaný blok) týhle definice přepsat. Tohle chování mě už párkrát pěkně kouslo a chtěl bych tak vědět, proč se to chová zrovna takhle, protože to je přesnej opak toho jak se v podstatě standardně chovají snad všechny běžně používáné programovací jazyky.

m.brecher
Generous Backer | 757
+
0
-

@CliffhAnger

solidní prostor pro hodně divný bugy, který vzniknou pokaždý, pokud se někdo, kdo vytvořil definici embedovaného bloku, rozhodne, že nějakou svoji dočasnou proměnou (uvnitř tý svojí definice) pojmenuje úplně stejně, jako já svojí proměnnou v šabloně

Ahoj, zajímavý postřeh, moc embedy nepoužívám, a tak jsem si to vyzkoušel. Jak máš ten příklad, tak to opravdu funguje tak, že se do definice bloku, který se vkládá tagem {embed} do kostry přednostně předá proměnná zapsaná v tagu {embed} a přepíše proměnnou, která se deklaruje MIMO vkládaný blok někde v hlavní šabloně.

Když jsem si ale napsal kód jak popisuješ s použitím lokální proměnné ve vkládaném bloku UVNITŘ toho bloku, tak to funguje jak potřebuješ – lokálně deklarovaná proměnná uvnitř tohoto bloku se NEPŘEPISUJE proměnnou stejného jména, která se předává v tagu {embed} – viz příklad:

kostra šablony sample.latte:

    <p>{$variable}</p>
    {block 'myBlock'}{/block}

aplikace {embed}:

    {embed $appDir.'/templates/sample.latte', variable: 'passed-variable'}  // předávaná proměnná
        {block 'myBlock'}
            {var $variable = 'local-variable'}  // lokální proměnná v bloku stejného jména
            <p>{$variable}</p>
        {/block}
    {/embed}

Výsledek je správně jak potřebujeme – lokální proměnná se nepřepisuje :)

<p>passed-variable</p>
<p>local-variable</p>

Takže to chce definovat lokální proměnnou používanou v bloku uvnitř toho bloku a problém je vyřešen.

Editoval m.brecher (11. 2. 2023 15:33)

CliffhAnger
Člen | 3
+
0
-

@m.brecher

Takže to chce definovat lokální proměnnou používanou v bloku uvnitř toho bloku a problém je vyřešen.

No pokud se jedná o nějakou konstantní hodnotu tak to asi lze takto udělat, jenže pokud mám třeba parametr šablony se stejným názvem jakej má nějaká proměnná uvnitř embedovaného bloku, tak jsem nahranej, protože konkrétní hodnotu toho parametru neznám a není tak možné takovou proměnnou redeklarovat.

Jako jediný řešení, který mě momentálně napadá, je nějakej naming pattern pro ty parametry, který se předávaj do šablony – že se jim dá nějakej prefix nebo budou začínat velkym písmenem nebo tak něco, aby se šance kolize názvu minimalizovala na úplný minimum.

David Grudl
Nette Core | 8129
+
0
-

proč je to naimplementováno zrovna tak, jak to je a proč to není tak, jak bych očekával já

Není v tom žádný záměr, jednoduše jsi první, kdo přišel s tím, že by měla být deklarovaná proměnná dostupná uvnitř embed. Implementovat by to šlo, jen by to znamenalo BC break.

Martin Dřímal
Člen | 16
+
+1
-

Za mě očekávané chování :) Kdyby tam bylo 25, místo explicitně předaných 35, hledal bych, kde mám chybu..

m.brecher
Generous Backer | 757
+
0
-

@CliffhAnger

jenže pokud mám třeba parametr šablony se stejným názvem jakej má nějaká proměnná uvnitř embedovaného bloku, tak jsem nahranej, protože konkrétní hodnotu toho parametru neznám

To máš pravdu. I z hlediska praktičnosti použití embed to nedává smysl, aby proměnná předávaná v tagu {embed} do kostry mohla současně přepisovat proměnnou stejného jména v předávaném bloku. Tuto proměnnou použije vývojář v kostře a vkládaný blok s tím velmi pravděpodobně souviset nebude.

Editoval m.brecher (12. 2. 2023 13:11)

CliffhAnger
Člen | 3
+
0
-

Martin Dřímal napsal(a):

Za mě očekávané chování :) Kdyby tam bylo 25, místo explicitně předaných 35, hledal bych, kde mám chybu..

Jenže jde o to kam. Je to explicitně předáno do embedovaného souboru/definice a ten parametr slouží k nějaké logice uvnitř tohoto souboru/definice. Jenže při embedování se snažím ovlivnit jednu nebo více částí, které jsou pro tento účel explicitně určeny vývojářem, který se stará o ten embedovaný soubor/definici a já bych se neměl starat o to, jaký všechny proměnný tenhle vývojář používá tak, aby náhodou nedošlo ke kolizi názvu. Já jen předávám vlastní implementaci pro určitou část, kterou mi on sám explicitně zpřístupnil pomocí pojmenovaného bloku a jediný, o co bych se měl starat, je název toho bloku (to je veřejné API pro embedovanou část + samozřejmě parametry, které mohu nebo musím předat do embedovaného souboru/definice).

Pokud bych měl mít při přepisování toho bloku přístupny nějaké proměnné z embedovaného souboru/definice, tak by to muselo být explicitně uvedeno uvnitř tohoto embedovaného souboru/definice tak, aby se to stalo součástí veřejného API danýho souboru/definice. V ideálním případě bych pak měl mít možnost si určit svůj vlastní název pro ty zpřístupněný proměnný (v místě přepisování toho přepisovanýho bloku) tak, abych se mohl vyhnout kolizím názvů. Je to v podstatě stejný způsob, jakým to funguje (pokud zůstaneme u PHP) například s použitím lambda funkcí, které předávám do nějaké funkce/metody, což je z mého pohledu (z pohledu uživatele danýho API) přesně to, čeho se s použitím tohodle makra snažím docílit.

Příklad ideálního stavu (z mého pohledu):

{* Soubor, který obsahuje embedovanou definici. *}

{define embedovanaDefinice, $promenna}
	{var $promenna2 = $promenna + 10}
	{var $promenna3 = $promenna + 20}

	{block prepisovanyBlok, $promenna, $promenna2}{/block}
{/define}
{* Soubor, ve kterém chceme přepsat blok z výše uvedené definice. *}

{import souborUvedenyVyse}

{var $promenna = 25}

{embed embedovanaDefinice, promenna: 35}
	{block prepisovanyBlok, $vnitrniPromenna, $vnitrniPromenna2}
		{$promenna} {* Vypíše 25. *}
		{$vnitrniPromenna} {* Vypíše 35. *}
		{$vnitrniPromenna2} {* Vypíše 45. *}
		{$promenna2} {* UNDEFINED *}
		{$promenna3} {* UNDEFINED *}
	{/block}
{/embed}

Editoval CliffhAnger (13. 2. 2023 8:32)