Obsah
Vytvoření presenteru
Dalším krokem, který provedeme, bude vytvoření tzv. „presenteru“. To bude takový „ředitel“ naší aplikace. Než se do toho pustíme, je třeba si vyjasnit, co je to MVP:
Princip MVP (a MVC)
Nette Framework podporuje užitečný návrhový vzor Model-View-Controler (MVC), v našem případě je písmenko „C“ nahrazeno písmenkem „P“. Nette Framework místo „controleru“ používá „presenter“.
Ten návrhový vzor MVP (i MVC) je ve skutečnosti velmi jednoduchý – spočívá v tom, že naši aplikaci rozdělíme do tří částí (ano, budou jimi Model, View a Presenter), které budeme moci vyvíjet a především udržovat samostatně. Tím návrh naší aplikace získá na robustnosti a flexibilitě a budeme jej díky tomu snadno udržovat.
Na následujícím obrázku vidíme schéma toho, jak návrhový vzor MVP vlastně pracuje:

Celý ten kolotoč začíná tím, že uživatel po naší aplikaci něco chce (v tom je hold s uživateli potíž), to se zpravidla projevuje tím, že on (resp. jeho webový prohlížeč) vytvoří tzv. požadavek (červená šipka od Usera k Presenteru), který směřuje na nějakou URL.
Tento požadavek Nette Framework pomocí něčeho, čemu se říká routování a routovací pravidla (a k čemu se podrobněji dostaneme později), zanalyzuje a najde příslušný presenter, který spustí a předá mu řízení.
Presenter si popovídá s modelem, kterému sdělí jaká data požaduje. Model tato data načte (kde je vezme je jeho problém, který presenter naprosto nezajímá, mohou to být soubory, databáze, či jiný zdroj dat).
Presenter tato data vezme a předá je pohledu (model by měl presenteru usnadňovat práci, takže pokud data, která získáte ze svých modelů, musíte v presenteru filtrovat, je to špatně a váš model by neměl dostat výplatu nebo byste ho měli rychle opravit). Správně vychovaný model dá presenteru přesně ta data, která presenter potřebuje a ten je z modelu pouze načte a předá je pohledu.
Pohled sám se už postará o jejich vykreslení. To, jak to dělá, je ale opět něco, co náš presenter zcela nezajímá.
Presenter jednoduše přikáže pohledu, aby se vykreslil a odešle to, co z něj vypadne, uživateli.
A celý ten kolotoč začne znovu s dalším uživatelovým požadavkem.
O modelu a pohledu si řekneme více až za chvilku.
Jak funguje presenter
Teď se detailněji podíváme na samotný Presenter.
Ta podivná výše uvedená věta o tom předávání řízení si zasluhuje lehké vysvětlení:
Už víme, že Presenter je takový ředitel nebo vedoucí naší aplikace. A stejně, jako může vedoucí nějakého podniku provádět několik různých činností, které souvisejí s náplní jeho práce, není ani náš presenter jednoúčelový, a může provádět několik různých činností. Těmto činnostem říkáme akce.
Stejně jako může ve firmě vedoucí pracovník provádět několik různých činností a stejně, jako může v MVC aplikacích každý Controler mít několik různých akcí, může mít tedy i v Nette Frameworku každý Presenter několik různých akcí.
Hierarchie presenterů
V řadě firem vedoucí pracovník ale není jen jeden jediný, často je jich ve vedení více a mají mezi sebou hierarchii.
Stejné to je i s webovou aplikací. I v ní může (a nemusí) být více presenterů, které mezi sebou mohou (a nemusí) mít hierarchii.
Takže jsme se dozvěděli, že v jedné webové aplikaci může být jeden nebo více presenterů, z nichž má každý jednu nebo více akcí a tyto presentery mezi sebou mohou a nemusí mít hierarchii. Také se vám z toho točí hlava? Mně ano. Pojďme to točení zastavit a srovnat si to:
Díky tomu, že máme tolik možností, můžeme strukturu presenterů naší aplikace snadno zkazit a navrhnout špatně (což je mimochodem i případ struktury hierarchie vedení u většiny velkých firem). Taková špatně navržená struktura je tragédie. Jak tomu zabránit?
Velice snadno. Stačí se při návrhu struktury presenterů držet těchto několika pravidel:
- Netvořte superpresentery (superpresenter je presenter, který dělá všechno)
- Snažte se mít co nejmenší počet presenterů
- Netvořte superakce (superakce je akce, která dělá činnost několika akcí)
- Snažte se mít co nejmenší počet akcí v 1 presenteru
- Struktura aplikace musí být jasná a srozumitelná (jakmile vám jako vývojáři jasná být přestane, je něco špatně)
- Pokud mají některé presentery společnou část chování (nebo nějaké akce), definujte abstraktního předka těmto presenterům a toto chování (či akce) dejte do něho.
- Správná struktura presenterů má vždy buď větve (abstraktní presentery) nebo listy (finální konkrétní presentery od nichž se už dále nedědí)
Pravidla 5 – 7 jsou docela v pořádku, problém je s pravidly 1 až 4, ta si totiž odporují… Co s tím?
Při odpovídání na tuto otázku se totiž začneme pohybovat na tenkém ledě. Kdy je presenter superpresenterem a měl by být rozdělen do několika menších? Kdy je akce suprakcí a měla by být rozdělena do několika? Kolik akcí nebo presenterů je moc?
Jak navrhnout správnou hierarchii presenterů?
Na žádnou z těchto otázek neexistuje univerzální odpověď. Zde lze pomocí odpovědi pouze nasměrovat a dát k lepšímu několik zásad, jejichž dodržování je zcela jistě krok správným směrem:
- Každá akce by měla udělat právě jen a pouze to, co popisuje jedna otáčka našeho kolotoče.
Tedy:
- Inicializovat model (nebo více modelů)
- Inicializovat akci modelu (zavolat nějakou jeho metodu) – této lze předat nějaké vstupní argumenty
- Inicializovat pohled
- Předat výstup z modelu do pohledu
- Přikázat pohledu vykreslit se
- Každá akce by měla reagovat na jeden druh požadavku od klienta (pokud má naše aplikace umět X věcí, pak musí umět obsloužit X různých druhů požadavků, pokud bude každá akce obsluhovat právě jeden požadavek, pak budeme potřebovat celkem X akcí)
- Tyto akce rozdělíme do presenterů podle toho jak spolu souvisejí
- Pokud zjistíme, že některé dva presentery mají stejnou akci, vydefinujeme ji z nich do jejich abstraktního předka.
Tím získáme správnou strukturu presenterů aplikace.
Pro více informací o MVP si přečtěte Model, View a Presenter
Navrhujeme presenter
Správný presenter by tedy měl:
- Být nestavový
- Mít pouze akce, které souvisejí s jednou činností (tj. např. buď Registrace nebo Přihlašování a Odhlašování, ale už ne obojí) – Jeden presenter by měl pokrývat jeden nebo několik souvisejících Use Case (případ užití)
- Každá jeho akce by měla reflektovat maximálně jeden řádek ve scénáři Use Case (případu užití)
- Mít pouze jednoúčelové a jednoduché akce
- Být abstract nebo final, nikdy ne něco mezi tím
- Obsluhovat právě jeden případ užití
Když tedy konečně opustíme ty nepříjemné vody teorie a vrátíme se k naší aplikaci s todolistem, měli bychom při uvažování nad strukturou presenterů dospět k následujícímu:
- Budeme vytvářet jednoduchý todolist, pro začátek nám bude umožňovat úkoly zobrazovat, přidávat, měnit a mazat.
- Postačí nám tedy jeden presenter, neboť potřebujeme, aby nám naše aplikace umožňovala pouze čtyři související činnosti.
- Náš presenter bude mít čtyři akce, které budou reflektovat to, co od naší aplikace potřebujeme.
No a teď už zbývá to jen napsat:
Implementujeme presenter
Implementace presenteru je v Nette Frameworku velmi jednoduchá.
Presenter je třída:
- která dědí od třídy
Presenter - která se jmenuje
XXXPresenter, kdeXXXje název presenteru - která je uložena v souboru
XXXPresenter.php, kdeXXXje název presenteru - která se nachází v adresáři
app/presenters(resp. v tom adresáři, který je definován v příslušné proměnné v konfiguraci, implicitně je použit právě adresářapp/presenters)
Díky dedukci a analýze uvedené výše už
víme, že chceme nyní vytvořit právě jeden presenter. Vytváříme todolist
a proto by se i náš presenter měl jmenovat todolist. Jména
presenterů se ovšem píší s velkým počátečním písmenem. Proto se
náš presenter bude jmenovat Todolist.
Abychom presenter Todolist vytvořili, stačí vytvořit soubor
TodolistPresenter.php v adresáři app/presenters a
do něj vložit následující kód:
<?php
class TodolistPresenter extends Presenter
{
}
Tak a máme náš první presenter, nebylo to nějak moc snadné? Bylo, už to skoro máme, ale hotové to ještě není.
S čím pomáhá skeleton?
Při ukládání souboru s presenterem jsme si mohli všimnout, že díky
skeletonu už v adresáři app/presenters nějaké presentery
máme. Konkrétně:
+--app/
| +--presenters/
| | +--BasePresenter.php
| | +--ErrorPresenter.php
| | +--HomepagePresenter.php
| | +--LoginPresenter.php
| + ...
+ ...
Ještě než dokončíme ten náš, tak si o nich v rychlosti něco povíme:
Prakticky každá (i ta nejjednoduší aplikace, jakou je i náš todolist) obsahuje nějaké chování presenterů, které jim chceme definovat všem společně. Z toho tedy vyplývá, že prakticky vždy budeme potřebovat alespoň jeden ten abstraktní presenter, který ve struktuře presenterů tvoří větev.
Na to myslí i skeleton a ten presenter pro nás má již připraven – je
jím právě presenter Base, který je uložen v souboru
BasePresenter.php (navzdory výše uvedené konvenci je tento
presenter známý jako BasePresenter místo obvyklého Base).
Když bychom se do souboru podívali, zjistili bychom, že obsahuje po ostranění komentářů něco takovéhoto:
<?php
abstract class BasePresenter extends Presenter
{
public $oldLayoutMode = FALSE;
}
Vidíme, že jde o abstraktní třídu, která dědí od presenteru a nastavuje nějakou proměnou na hodnotu FALSE. Tu proměnou budeme řešit až jindy a nyní se místo toho trochu zamyslíme:
Jak jsme si řekli výše, zpravidla je vždycky nutné některé věci
nastavovat pro všechny presentery v celé aplikaci. Proto by bylo dobré,
kdyby všechny měly nějakého společného předka. Potom to můžeme nastavit
jemu a ostatní to zdědí. A přesně k tomu nám slouží
BasePresenter.
Používáme BasePresenter
Když už nám ho ten skeleton tak hezky připravil, tak jej využijeme a
předěláme náš TodolistPresenter tak, aby dědil místo od
Presenteru od BasePresenteru. Kód bude po úpravě
vypadat takto:
<?php
class TodolistPresenter extends BasePresenter
{
}
Výše jsme si také povídali o tom, že by všechny presentery měly být
buď abstract, nebo final a ten náš zatím není ani
jedno ani druhé – a to je špatně. Náš presenter bude konkrétní a
v hierarchii presenterů půjde o list. Nepůjde od něj tedy dědit a bude
finální.
Znovu lehce poupravíme zdrojový kód:
<?php
final class TodolistPresenter extends BasePresenter
{
}
Příklady presenterů
Ještě abych splnil slib se zmíním o těch zbývajících presenterech, které nám připravil skeleton: kromě presenteru Base v adresáři najdeteme presentery Error, Homepage a Login.
Na nich krásně vidíme, k čemu všemu nám presentery v aplikaci mohou sloužit:
- Error presenter je zvlášní presenter, který je Nette Frameworkem
použit k zobrazování chybových hlášek (ano, zapomeňte na vytváření
souborů
404.htmlapod. a to, že na ně budete pomocí souborů.htaccessserver směrovat. Nette Framework se svýmErrorPresenteremje řešení mnohem mocnější a lepší, ale o něm si povíme až jindy). Zatím nám stačí vědět, že součástí skeletonu je i základní konfigurace tohoto presenteru, tak to zatím necháme být. - Presenter Homepage je prototypem presenteru, který můžeme použít k vytvoření domovské stránky naší webové aplikace. Ten nebudeme potřebovat, ale smažeme jej až za chvíli, zatím ho tam hezky nechte.
- A konečně presenter Login, jak už jeho název napovídá, slouží k implementaci přihlašování do systému – ten zatím rovněž nebudeme potřebovat, ale mazání necháme na jindy.
Tak a nyní se můžeme už s čistým svědomím vrátit k našemu
presenteru Todolist.
Přidáváme akci
Náš presenter jako takový je nyní hotov. Vidíte, že díky Nette Frameworku to není nic těžkého. Jak si ale ti bystřejší z vás již mohli všimnout, náš presenter zatím nemá žádnou akci. Což je trošku nepraktické, neboť nyní máme presenter, který sice existuje, ale nic neumí a proto nám k ničemu není.
Něco s tím uděláme a naučíme ho provádět první ze čtyř plánovaných akcí: zobrazování příspěvků.
Když chceme presenter naučit novou akci, pak musíme udělat následující:
1. Zvolíme si název akce, kterou chceme přidat. Vzhledem k tomu, že se
zobrazit řekne anglicky show a naše akce má zobrazovat úkoly,
tak se bude jmenovat show. Mluvit o ní budeme jako o „akci
show“.
Jako název akce nám opravdu stačí slovo show,
není třeba, aby se jmenovala showTodos nebo podobně, protože
v naší aplikaci se bude uvádět zpravidla společně s názvem svého
presenteru. A výraz Todolist:show je již dostatečně
jednoznačný.
2. Když už máme název akce, přidáme našemu presenteru metody
actionXXX a renderXXX, kde místo XXX
uvedeme název naší akce, tedy slovo show. Názvy metod, které
přidáme našemu presenteru, abychom ho naučili akci show, tedy
budou actionShow a renderShow. Po úpravě bude
zdrojový kód vypadat následovně:
<?php
final class TodolistPresenter extends BasePresenter
{
public function actionShow() {
}
public function renderShow() {
}
}
Ve zdrojovém kódu uvádíme dle konvence metody zpravidla v pořadí napřed actionXXX a potom renderXXX. Ale záleží to především na vás.
Už tedy víme, že pro každou akci je do presenteru nutné přidat tyto dvě metody. Také si říkáte, proč jsou to metody dvě a ne jedna? Důvod je jednoduchý. Nette Framework je MVP, jak už víme, má každá aplikace v něm napsaná tři části. Presenter je jednou z nich a pracuje se zbývajícími dvěma.
A jelikož Nette Framework podporuje dobré programátorské návyky, které říkají, že má být model a pohled oddělený a každá akce má pracovat nejdříve s modelem (nebo modely) a potom s pohledem, má každá akce presenteru dvě metody, jednu na práci s modelem a druhou pro pohled.
Je konec starostem s tím, zda se vám to volá ve správném pořadí, Nette Framework tyto metody ve správném pořadí volá za vás!
A to není to jediné, co dělá za vás:-)…
Jediné, co je k tomu třeba z vaší strany, je vědět, že s modelem
pracujeme v metodě actionXXX a s pohledem v metodě
renderXXX. A nikdy jinak!
Závěrem
Úspěšně jsme vytvořili náš první presenter! Když pominu tu šíleně nudnou teorii, bylo to docela snadné, ne?
Nyní náš presenter umí obsloužit akci show, sice tato akce
zatím neobsahuje žádný funkční kód, ale presenter ji už má a umí
s ní pracovat. Ano, tak snadné to bylo!
Když bychom se nyní akci show presenteru Todolist
pokusili spustit, neuspěli bychom. K tomu, aby vše fungovalo, jak má, nám
stále něco chybí. Už máme presenter, tedy písmenko „P“ z MVP. Ale to
„M“ a „V“ nám stále chybí.
Nette Framework to ví a proto nám při pokusu o spuštění oznámí, že
k akci show postrádá soubor šablony. To je soubor, ve kterém
je uložen pohled. Ale to už předbíhám, více najdete na další
stránce…
Co bychom si měli zapamatovat?
- Nette Framework podporuje návrhový vzor MVC (resp. MVP)
- Aplikace v Nette Frameworku se skládá z modelů, pohledů a presenterů
- Aplikace v Nette Frameworku obsahuje jeden nebo více presenterů
- Presentery v aplikaci mohou a nemusí tvořit hierarchii (ta hierarchie je však vždy stromová → každý presenter je buďto abstract, nebo final)
- Každý presenter má několik akcí (umí obsluhovat několik druhů požadavků)
- Každý presenter agreguje jen ty akce, které spolu souvisejí
- Každá akce obsluhuje právě jeden požadavek
- Implementací presenteru je třída, která
- dědí od
Presenter, resp.BasePresenter - se jmenuje
XXXPresenter, kdeXXXje název presenteru, XXX začíná velkým písmenem a pokud je tvořeno více slovy je použito PascalCaps. - je uložena v souboru
XXXPresenter.php, v zpravidla v adresářiapp/presenters, kdeXXXje název presenteru
- dědí od
- Implementací 1 akce presenteru jsou
publicmetodyactionXXXarenderXXX, kde XXX je název akce. Pokud je se název akce uvádí samostatně (mimo metodyrenderaaction) začíná malým písmenem - Každý presenter ke každé své akci potřebuje šablonu (kromě akcí,
které v metodě
actionexplicitně sdělí že šablonu nepoužívají)
A teď se konečně dostaneme k té zajímavější části návodu…
Komentáře 
dehtak | 4. 2. 2010, 12:08 | comment
a koukam ze v tom zipu je uplne neco jineho nez tu pisete. Kam se najednou podeli soubory ze skeletoon . Nikde jste nepsal ze se maji vsechny ty soubory smaznout. Nikde jste nepsal co mame napsat do bootstramp.php
Inza | 8. 2. 2010, 14:03 | comment
Tento tutoriál ještě není dokončen! Aktualizujeme jej na novou verzi.
Soubor, který jste si stáhli patřil ke staré verzi. Nelamte si s tím hlavu a ještě chvilu posečkejte na dokončení tohoto tutoriálu…
Endrju | 9. 2. 2010, 18:27 | comment
Paráda, prořel jsem si celý QS včetně předchozích částí 1, 2 a 3 (přibylo oproti předchozí verzi „Co bychom si měli zapamatovat?“).
Ta teorie v této části mi vůbec nevadí, ba naopak, řekl bych, že je docela důležitá. Ne všichni mají dobrou představu o tom, co je to MVP (MVC).
Nedočkavě už refreshuju následující část – Vytvoření šablony, tak šup do toho Inzo… :)
enigma | 26. 2. 2010, 14:58 | comment
Souhlasím…paráda,také mi vyhovuje teorie,která je uvedena průběžně.
bazo | 1. 3. 2010, 15:30 | comment
ja by som len podotkol, ze MVP nevznikol len nahradenim pismenka C v MVC. je tam rozdiel, takze by som to nedaval ako ekvivalentne pojmy




dehtak | 4. 2. 2010, 12:06 | comment
Nefunguje : hlasi to chybu
File: D:\nette\libs\Nette\Application\Application.php Line: 146
Line 139: Line 140: // Instantiate presenter Line 141: $presenter = $request->getPresenterName(); Line 142: try { Line 143: $class = $this->getPresenterLoader()->getPresenterClass($presenter); Line 144: $request->setPresenterName($presenter); Line 145: } catch (InvalidPresenterException $e) { Line 146: throw new BadRequestException($e->getMessage(), 404, $e); Line 147: } Line 148: $request->freeze(); Line 149: Line 150: // Execute presenter Line 151: $this->presenter = new $class; Line 152: $response = $this->presenter->run($request); Line 153:
Call stack ▼
1.
app/bootstrap.php (53) source ► Application → run ()
Line 46: ‚action‘ ⇒ ‚default‘,
Line 47: ‚id‘ ⇒ NULL,
Line 48: ));
Line 49:
Line 50:
Line 51:
Line 52: // Step 5: Run the application!
Line 53: $application->run();
Line 54:
2.
document_root/index.php (13) source ► require (arguments ►)
Ja se domnivam ze jste zapomneli napsat neco o tom bootstrampu , protoze porad v nem je nastaveny
‚presenter‘ ⇒ ‚Homepage‘,
‚action‘ ⇒ ‚default‘, z toho skeletonu . Dalsi vec proc se uz slozka nejmenuje todolist jako v predchozich castech dilu ale ma ted jmeno DataGrind ? Bylo by lepsi napsat ten navod tak aby si uzivatel vytvarel sam ty soubory , aby to lepe pochopil. A ne jednou nakopirovat skeleton a potom vytvaret soubory. Pak je v tom gulas.