Je vhodnější používat komponenty nebo společné šablony generovat přes jeden prezentér?

zachrdlapetr
Člen | 49
+
0
-

Ve svém stávajícím systému mám vše řízené pohledem (alias view, alias šablona). Router volá view, view si sáhne na kontrolér, kontrolér na model, model na databázi, model vrátí obsah do kontroléru a ten jej předá do view a zobrazí. Výhodou pro mě je, když udělám ve view (šabloně) include jakékoliv šablony, nemusím se starat co se stane, protože každý view má volitelně kontrolér. Pokud nepotřebuji generovat v kontroléru žádné data, tak jej nemusím programovat, pokud jsou potřeba data, tak se vytvoří kontrolér (stejná syntaxe pro všechny kontroléry) a z jednoho nebo více modelů se vloží obsah proměnných do šablony. Pomocí routeru však musím nastavit co lidé mají vidět a co ne. Resp. co tam není, není veřejně vidět.

V nette je hlavním spouštěčem prezentér, který si sáhne do modelů, modely načtou data z databáze nebo zpracují obsah, vrátí jej do prezentéru a ten je vloží do šablony a pošle uživateli.

Moje dilema se týká vkládání více šablon do jedné. Typicky eshop a šablona košík vpravo nahoře. Šablonu vkládám opakovaně do různých jiných šablon a mám dvě možnosti.

První: Vytvořit komponentu (nutnost vytvořit více kódu, navázat na model a nasměrovat na šablonu), navázat na ni např. šablonu košík_nahoře.latte, vložit ji do prezentéru Homepage (createComponentKosikNahore) a v šabloně Homepage.default.latte vložit {control košík_nahoře.latte}

Druhá: Vložit šablonu košík_nahoře.latte do Homepage.default.latte k prezentéru Homepage přes INCLUDE a proměnné v košík_nahoře.latte doplnit přes prezentér Homepage z modelu.

Druhá možnost se mi zdá čistější (méně kódu – klidně jen jeden řádek navíc), ale nevím jestli je to úplně systémové. První možnost je určitě systémová, ale mám obavu z nadbytku kódu.

Která možnost je podle vás lepší?

CZechBoY
Člen | 3608
+
0
-

To už záleží na tobě jestli chceš mít související logiku oddělenou v komponentě – tady můžeš mít třeba další subkomponenty na přidání/odebrání položky do košíku – nebo mít úplně všechnu „logiku“ v BasePresenteru.

Já moc nemám rád šablony s logikou – pokud používám nějakou šablonu na více místech tak je to většinou jen nějaká dekorace a ne přímo logická část systému.

zachrdlapetr
Člen | 49
+
0
-

CZechBoY napsal(a):

To už záleží na tobě jestli chceš mít související logiku oddělenou v komponentě – tady můžeš mít třeba další subkomponenty na přidání/odebrání položky do košíku – nebo mít úplně všechnu „logiku“ v BasePresenteru.

Já moc nemám rád šablony s logikou – pokud používám nějakou šablonu na více místech tak je to většinou jen nějaká dekorace a ne přímo logická část systému.

No z mého pohledu patří logika kompletně do modelu. Prezentér vnímám jen jako zprostředkovatele. Neměly by se tam odehrávat žádné výpočty. Jen dává dohromady požadavky do modelů a předává data mezi modely, aby si modely zachovaly nezávislost.

To je otázka jestli mít v šablonách něco s generovaným obsahem. Pro mě jednoznačně ano. Když uděláš něco složitějšího anebo děláš pro zákazníky různé varianty, tak je lepší mít skládačku. Ve stávajícím systému to mám tak, že do hlavní šablony (mám vstup řízený šablonou nikoliv prezentérem) naskládám přes INCLUDE jen to co potřebuji zobrazit a už se nestarám o přístupové práva nebo jiné věci. Také je to značně přehlednější.

Změnu frameworku zvažuji kvůli bezpečnosti, která je tu vyřešena lépe resp. je otestovaná.

Takže v generování dat do include šablon mám názor pevný dokud nedostanu jiné pádné argumenty, které naruší moji logiku uvažování.

Spíš potřebuji rozseknout jestli:

Model1 – Prezenter1 – deafult.latte – include kosik.latte
Model2 /

nebo

Model3
\
Component1\ — path+render ------------------------------------------\
Model1 – Prezenter1 (+createComponent) – default.latte – control kosik.latte
Model2 /

Uvažujme, že nevíme kam se to bude v budoucnu rozšiřovat.

CZechBoY
Člen | 3608
+
0
-

No to co jsem tady zmiňoval jsou signály pro komponenty – tzn. pokud máš komponentu a ne jen hloupou šablonu tak můžeš použít nějaké signály v komponenty (jak už jsem psal třeba přidání/odebrání položky do/z košíku).
Taky z pohledu SRP mi přijde hodně podezřelé, že by presenter měl řešit ještě věci okolo.

zachrdlapetr
Člen | 49
+
0
-

CZechBoY napsal(a):

No to co jsem tady zmiňoval jsou signály pro komponenty – tzn. pokud máš komponentu a ne jen hloupou šablonu tak můžeš použít nějaké signály v komponenty (jak už jsem psal třeba přidání/odebrání položky do/z košíku).
Taky z pohledu SRP mi přijde hodně podezřelé, že by presenter měl řešit ještě věci okolo.

jj. já tomu rozumím, že signál ke košíku patří ke košíku a ne k prezentéru, ale z hlediska kódu je komplikovanější udělat komponentu, z ní sahat do modelu, data z modelu v komponentě vložit do šablony, a celou komponentu pak vložit do prezentéru formou createComponent, oproti vytvoření handleru přímo v prezentéru, který si sáhne přímo do modelu.

Varianta s komponentou může být přehlednější v případě, že existuje obrovské množství handlerů, ale na druhou stranu, dělal jsi někdy takovou aplikaci, kde byly handlery nepřehledné? Nebo jinak o kolik méně přehledné je vytvořit mnoho handlerů v prezentéru oproti naprosto stejnému množství createComponent?

Jediná výhoda by prakticky byla v případě, kdyby na jednu komponentu bylo více handlerů. Pak by byly přehlednější komponenty.

Editoval zachrdlapetr (23. 1. 2018 14:31)

CZechBoY
Člen | 3608
+
0
-

Stačí mít 4 komponenty rozbalené v presenteru a hned je presenter zbytečně dlouhý. Radši 4 krátké srp komponenty než 1 moloch presenter :-)
ps. můj BasePresenter už tak má celkem hafo komponent a to je vytvářím jen přes továrničku a je celkem dost dlouhý (na řádky).

zachrdlapetr
Člen | 49
+
0
-

CZechBoY napsal(a):

Stačí mít 4 komponenty rozbalené v presenteru a hned je presenter zbytečně dlouhý. Radši 4 krátké srp komponenty než 1 moloch presenter :-)
ps. můj BasePresenter už tak má celkem hafo komponent a to je vytvářím jen přes továrničku a je celkem dost dlouhý (na řádky).

jj. Já to chápu jak to myslíš, ale tvrzení o více kódu v prezentéru platí jen pro situaci, kdyby měla každá komponenta víc jak jeden handler. V opačném případě je to pouze více kódu, protože děláš komponenty, které pak musíš stejně implementovat v prezentéru. Stejně v komponentě se musíš dotázat do stejného modelu jako by jsi to dělal z prezentéru, kdyby jsi subšablony vkládal pomocí include a ládoval je z modelu přímo v prezentéru (je to jeden řádek kódu).

Hele zatím mě to nepřesvědčilo, že se mýlím. Jestli mohu poprosit, zkus mi to prosím ještě nějak nabourat.

Šaman
Člen | 2666
+
0
-

Tohle ti nabourá až praxe, pár projektů, které dojdou do špatně udržitelného stavu, kde pomůže jen kompletni refaktoring. A následná snaha o udržitelný kód.
Pak si sám stanovíš pár pravidel, které nebudeš chtít porušovat jen kvůli tomu, že ušetříš pár řádků kódu (navíc generického, nebo přímo generovaného IDEm). Stačí, že je občas nutné něco porušit prostě proto, že to z těch pravidel nějak zásadně vybočuje.

Další věc (i když stále se týká udržitelnosti) je když se vrátíš k projektu po roce, nebo i déle. Pak opravdu oceníš důsledné rozdělení kódu na logické kusy, které si spravují veškerou svoji logiku.

zachrdlapetr
Člen | 49
+
0
-

Šaman napsal(a):

Tohle ti nabourá až praxe, pár projektů, které dojdou do špatně udržitelného stavu, kde pomůže jen kompletni refaktoring. A následná snaha o udržitelný kód.
Pak si sám stanovíš pár pravidel, které nebudeš chtít porušovat jen kvůli tomu, že ušetříš pár řádků kódu (navíc generického, nebo přímo generovaného IDEm). Stačí, že je občas nutné něco porušit prostě proto, že to z těch pravidel nějak zásadně vybočuje.

Další věc (i když stále se týká udržitelnosti) je když se vrátíš k projektu po roce, nebo i déle. Pak opravdu oceníš důsledné rozdělení kódu na logické kusy, které si spravují veškerou svoji logiku.

jasný rozumím. jen to nechci rozdrobit do tak mnoho vrstev, za každou cenu, protože to pak považuji za nepřehledné. jak jsem psal, tak v současnosti mám čistý MVP systém. Takže jsem do teď komponenty nepotřeboval, protože jsem jednoduše zavolal pohled a hotovo. Když to např. byla obnova dat v tabulce, tak jsem ajaxem vyvolal příslušný pohled a funkci komponenty mi plnil prezentér ke konkrétní šabloně. Tam měl logický celek vždy view+prezentér a link do modelu(ů).

Nette je v podstatě hybrid mezi MVC a MVP. Tady je obrázek jak to myslím https://cdn-images-1.medium.com/…vPzRAuqg.png

Proto se tak zdráhám používat komponenty jako další vrstvu navíc a proto hledám pádné argumenty, které mi rozbourají mojí představu. V podstatě se komponentám nebráním, ale nechci je používat za každou cenu, pokud to nebude nezbytně nutné. Tedy pokud mi někdo nenapíše dostatečně pádný argument z praxe, který smete jak moji tvrdohlavost, tak moji představu o skutečně jen třívrstvé aplikaci.

Šaman
Člen | 2666
+
0
-

Komponenty nejsou další vrstva, patří do prezenční vrstvy. Jsou fajn na věci, které nemají vazby na jeden konkrétní presenter.
Jinak použití BasePresenteru na „univerzální“ signály a akce považuji na trochu nečisté. Tam patří spíš nastavení chování všech dalšich presenterů (třeba změna hledání šablon, automatická kontrola oprávnění, případně rozšíření životního cyklu o nějaké další události apod.)
Ale i to je prostě jen osobní zkušenost. Čistě technicky, dokud aplikace funguje, tak je v pořádku.

zachrdlapetr
Člen | 49
+
0
-

Šaman napsal(a):

Komponenty nejsou další vrstva, patří do prezenční vrstvy. Jsou fajn na věci, které nemají vazby na jeden konkrétní presenter.
Jinak použití BasePresenteru na „univerzální“ signály a akce považuji na trochu nečisté. Tam patří spíš nastavení chování všech dalšich presenterů (třeba změna hledání šablon, automatická kontrola oprávnění, případně rozšíření životního cyklu o nějaké další události apod.)
Ale i to je prostě jen osobní zkušenost. Čistě technicky, dokud aplikace funguje, tak je v pořádku.

O BasePrezentéru jsem nepsal. Mám na logické části aplikace navrženy samostatné prezentéry. Aktuálně mám navrženo 15 kousků pro front a cca 30 pro admin (bude se kvůli CRM měnit). V nich jsem očekával, že budu řešit většinu interakcí přes akci např. /product/delete/1, nikoliv přes signál. Takže nikdy by případné signály nebyly všechny v jednom.

Stále váhám. Nevidím tom stále žádnou výhodu.

Je to pro mě buď

komponenta
class TestControl extends BaseControl {
	public function render() {
		$testdata = new Model1;
		$this->template->setFile(__DIR__ . '/templates/test/default.latte');
		$this->template->data = $testdata->getData();
		$this->render();
	}
	public function handleClick() {
		....
	}
}

šablona komponenta
{$data}

prezentér
class HomepagePresenter extends BasePresenter {
	public function createComponentTest() {
		return \App\Controls\TestControl;
	}

}

šablona prezentér
{control test}

vs.

prezentér
class HomepagePresenter extends BasePresenter {
	/** @var \App\Models\Model1 @inject */
	public $model1;
	public function renderDefault() {
		$this->template->data = $model1->getData();

	}

}

šablona prezentér
{include 'test.latte'}

univerzální šablona test.latte
{$data}
Šaman
Člen | 2666
+
0
-

Na začátku diskuze byl příklad s nákupním košíkem. Jestli ho chceš mít na více stránkách (a něco složitějšího, než jen odkaz na stránku „košík“), tak jeho akce a handlery musí znát i aktuální presenter. Z toho mi vyplývá:

  • Buď to dám do BasePresenteru, pak se o to dál nemusím starat a stačí na libovolné místo includnout kosik.latte a bude to fungovat. Pak platí mé výhrady k takovým věcem v BasePresenteru.
  • Nebo musím nejen includnout šablonu košíku, ale také hned zkopírovat handlery, které s tou šablonou souvisí. Už není možné jen někam plivnout košík, musím navíc zajistit jeho obsluhu. To může být na více místech a pokud se někdy změní ta šablona košíku natolik, že bude vyžadovat změnu v obslužném kódu, bude potřeba to změnit všude. Zatímco komponenta si tohle udržuje pohromadě. Komponenta je šablona + její prezentační kód v jednom adresáři a z hlediska OOP v jedné třídě.

Komponenty mají navíc výhodu při práci se snippety, ale to je už jiná diskuze.


V tom tvém příkladu nad tímto příspěvkem je to vidět. V případě includované šablony se musí presenter postarat o dodání dat. V tom prvním jen vytvoří komponentu a pak v šabloně zobrazí komponentu. Do jejích dat presenteru nic není a odladěná komponenta bude stále fungovat, i když se brutálně změní.
V druhém případě se po změně musí projít a zkontrolovat/upravit všechna volání

<?php
public function renderDefault() {
    $this->template->data = $model1->getData();
}
?>

A ta příprava dat může být složitější.


Ještě jinak řečeno. V případě includované šablony je to celé zodpovědnost presenteru. A čím víc toho dělá, tím méně je přehledný.
Pokud je to problém, který se bude opakovat ve více presenterech, případně který je poměrně autonomní, tak je lepší ho vyčlenit do komponenty. Ta si své problémy řeší sama a s presenterem komunikuje jen pomocí předem daných rozhraní. Samotná komponenta řeší jen jeden problém, takže je přehledná. A lépe se testuje.

Editoval Šaman (24. 1. 2018 11:06)

zachrdlapetr
Člen | 49
+
0
-

Šaman napsal(a):

Na začátku diskuze byl příklad s nákupním košíkem. Jestli ho chceš mít na více stránkách (a něco složitějšího, než jen odkaz na stránku „košík“), tak jeho akce a handlery musí znát i aktuální presenter. Z toho mi vyplývá:

  • Buď to dám do BasePresenteru, pak se o to dál nemusím starat a stačí na libovolné místo includnout kosik.latte a bude to fungovat. Pak platí mé výhrady k takovým věcem v BasePresenteru.
  • Nebo musím nejen includnout šablonu košíku, ale také hned zkopírovat handlery, které s tou šablonou souvisí. Už není možné jen někam plivnout košík, musím navíc zajistit jeho obsluhu. To může být na více místech a pokud se někdy změní ta šablona košíku natolik, že bude vyžadovat změnu v obslužném kódu, bude potřeba to změnit všude. Zatímco komponenta si tohle udržuje pohromadě. Komponenta je šablona + její prezentační kód v jednom adresáři a z hlediska OOP v jedné třídě.

Komponenty mají navíc výhodu při práci se snippety, ale to je už jiná diskuze.

Jo. To beru, že pokud tam budou handlery, tak bych je musel kopírovat do každého prezentéru, kde se odkazuji na univerzální šablonu anebo to šupnout do BasePresentéru, kam to tutově nepatří.

Jakou výhodu mají komponenty při práci se snippety?

zachrdlapetr
Člen | 49
+
0
-

Šaman napsal(a):

V tom tvém příkladu nad tímto příspěvkem je to vidět. V případě includované šablony se musí presenter postarat o dodání dat. V tom prvním jen vytvoří komponentu a pak v šabloně zobrazí komponentu. Do jejích dat presenteru nic není a odladěná komponenta bude stále fungovat, i když se brutálně změní.
V druhém případě se po změně musí projít a zkontrolovat/upravit všechna volání

<?php
public function renderDefault() {
    $this->template->data = $model1->getData();
}
?>

A ta příprava dat může být složitější.


Ještě jinak řečeno. V případě includované šablony je to celé zodpovědnost presenteru. A čím víc toho dělá, tím méně je přehledný.
Pokud je to problém, který se bude opakovat ve více presenterech, případně který je poměrně autonomní, tak je lepší ho vyčlenit do komponenty. Ta si své problémy řeší sama a s presenterem komunikuje jen pomocí předem daných rozhraní. Samotná komponenta řeší jen jeden problém, takže je přehledná. A lépe se testuje.

jj. tak to beru. už jsem to rozdělil na samostatné komponenty. děkuji za vysvětlení.

Czechboy: také děkuji.

Editoval zachrdlapetr (28. 1. 2018 1:26)