Šablonové helpery v Nette – umístění v MVC

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

Ahoj, už delší dobu mě trápí takový menší návrhový problém :-)

Jde o MVC a o zařazení helperů pro šablony. Princip říká, že vše, co se týká vykreslování (Jak se data, která dostávám z presenteru, zobrazí?) patří do vrstvy View. Šablonové helpery tedy jednoznačně patří do vrstvy View – jen upravují, jak se data zobrazí. Proč tedy musím kvůli helperům psát nějaký kód do presenteru, kde podle principu MVC nepatří?

Příklad

Dělám jednoduchý katalog produktů, kde mi stačí cenu zobrazit jako klasické číslo. V šabloně Products/list.latte tedy budu mít klasicky {$product->price}.
Za měsíc přijde zákazník, že chce ceny zobrazovat hezky, oddělené tečkami, zaokrouhlené, na dvě desetinná místa a v případě celých korun s pomlčkou (10.000,- Kč). Jde jen o úpravu zobrazení (v MVC vrstva View), přesto ale musím sahat do presenteru, vytvářet nový helper price a v presenteru ho registrovat. O další měsíc později třeba může přijít, že mu konkurence strojově kopíruje ceny produktů, a že chce cenu vypsat jako obrázek :-) Zase další zásah do aplikace na místě, které by se editovat vůbec nemělo (Presenter).

Řešení

Řešení vidím v latte makru {helpers}. Ve složce app/templates/ by si programátor vytvořil třeba soubor Helpers.php se třídou Helpers. Ta by obsahovala helpery. V šabloně (třeba i v layoutu) by pak programátor napsal jen

{helpers 'price' => 'Helpers::price', 'anotherHelper' => 'Helpers::anotherHelper'}
{$product->price|price}

<!-- nebo -->

{helpers 'Helpers.php'}
{$product->price|Helpers::price}

Při potřebě přidat do šablon nový helper by se editovala opravdu jen složka app/templates/ a do presenterů by se nemuselo vůbec šahat.

Co si o tom myslíte? Jde o návrh na vylepšení Nette, nebo jen o mé špatné/jiné pochopení MVC? Díky za názory.

Editoval xxxObiWan (14. 8. 2011 13:50)

pepakriz
Člen | 246
+
0
-

Tímto jsem se také zabýval. Ve Venne jsem se dokonce pokoušel o lazy loading helperů a maker. Bylo to funkční, ale bohužel jedna úprava zasahovala do protected metody a proto jsem se rozhodl lazy loading vyhodit a nahradit ho něčím podobným jak ukazuješ.

Editoval pepakriz (14. 8. 2011 14:59)

Mikulas Dite
Člen | 756
+
0
-

Moc se mi to nezdá. Zkus to implementovat, použít a uvidíš jestli je to dobrý.

Každopádně když stejně mám ty helpery v nějakém řekněme Helpers.php, tak nemusím do presenteru šahat, přestože bulk registrace tam proběhne. Tzn. ty chceš jenom přesunout tuhle jednu řádku z presenteru do šablony:

public function templatePrepareFilters($template) {
	Helpers::register($template);
}

když klient bude chtít upravit makro nebo přidat, šáhnu do Helpers.php.

{helpers callback('Helpers', 'register)}

kdyby to makro přijímalo soubor, tak to bude načítat moc složitě, přes třídu je to snažší.

Filip Procházka
Moderator | 4668
+
0
-

Mi se to nelíbí. To bych jako do každé šablony musel psát jaké funkce v ní budu používat? No to chudák kodér.

Udělej si raději lazy načítání helperů, jak to nyní má Nette.

nanuqcz
Člen | 822
+
0
-

Mi se to nelíbí. To bych jako do každé šablony musel psát jaké funkce v ní budu používat? No to chudák kodér.

Stačí jednou, do @layout.latte, ne?

EDIT:

Udělej si raději lazy načítání helperů, jak to nyní má Nette.

To pořád nic nemění na tom, že podle mě problém „Načtu helper? Nenačtu helper?“ patří do vrstvy View. Stejně, jako se v Nette kdysi logika „Použiju layout? Nepoužiju layout?“ přenesla z presenterů do šablon (vzniklo makro {extends}), patří podle mě i načítání helperů do šablon.

Editoval xxxObiWan (14. 8. 2011 15:36)

nanuqcz
Člen | 822
+
0
-

Mikulas Dite napsal(a):

{helpers callback('Helpers', 'register)}

kdyby to makro přijímalo soubor, tak to bude načítat moc složitě, přes třídu je to snažší.

To se mi líbí :-) Jen mě napadl problém, v mojem CMS fungují šablony v podsložce (app/templates/default/, app/templates/beautiful_skin/, …). A pokud by v každém skinu byl soubor se třídou Helpers, tak by mohla nastat kolize. Takže třeba

{helpers callback('Helpers', 'register), 'Helpers.php'}  <!-- nepovinný druhý parametr, cesta relativní vzhledem k umístění šablony -->

Editoval xxxObiWan (14. 8. 2011 15:41)

Tharos
Člen | 1030
+
0
-

IMHO ten výklad MVP v úvodním příspěvku není úplně přesný. :) Presenter vrstva přece deleguje view vrstvu. Presenter nastavuje soubor šablony, proměnné šablony a to vše se bere jako legitimní aktivita. Nastavení helperů mně osobně z toho svým charakterem nijak nevybočuje.

Vem si třeba takovou komponentu Webloader. Ta by podle toho výkladu byla celá špatně, protože proč máme řešit připojené CSS soubory někde v Presenteru? Zde je to podle mě ještě křiklavější a ano, zde uznávám, že teoreticky je to skutečně už na hraně.

Jak to vidím já osobně… Třída Nette\Templating\Template je již součástí view vrsty, přestože se s ní pracuje v Presenteru. Jedná se právě o to „delegování“, „inicializování“, anebo jak bych to nazval. A jelikož se helpery registrují právě v této třídě, považuji to za naprosto legitimní. To, že změna view vrstvě může vyžadovat zásah do Presenter vrstvy nemusí být nutně špatně. Stejně tak změna v modelové vrstvě může vést i k zásahu do Presenterů (například při změně API modelu) a taky to nemusí být chyba.

To, co navrhuješ, by IMHO vedlo k „programování v šablonách“ a to by mně osobně vadilo nejvíce. :)

Editoval Tharos (14. 8. 2011 15:52)

22
Člen | 1478
+
0
-

@xxxObiWan: mě se nějak nezdá, že by loading helperu patřil do šablony. To už by tam rovnou mohla být inicilizace Latte a loding maker.

Filip Procházka
Moderator | 4668
+
0
-

Naprosto souhlasím s @**Tharos** a doporučuju ti folowovat žárovku. Ta by se ti líbila. Tam má Pavel v šablonách taky co se dá :)

nanuqcz
Člen | 822
+
0
-

A co na to „dgx-ova břitva dobrého MVC“?

  1. když změním názvy sloupců v databázové tabulce, bude nutné editovat kód controlleru či view?
  2. když změním HTML rozhraní za Flashové, bude nutné editovat kód modelu?
  3. když přehodím rozložení prvku na stránce, bude nutné editovat controller nebo model?

Příklad

  • Vezmu Sandbox Nette.
  • V HomepagePresenteru přidám $this->template->email = 'whatever@example.com';
  • V šabloně vypíšu {$email}

Teď budu chtít e-mail vypsat jako obrázek, abych neměl zaspamovanou poštu. Jak na to, abych nemusel editovat kód presenteru a bod 3) tak byl zachován?

Jan Tvrdík
Nette guru | 2595
+
0
-

To je prosté. Vrstva view není pouze v šablonách, ale je částečně i v presenterech. Tedy ne každá úprava presenteru je úpravou controlleru :)

nanuqcz
Člen | 822
+
0
-

Myslel jsem, že presenteru je „houby“ po tom, jak jsou data vykreslována. To, že presenter je částečně i vrstva View, se mi nezdá jako moc hezké řešení…

pave.kucera
Člen | 122
+
0
-

Imho se ptáš špatně. Neměníš rozložení prvků na stránce, transformuješ text na obrázek a to podle mě nepatří nikam jinam než do presenteru nebo líp do speciální třídy, kterou presenter povolá do služby.

Každopádně, nechceš-li kvůli registraci helperu šahat do presenteru, napiš si service třídu „HelperManager“, do které můžeš svoje helpery přidávat jakkoli tě napadne (bootstrap || může hledat třídy implementující určité rozhraní || cokoli dalšího…) a kterou pak v presenteru zavoláš a vždy zaregistruješ do šablony všechny helpery, které má „HelperManager“ v evidenci.