Template factory: TODO

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

V Nette by měla být jedna globální template factory jako služba. Pak by bylo snadné například na jednom místě ve vlastní implementaci ITemplateFactory nebo v configu zaregistrovat helpery či makra pro celou aplikaci, což je velmi často potřeba. Nyní je potřeba registraci helperů nebo vlastních maker zařizovat jednak v nějakém BasePresenteru a i v nějaké BaseControle, protože vytváření šablony je někde napraseno ve třídě (asi) PresenterComponent.

Pokud by nějaká komponenta z addonů na tuto službu nechtěla spoléhat, použije DefaultTemplateFactory nebo si implementuje vlastní template factory.

Nemáte někdo chuť to implementovat?

Caine
Člen | 216
+
0
-

+1

David Grudl
Nette Core | 8218
+
0
-

Slovo globální vždycky zavání ;-)

Otázka je, co je to pro „celou aplikaci“. Jednotlivé komponenty určitě žádnou globální factory nechtějí, protože si věci řeší po svém (aby byly přenositelné). Totéž platí pro jednotlivé moduly. Takže spíš jde o to, jak ovlivnit template factory na úrovni modulů + komponent.

Honza Marek
Člen | 1664
+
0
-

Pokud přidáš nějaké helpery/makra do šablony, tak neovlivňuješ přenositelnost komponent, které využívají jen základní funkčnost šablon z nette.

To, že chceš mít k dispozici v celé aplikaci stejně nakonfigurované šablony je strašně častá situace. Nechceš se prostě starat o to, které fičury kde fungují, očekáváš je všude. Nakonec se to hodí i pokud budeš chtít upravit šablonu přenositelného datagridu.

Tu myšlenku bys neměl odsoudit na základě použití slovíčka globální. Máme DI a ty komponenty, které budou chtít jinou template factory ji přes setter nebo konstruktor dostanou.

redhead
Člen | 1313
+
0
-

+1 vždycky mě štvalo vše registrovat v BasePresenteru a v BaseControl.

Eda
Backer | 220
+
0
-

+1 bylo by fajn mít konfiguraci šablon na jednom místě.

Filip Procházka
Moderator | 4668
+
0
-

Proč né tohle? Kdyby se to ještě decánko učesalo, tak to imho splní účel perfektně.

David Grudl
Nette Core | 8218
+
0
-

Jednak by to chtělo přepsat ze šíleného konfiguračního jazyka do normálního PHP, ale především tím $presenter->getContext()->getService('nette.template') se prohlubuje onen „globální problém“.

pawouk
Člen | 172
+
0
-

Slovo globální je zde dle mého použito trochu ve špatném významu. Template factory jako servis ano, ale to přece neznamená že je globální. Nicméně s myšlenkou souhlasím a sám to již dlouhou dobu používám. Občas si třeba potřebuji jen vytvořit template někde mimo tak si prostě vytvářím přez TemplateFactory, což je definované v contextu. Pak jde jen o to přepsat BasePresenter a BaseControl metody createTemplate a je to. Jestli to bude Nette implementovat nebo ne je mi fuk, já to rozhodně budu používat tak jako do ted, což je přes (injektovaný) templateFactory.

pawouk
Člen | 172
+
0
-

@David Grudl:

$presenter->getContext()->getService('nette.template')

Něco mi asi nedochází, tohle jsi vzal kde?

Filip Procházka
Moderator | 4668
+
0
-

Kdybys mi to napsal tam, tak jsem to mohl před čtvrt rokem opravit :) A dneska to předělám.

Milo
Nette Core | 1283
+
0
-

Mě se moc nelíbí, aby se šablony vytvářely na jednom místě a cpalo se do nich úplně vše. Dřív jsem se o to snažil, až jsem jednoho dne kopíroval komponentu se šablonou z jedné aplikace do druhé a hle, najednou mi chybí pár helperů tady a pár maker tam a dopadlo to tak, že jsem zběsile copy-pastoval vše možný.

Mě by se líbilo, kdyby si šablona mohla říct, co chce. To by bylo porno.

{require Nette.urls}
{require Nette.Helpers.bytes}

Editoval Milo (14. 3. 2013 11:58)

Honza Marek
Člen | 1664
+
0
-

Je naprosto logický, že když chceš v šabloně nějaké helpery používat, tak je tam musíš zaregistrovat. To, že bude složitější registrace helperů, aby si lidi radši nic neregistrovali, to přece není řešení :D

Milo
Nette Core | 1283
+
0
-

Honza Marek napsal(a):
Je naprosto logický, že když chceš v šabloně nějaké helpery používat, tak je tam musíš zaregistrovat.

Souhlas :-) Ale při tom kopírování komponenty mi nedošlo, že se helpery registrují jinde. Byly to helpery, které jsem původně psal pro jinou šablonu ale pak se mi hodily i tady.

To, že bude složitější registrace helperů, aby si lidi radši nic neregistrovali, to přece není řešení :D

To byl jen pseudo-příklad. Nejde mi o to, aby se každý helper musel „requirnout“. Jen o to, aby si šablona mohla říct co chce a nečekat, že to tam prostě bude.

David Grudl
Nette Core | 8218
+
0
-

Klíčové je si uvědomit, že generování šablony není služba.

Úkolem komponenty je něco vykreslit. Jak to udělá (přímo HTML, Latte, jiný šablonovací jazyk, atd) je její interní věcí, která musí být imunní vůči prostředí, kde komponenta žije. Konfigurovatelné může být snad jen to, jestli generovat XHTML nebo HTML kód.

pawouk
Člen | 172
+
0
-

Componenta může mít defaultní vytvoření template tak jak má, ale pokud ji nastavíš template, tak se použije to co nastavíš. Stejně jako je Reflection u DB nebo Mailer u Emailu. Což tak defakto je žejo :-) tedy ještě by musela v Control přibýt metoda setTemplate() a neni co řešit…

Sám ovšem generování šablon jako službu používám a jsem s tím spokojen, ikdyž je pravda, že komponenta pak není izolovaná, ale to mě netrápí.

Editoval pawouk (14. 3. 2013 13:26)

Honza Marek
Člen | 1664
+
0
-

David Grudl napsal(a):

Klíčové je si uvědomit, že generování šablony není služba.

Úkolem komponenty je něco vykreslit. Jak to udělá (přímo HTML, Latte, jiný šablonovací jazyk, atd) je její interní věcí, která musí být imunní vůči prostředí, kde komponenta žije. Konfigurovatelné může být snad jen to, jestli generovat XHTML nebo HTML kód.

Máš nějakej lepší nápad jak řešit situaci, že chceš mít ve všech vlastnoručně napsaných komponentách a v presenterech stejně nastavené latte, protože nechceš řešit v rámci jednoho webu kde jaký helper funguje a nefunguje?

Udělat službu TemplateFactory mi přijde jako velmi užitečná věc a ostatně konkurence to tak má

Dále bych upozornil, že by to přispělo k zeštíhlení presenteru z five responsibilities principle na four responsibilities principle. A taky, že bych na to byl schopnej vyrobit pull request tak za hodinu práce, protože to mám celkem rozmyšlené. Nemusíš tedy argumentovat proti jen proto, abys to nemusel programovat ;)

David Grudl
Nette Core | 8218
+
+1
-

Tohle jsou všechno, jeden vedle druhého, nevalidní argumenty.

Pokud chci mít ve všech komponentách a presenterech stejně nakonfigurovanou šablonu, nechám si je všechny vyrobit společnou továrnou.

Přičemž přenositelná komponenta by neměla být závislá na tom, jakou továrnou je vyrobená.

Patrik Votoček
Člen | 2221
+
0
-

David Grudl napsal(a):

Úkolem komponenty je něco vykreslit. Jak to udělá (přímo HTML, Latte, jiný šablonovací jazyk, atd) je její interní věcí, která musí být imunní vůči prostředí, kde komponenta žije. Konfigurovatelné může být snad jen to, jestli generovat XHTML nebo HTML kód.

Nevidím důvod proč by komponenta nemohla dostat informaci (pomoc / vykreslovatko) to jak se má vykreslit z venku.

Viz třeba renderer u formulářů, proč by tohle samé nemohlo být i u „normálních“ komponent?

Pokud chci mít ve všech komponentách a presenterech stejně nakonfigurovanou šablonu, nechám si je všechny vyrobit společnou továrnou.

Což momentálně nelze jinak než si udělat BasePresenter a BaseControl ve kterých bude stejný copy-paste kód. (Nebo se pletu?)

A to je imho to o co tady jde.

David Grudl
Nette Core | 8218
+
0
-

Copy-paste není potřeba, může tam být volání stejné factory.

A co tady jde, je použití globálna. Beru řešení, které nepoužije static, global nebo $context. Tj. něco, co je čistější, než současné nedokonalé řešení. Thats all.

Honza Marek
Člen | 1664
+
0
-

Nevidím důvod, proč by mělo být použito static, global nebo $context.

David Grudl
Nette Core | 8218
+
0
-

Aha, tak pak není co řešit, rád tvůj pull request mergnu.

Honza Marek
Člen | 1664
+
0
-

Z téhle rozdělané větve by mělo být zřejmé, jak to celé myslím – https://github.com/…late-factory

K mergnutelnosti chybí poladit nette extension a vyrobení testů.

Má smysl, abych pokračoval?

Tomáš Votruba
Moderator | 1114
+
0
-

Ping. Pro mne
Zatím to vypadá dobře. Jaké máš ještě plány? Už je to nějak použitelné? Budu rád za příklad.

David Grudl
Nette Core | 8218
+
0
-

Problém je v tom $templateFactory = $this->templateFactory ?: $this->getPresenter()->getTemplateFactory();.

Pokud si změním v aplikaci výchozí template factory, přestanou být komponenty přenositelné.

Honza Marek
Člen | 1664
+
0
-

Nesouhlasím.

Pokud někdo bude měnit template factory, bude to dělat z důvodu, aby rozšířil její funkčnost. Pokud tedy komponenta bude používat základní podmnožinu maker, helperů atd., tak nebude problém. Pokud bude komponenta potřebovat něco speciálního, stejně si musí šablony řešit po svém, takže ani tady změna nebude.

Ano, čistě hypoteticky si někdo může vyrobit template factory, která bude třeba používat Twig místo Latte. Pokud se ale do něčeho takového pustí, jistě zvládne i zavolat setter na template factory u té přenositelné komponenty.

David Grudl
Nette Core | 8218
+
0
-

Pokud tedy říkáš, že

  • template factory slouží k rozšíření funkčnosti
  • ale komponenty se to nedotkne, protože ta bude využívat základní sadu,

vyplývá z toho zbytečnost navrhované úpravy.

Honza Marek
Člen | 1664
+
0
-

Cyklíme se!

  1. Existují i nepřenositelné komponenty fungující jen v jedné konkrétní aplikaci.
  2.  

    Honza Marek napsal(a):

    Nakonec se to hodí i pokud budeš chtít upravit šablonu přenositelného datagridu.

enumag
Člen | 2118
+
0
-

@dg: Zbytečné to není, CompilerExtension tím získá několik možností navíc:

  1. Přidávání helperů do šablony.
  2. Přidávání vlastních proměnných do šablony, tyto proměnné pak mohou používat makra, které to extension registruje. Nyní když ve vlastním makru potřebuji nějakou službu, musím po uživateli chtít aby mi tu službu předal do šablony jako proměnnou nebo v makru použít $_presenter->context->getByType(...).

Dle mého názoru je primárním účelem služby templateFactory právě možnost rozšíření přes CompilerExtension, nikoli možnost kompletní výměny templateFactory. Např. mohu mít addon který pomocí CompilerExtension zaregistruje makra a helpery, které pak bude používat komponenta z toho addonu – tj. komponenta bude přenositelná společně s tím extension, protože extension zařídí její závislosti.

Honza Marek
Člen | 1664
+
0
-

enumag napsal(a):

  1. Přidávání vlastních proměnných do šablony, tyto proměnné pak mohou používat makra, které to extension registruje.

Ideální stav u vlastních maker by byl takový, že makro je objekt a referenci na potřebnou službu už má v sobě.

Filip Procházka
Moderator | 4668
+
0
-

Problém je v tom, že makro se ti spouští jenom a pouze při komplikaci a když potřebuješ nějaké závislosti runtime, tak je tam přes makro těžko dostaneš :)

enumag
Člen | 2118
+
0
-

@Honza Marek: Přesně jak říká Filip, nejde o závislosti které jsou pořeba při kompilování latte → PHP, ale o závisloti které makro potřebuje při spuštění výsledného PHP kódu. Makro jako objekt vůbec nic neřeší protože i ten bys musel nějak dostat do té šablony, což jsme tam kde jsme byli.

sifik
Člen | 27
+
0
-

Nadruhou stranu se musí „globálnímu“ template factory nechat, že je to docela dost velká úspora času.

Když jsem na jeden ze svých projektů naimplementoval postup, který je detailně popsaný zde – https://forum.nette.org/…-pres-config, na content loadu jsem ušetřil více jak 100ms.

Felix
Nette Core | 1196
+
0
-

Zdravim, chtel jsem se jen zeptat jestli se s tim tedy pocita nebo ne? Pripadne kdy to bude ;-) Cela myslenky templateFactory se mi libi a je IMHO velkym prinosem.

Editoval Felix (26. 8. 2013 12:26)

Honza Marek
Člen | 1664
+
0
-

Kdeže, David si z neznámého důvodu myslí, že všechny controly by si měly nastavovat šablony samy. Ne, že by se to mělo umožnit, ale že by se to mělo vynutit. Myšlenka template factory jako služby jde bohužel proti tomu :)

enumag
Člen | 2118
+
0
-

@Honza Marek: Brání nám něco v tom udělat to jako extension s traitami pro presenter a control? :-)

Pokud jde o přenositelnost komponent tak to řeší CompilerExtension distribuované společně s komponentou (viz zde) mnohem lépe imho. Rád bych znal Davidův názor na tuto možnost, ale bohužel se zatím nevyjádřil.

mishak
Člen | 94
+
0
-

Podobný problém řeším s rixxi/template-factory a rixxi/template-locator. Nejspíš o nich nevíte, ale než se dokopu napsat dokumentaci vyřeší se to v Nette :)

Editoval mishak (6. 1. 2014 21:01)

enumag
Člen | 2118
+
0
-

@mishak: Bez Extension ta TemplateFactory není zajímavá (alespoň pro mne). TemplateLocator je tady mimo téma.

Tomáš Votruba
Moderator | 1114
+
0
-

@enumag: TemplateFactory jako extension – Zenify/TemplateFactory

Prosím pouze o podněty ke zlepšení. Díky.

enumag
Člen | 2118
+
0
-

@Tomáš Votruba:

Undefined $this->paramService: https://github.com/…eFactory.php#….

Imho jsou lepší konstanty ve tvaru TAG_*: https://github.com/…xtension.php#….

Konfigurace extension imho není nutná když se totéž dá udělat pomocí tagů (a ty jsou zde vhodnější).

Myslím že by to mělo jít bez DIC, jen s předáním polí služeb + ITranslatoru (ten by měl povoleno NULL): https://github.com/…eFactory.php#….

Zde bych použil protected: https://github.com/…eFactory.php#….

Imho by to nemělo chtít Control, vytvořit šablonu potřebuju třeba i pro e-mail: https://github.com/…eFactory.php#L54, tzn. parametry ať si doplní Control/Presenter – v tvém případě TTemplateFactory trait. Že presenter / control pro vytvoření e-mailu stejně potřebuji kvůli odkazům není platný argument, generování odkazů by též mělo být služba.

Přemýšlím že by to mohla být generovaná továrna, ale na to by možná byly potřeba nějaké úpravy v Nette DI.

Tomáš Votruba
Moderator | 1114
+
0
-

@enumag: Díky za přehledný feedback. OK: 1. layouts, 2. tagy, 3. konfigurace, 5. protected, viz změny,

4. (pole služeb) Tedy předat nette.templateCacheStorage, Nette\Http\IResponse, Nette\Caching\IStorage, Nette\Http\IRequest a Nette\Localization\ITranslator přes constructor, je tak?

6. (ne control) Zkusil jsem přesunout. Mohl bys mi případně ukázat konkrétní návrh?

7. (generovaná továrna) Zkoušel jsem, ale neuspěl.

enumag
Člen | 2118
+
0
-

@Tomáš Votruba:

4. Myslel jsem pole filtrů, helper loaderů a maker, ale neuvědomil jsem si že těch závislostí je tolik. Tzn. to co jsi uvedl bude lepší. Službu nette.templateCacheStorage bude nutné předat ručně v extension, v parametrech bude tedy první. Ostatní stačí přes autowiring, ITranslator bude poslední a s NULL.

6. Tohle souvisí ještě s jednou věcí – bylo by fajn aby cizí extension mohlo vynutit přítomnost určité služby v šabloně, aby tu službu mohlo používat nějaké makro definované stejným extension. Ještě jsem úplně nevymyslel kudy na to.

7. Ok, chápu.

Když tak koukám na 4 a 6 tak spolu vlastně taky souvisí, pokud by se 6 podařilo elegantně vyřešit tak TemplateFactory ubydou některé závislosti.

Editoval enumag (5. 2. 2014 13:30)

enumag
Člen | 2118
+
0
-

ad 6) Přemýšlím nad něčím typu ITemplateConfigurator, kterých by bylo více (přidávány pomocí tagu) a ta TemplateFactory by novou šablonu prohnala těmito službami. Ten konfigurátor by mohl vypadat asi takto:

class TranslatorTemplateConfigurator implements ITemplateConfigurator
{
	private $translator;

	public function __construct(ITranslator $translator = NULL) { ... }

	public function configureTemplate(ITemplate $template) {
		$template->translator = $this->translator;
	}

}

Považujete to za dobrou cestu nebo za blbost?

EDIT: Pozn. šablona by imho vůbec neměla mít metodu setTranslator, ten helper by se přidal jinak.

EDIT2: Možná by se všechno (filtry, helpery, makra) mohlo přidávat skrz tyhle služby. TemplateFactory by pak jako jedinou závislost měla pole těch konfigurátorů a možná templateCacheStorage.

EDIT3: A ještě jedna střela od boku, možná úplná blbost – připravit jednu šablonu interně v té továrně a poté vracet klony.

Všechno co tu teď píšu jsou momentální nápady nad kterými jsem zatím moc nepřemýšlel tak to berte s rezervou. ;-)

Editoval enumag (5. 2. 2014 13:52)

Tomáš Votruba
Moderator | 1114
+
0
-

@enumag: Jsi rychlý jak blesk.

4. Takto nějak?

6. To už je na mne moc složité, nechám na ostatních.

+8. Ještě zvažuji dekompozici metod uvnitř factory. Už teď je to pro mne nepřehledné. Něco jako setupMacros(), setupHelpers(), setupFilters(), setupControl(), setupPresenter() a setupPaths().

David Matějka
Moderator | 6445
+
0
-

@enumag: tohle vypada jako reseni :) zavislosti, helpery apod. by se pridavaly dobre, komplikovanejsi by to bylo s makrama.. ale to by se snad nechalo vyresit…

edit: nebo co takhle pridavat makra pres compiler extension? podobne jako to kdyby resi treba s IDatabaseTypeProvider ?

Editoval matej21 (5. 2. 2014 14:01)

David Matějka
Moderator | 6445
+
0
-

@Tomáš Votruba: user by taky nemusel byt zavisly na presenteru, nechal by se klasicky injectnout Nette\Security\User

enumag
Člen | 2118
+
0
-

@Tomáš Votruba:

4. Ano, takto.

8. Konfigurátory, které navrhuji by to asi vyřešily lépe.

Jsi rychlý jak blesk.

Jo, někdy až příliš… Mluvím/píšu dříve než si to stihnu promyslet.

@matej21:

Jo, makra to trochu komplikují… tam bude asi lepší ten provider jak píšeš.

Se službou User máš samozřejmě pravdu, nevšiml jsem si. :-)

Nějak se vracím ke 3 dny starému závěru – to RFC na TemplateFactory budu muset stejně napsat. :-D

Editoval enumag (5. 2. 2014 14:04)

Tomáš Votruba
Moderator | 1114
+
0
-

@matej21: User přesunut

Registrace maker je v poho, stačilo přidat Nette\Latte\Compiler.

Osobně bych byl spokojen, kdyby v šablonách pro presenter, komponentu a email fungovaly helpery, makra a odkazy n:href a {link Presenter:action}.


Napadá mne, že i presenter lze injectnout. Tím by tato továrničky byla zcela nezávislá.

public function __construct(Nette\Application\Application $application)
{
	$this->presenter = $application->getPresenter();
}

Teď to nechám chvíli vychladnout. Stále prosím zkuste přicházet s konkrétními návrhy, lépe pull-requesty.

David Matějka
Moderator | 6445
+
0
-

@Tomáš Votruba:

Registrace maker je v poho, stačilo přidat Nette\Latte\Compiler.

jako kam? jestli do ITemplateConfigurator, tak rozhodne ne. sablona by nemela byt tolik zavisla na latte, krom toho se latte kompilace neprovadi tolikrat a ve stejnou dobu jako vytvareni sablony atd. jedine jako samostatnou sluzbu, ILatteConfigurator, ktery by se staral o registraci maker

Napadá mne, že i presenter lze injectnout. Tím by tato továrničky byla zcela nezávislá.

kdyz bezi aplikace, muze projit nekolika presenterama, at uz proste obycejny error presenter, nebo rucni zmena pomoci ->forward() apod. takze by se minimalne musel vytahovat ten presenter vzdy pri vytvareni sablony. ale stejne jsem proti tomu :) az se refaktoruje generovani linku a vytvori se pro to samostatna sluzba, nebude potreba dostavat presenter do kazdy sablony

enumag
Člen | 2118
+
0
-

@Tomáš Votruba: Takhle sice předáš Presenter, ale už ne Control.