Šablonové helpery v Nette – umístění v MVC
- nanuqcz
- Člen | 822
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
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
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
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
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
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
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)
- Filip Procházka
- Moderator | 4668
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
A co na to „dgx-ova břitva dobrého MVC“?
- když změním názvy sloupců v databázové tabulce, bude nutné editovat kód controlleru či view?
- když změním HTML rozhraní za Flashové, bude nutné editovat kód modelu?
- 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
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 :)
- pave.kucera
- Člen | 122
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.