4. diel - Dokončenie kalkulačky v Nette
V minulej lekcii, Prvé aplikácie v Nette , sme dokončili model a teraz sa môžeme presunúť na presenter. Takže bez ďalšieho otáľania ideme na to!
Presenter
App / presenters / CalculatorPresenter.php
V šablóne Nette webového projektu máme v priečinku
app/presenters/
už vytvorený súbor
HomepagePresener.php
. My ho však zmažeme alebo premenujeme a
vytvoríme si tu náš vlastný CalculatorPresenter.php
a v ňom
triedu CalculatorPresenter
, ktorá dedí z
Nette\Application\UI\Presenter
. Tým sme si vytvorili základnú
kostru prezentačného, do ktorej ešte doplníme predvolenú metódu pre
vykresľovanie šablóny, aby výsledku vyzerala nejako takto:
<?php namespace App\Presenters; use Nette\Application\UI\Presenter; use App\Model\CalculatorManager; use Nette\Application\UI\Form; use Nette\Utils\ArrayHash; /** * Presenter kalkulačky. * @package App\Presenters */ class CalculatorPresenter extends Presenter { /** @var int|null výsledek operace nebo null */ private $result = null; /** Výchozí vykreslovací metoda tohoto presenteru. */ public function renderDefault() { // Předání výsledku do šablony. $this->template->result = $this->result; } }
Ako vidíte, odovzdávame tu výsledok do šablóny, aby sme ho mohli
zobraziť. Výsledok je zatiaľ null
, ale to za chvíľu
napravíme.
Získanie modelu z prezentačného
K tomu, aby sme získali výsledok, budeme potrebovať prístup k modelu. Ten
sa v Nette štandardne zabezpečuje pomocou Dependency Injection
(skrátene DI) a to tak, že v konfiguračnom súbore config.neon
zaregistrujeme náš model ako anonymný službu (service) a potom si ho
necháme injektovať do nášho prezentačného.
App / config / congif.neon
Najskôr teda nájdeme tento súbor a upravíme pridaním služby:
... services: router: App\RouterFactory::createRouter - App\Model\CalculatorManager
Teraz máme niekoľko možností, ako a kde si nechať službu injektovať.
Ja si zvolím štandardné a asi najpoužívanejšie postup a to cez
konštruktor prezentačného. Do našej triedy CalculatorPresenter
teda pridáme nasledujúci kód:
// ... /** @var CalculatorManager Instance třídy modelu pro práci s operacemi kalkulačky. */ private $calculatorManager; /** * Konstruktor s injektovaným modelem pro práci s operacemi kalkulačky. * @param CalculatorManager $calculatorManager automaticky injektovaná třída modelu pro práci s operacemi kalkulačky */ public function __construct(CalculatorManager $calculatorManager) { parent::__construct(); $this->calculatorManager = $calculatorManager; } // ...
Teraz máme prístup k nášmu modelu cez
$this->calculatorManager
.
Nette formuláre v Presenter
Máme už všetko potrebné pre výpočet a odovzdanie výsledku do
šablóny. Je teda potrebné sa zamyslieť nad tým, ako budeme získavať dáta
pre výpočet od užívateľa. Odpoveď je jednoduchá, cez formulár. To v
Nette znamená, že si potrebujeme v prezentačného zadefinovať formulár,
ktorý potom odovzdáme do šablóny. Z neho získame dáta, ktoré odovzdáme
modelu na výpočet a výsledok uložíme do $this->result
.
Nette nám na tento účel prináša systém komponentov a špeciálne pre
formuláre v Presenter má už pripravenú triedu
Nette\Application\UI\Form
. Nám len stačí pomocou nej
zadefinovať podobu formulára a funkciu pre jeho spracovanie:
/** Definice konstant pro zprávy formuláře. */ // ... const FORM_MSG_REQUIRED = 'Tohle pole je povinné.', FORM_MSG_RULE = 'Tohle pole má neplatný formát.'; // ... /** * Vrátí formulář kalkulačky. * @return Form formulář kalkulačky */ protected function createComponentCalculatorForm() { $form = new Form; // Získáme existující operace kalkulačky a dáme je do výběru operací. $form->addRadioList('operation', 'Operace:', $this->calculatorManager->getOperations()) ->setDefaultValue(CalculatorManager::ADD) ->setRequired(self::FORM_MSG_REQUIRED); $form->addText('x', 'První číslo:') ->setType('number') ->setDefaultValue(0) ->setRequired(self::FORM_MSG_REQUIRED) ->addRule(Form::INTEGER, self::FORM_MSG_RULE); $form->addText('y', 'Druhé číslo:') ->setType('number') ->setDefaultValue(0) ->setRequired(self::FORM_MSG_REQUIRED) ->addRule(Form::INTEGER, self::FORM_MSG_RULE) // Ošetříme dělení nulou. ->addConditionOn($form['operation'], Form::EQUAL, CalculatorManager::DIVIDE) ->addRule(Form::PATTERN, 'Nelze dělit nulou.', '^[^0].*'); $form->addSubmit('calculate', 'Spočítej výsledek'); $form->onSuccess[] = [$this, 'calculatorFormSucceeded']; return $form; } /** * Funkce se vykonaná při úspěšném odeslání formuláře kalkulačky a zpracuje odeslané hodnoty. * @param Form $form formulář kalkulačky * @param ArrayHash $values odeslané hodnoty formuláře */ public function calculatorFormSucceeded($form, $values) { // Necháme si vypočítat výsledek podle zvolené operace a zadaných hodnot. $this->result = $this->calculatorManager->calculate($values->operation, $values->x, $values->y); }
Je toho viac, takže to vezmeme pekne poporiadku. Prvá metóda je
špeciálna metóda pre tvorbu komponentov, ktorá sa definuje ako
createComponent<název_komponenty>()
a vracia požadovanú
komponent. Len upozorňujem, že u tejto metódy stačí, aby bola
protected
. Ak metóda spĺňa tieto podmienky, môžeme jej potom
zavolať priamo zo šablóny a to pomocou špeciálneho Latte makra
{control}
, čo si za chvíľu ukážeme.
Ďalej pár slov k samotnému formulári. Definujeme tu celkom 4 prvky:
- Pole radio inputov, ktoré slúžia pre výber operácie výpočtu. Tu si môžete všimnúť volanie metódy z modelu, ktorá nám vráti univerzálne všetky dostupné operácie. Ďalej nastavujeme predvolenú hodnotu na sčítanie a že je povinné toho pole vyplniť.
- Text input pre zadanie prvého čísla, kde nastavíme, že sa jedná o typ inputu number, čo platí pre prehliadače podporujúce HTML5. Ďalej určíme predvolenú hodnotu 0 a validačné pravidlo, že toto pole musí byť vyplnené a iba hodnotou celého čísla.
- Text input pre zadanie druhého čísla, ktorý je identický s tým prvým, iba obsahuje navyše pravidlo, kde ošetríme delenie nulou, ako som sľúbil. Teraz by asi bola na mieste diskusia, prečo som to ošetril tu a nie už v modeli. Samozrejme to možno urobiť oboma spôsobmi. Ja som sa ale rozhodol demonštrovať, že presenter by mal spracovať všetky dáta z šablóny a do modelu už by mala ísť len tie dáta, s ktorými tento model vie pracovať. Naviac tu môže dôjsť k validáciu už na strane užívateľa a celkovo je tento spôsob efektívnejší, než napríklad vyhadzovať nejaké výnimky z modelu.
- Submit button ako jednoduché tlačidlo pre odoslanie formulára.
Nakoniec sa formulári odovzdá funkcia, ktorá sa volá pri jeho úspešnom
odoslaní a do parametra dostane užívateľom zadanej hodnoty. Chcel by som tu
upozorniť na to, že úspešné odoslanie formulára znamená jeho kompletné
validáciu na strane klienta i servera podľa zadaných pravidiel, tzn. že do
metódy calculatorFormSucceeded()
sa dostanú už len hodnoty, s
ktorými vie náš model pracovať. V tejto metóde potom len stačí zavolať
univerzálny výpočtový funkciu z modelu, odovzdať jej potrebné hodnoty od
užívateľa a výsledok uložiť do $this->result
. Teraz je
náš presenter už kompletný, avšak cesta k nemu nie je úplne jasná. Poďme
to napraviť.
Routovanie v Nette
Keďže sme nahradili pôvodné triedu HomepagePresenter
našej
vlastnej, musíme upraviť aj router, ktorý k nemu určoval cestu, tj. Pod akou
URL ho nájdeme. V Nette k tomu slúži tzv. RouterFactory
a opäť
verím, že tí bystrejší z vás si všimli jej definícia v
config.neon
pri nastavovaní DI. Teraz ju potrebujeme upraviť tak,
aby pod predvolené URL bol práve náš presenter.
App / router / RouterFactory.php
Takže si otvoríme príslušný súbor a takto si ho upravíme:
<?php namespace App; use Nette\Application\IRouter; use Nette\Application\Routers\Route; use Nette\Application\Routers\RouteList; use Nette\StaticClass; class RouterFactory { use StaticClass; /** * @return IRouter */ public static function createRouter() { $router = new RouteList; $router[] = new Route('<presenter>/<action>[/<id>]', 'Calculator:default'); return $router; } }
Teraz je pod predvolený URL adresou náš presenter a jeho akcie default
(metóda renderDefault()
). Teraz už zostáva len posledná časť
skladačky a tou je šablóna.
Šablóna (View)
Ako už bolo riešené v prvej lekcii, Nette používa vlastný šablónovacích systém Latte. V ňom si teraz vytvoríme šablónu pre našu aplikáciu. Ako vzor si necháme pôvodnú šablónu, len ju trochu upravíme.
App / presenters / templates / Calculator / default.latte
Najskôr pôjdeme do zložky app/presenters/templates/
a tu
premenujeme zložku Homepage/
na Calculator/
. V nej sa
potom nachádza súbor default.latte
, ktorý poslúži ako
šablóna pre našu akciu default a my ho len upravíme:
{block content} <div id="banner"> <h1 n:block=title>Kalkulačka</h1> </div> <div id="content"> <h3 n:ifset=$result>Výsledek je: {$result}</h3> {control calculatorForm} </div> <style> ...
Ako je vidieť, <style>
zachováme a upravíme len kód
nad ním.
Najprv upravíme <h1>
, ktorý vďaka makre
n:block=title
slúži zároveň aj ako html
<title>
pre celú stránku.
Následne vymažeme obsah <div id="content">
a doplníme
naše vypísanie výsledku napr. Do <h3>
. Pomocou
{$result}
sa tu zobrazí dáta odovzdané z prezentačného a
pomocou makra n:ifset
sa výsledok zobrazí iba ak nie je
null
.
Celý definovaný formulár potom vykreslíme do šablóny pomocou už
spomínaného makra {control <název_komponenty>}
a názvu
nášho formulára (metódy createComponent*()
). A tým je naša
práca na šablóne aj na celom projekte hotová. Ak teraz otvoríte URL
projektu, uvidíte tu plne funkčné kalkulačku a môžete na nej vyskúšať
všetky chytáky, ktoré vás napadnú
Ak vám nie je čokoľvek jasné, stiahnite si projekt z prílohy a prejdite si ako sa dáta odovzdávajú z modelu do prezentačného zariadenia a odtiaľ do šablóny. Kódu v aplikácii toľko nemáme, po chvíli by ste sa mali zorientovať. Ak ani to nepomôže, určite vám MVC / MVP objasní seriál Jednoduchý redakčný systém v PHP objektovo (MVC).
To je pre dnešné lekciu naozaj všetko, ale nebojte. V budúcej lekcii, Jednoduchý redakčný systém v Nette - Štruktúra projektu , začneme úplne novú poriadnu aplikáciu v Nette
Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami
Stiahnuté 1341x (877.59 kB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP