IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

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 / CalculatorPre­senter.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:

  1. 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ť.
  2. 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.
  3. 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. :)
  4. 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é 1338x (877.59 kB)
Aplikácia je vrátane zdrojových kódov v jazyku PHP

 

Predchádzajúci článok
Prvé aplikácie v Nette
Všetky články v sekcii
Základy Nette frameworku
Preskočiť článok
(neodporúčame)
Jednoduchý redakčný systém v Nette - Štruktúra projektu
Článok pre vás napísal Jindřich Máca
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Autor se věnuje převážně webovým technologiím, ale má velkou zálibu ve všem vědeckém, nejen ze světa IT. :-)
Aktivity