EN | CS | Přihlásit | Registrovat

Nette\Applica­tion\Control

Control je vykreslitelná komponenta.

Ta si umí navíc, kromě toho že se umí vykreslit, zapamatovat, jestli při subrequestu došlo ke změnám, které si vyžadují jej překreslit. K tomu slouží triptych metod invalidateControl(), validateControl() a isControlInvalid(), což je základem AJAXu v Nette.

Nette však nabízí ještě jemnější rozlišení, než na úrovni Controlů, a to tzv. snippetů neboli ústřižků.

Poznámka: pro jednoduchost k pochopení budu v následujících odstavcích brát Control jako komponentu. To, že je vykreslitelná, vyplývá z překreslovací vlastnosti snippetů.

Lze tedy invalidovat/va­lidovat na úrovni těchto snippetů (každá komponenta může mít libovolné množství snippetů). Pokud se invaliduje celou komponentu, tak je i každý snippet považován za invalidní. Komponenta je invalidní i tehdy, pokud je invalidní některá její subkomponenta. Komponenta, která přijímá signál, je automaticky označena za invalidní.

Díky invalidaci snippetů přesně víme, které části kterých prvků bude potřeba překreslit.

Komponenta (tedy přesněji vykreslitelná komponenta Control) nepředstavuje pravoúhlou oblast ve stránce, ale logickou komponentu, která se může renderovat i do více podob. Každá komponenta může být navíc na stránce vykreslena vícekrát, nebo podmíněně, nebo pokaždé s jinou šablonou atd.

Komponenta Control ač má mnoho společných rysů s Presenterem nemá svůj životní cyklus v pravém slova smyslu. Jen metody attached() a detached() umožňují detekovat, kdy byl Control připojen k nebo odpojen od rodiče (presenteru či jiné komponenty).

O zachycení signálu se stará presenter, ten ho odevzdá komponentě, která je jeho příjemcem. Protože presenter je sám o sobě komponentou, tak ho klidně odevzdá i sám sobě.

Šablony

Třída Control obsahuje továrničku createTemplate() na svou šablonu. Ta standardně vytvoří šablonu, předá ji některé základní proměnné a zaregistruje standardní helpery:

{**
* Template's description.
*
* @param Presenter $presenter
* @param Control $control
* @param Template $template
* @param array $flashes
* @param string $baseUri Environment::getVariable('baseUri');
*
* You can use these helpers:
* escape, escapeJs, escapeCss, cache,
* snippet, lower, upper, capitalize, stripTags,
* strip, date, nl2br, truncate, bytes
*}

Pro pohodlnější práci v šablonách (hlavně v při vaší další práci v budoucnu) by každá šablona měla obsahovat hlavičku popisující proměnné, které v ní lze využívat.

Strom komponent

Každá komponenta děděná z třídy Control má jako první parametr konstruktoru rodiče (IComponentContainer) v hierarchii stromu komponent. Rodičem může být Presenter, nějaká komponenta nebo jakýkoliv jiný objekt implementující rozhraní IComponentContainer. Hierarchie pak může vypadat i nějak takto:

Presenter
  |
  --Control { implementuje IComponentContainer => může být rodičem }
     |
     --Component
     |
     --Component { neimplementuje IComponentContainer => nemůže být rodičem }
     |
     --Control
        |
        --Component

Protože Control samotný neumí generovat odkazy, ale jen signály, potřebujeme jej svázat s Presenterem. Podle struktury a zanoření hierarchie se můžeme k presenteru dovolat i z podkomponent a používat jeho veřejné metody.

$presenter = $control->getPresenter();

Hierarchie vzníká připojováním komponent do stromu komponent. Při vytváření komponenty uvedeme v parametru konstruktoru instanci jeho rodiče a řetězec se jménem komponenty. Uvedením stejné komponenty pod různými jmény se dá dosáhnout například zobrazení jedné komponenty na stránce vícekrát.

Komponentový model Nette umožňuje velmi dynamickou práci se stromem (komponenty můžeme vyjímat, přesouvat, přidávat), proto by byla chyba se spoléhat na to, že po vytvoření komponenty je hned znám rodič, rodič rodiče atd. Nemusí být.

$control = new NewsControl;
// ...
$parent->addComponent($control, 'shortNews');

// nebo alternativně starším (statickým) způsobem
$control = new NewsControl($parent, 'shortNews');

Flash zprávy

Vizuální komponenta Control má své vlastní úložiště flash zpráv nezávislé na presenteru (metoda flashMessage patří třídě Control).

Jde o zprávy, které např. informují o výsledku operace a uživateli se zobrazí až po přesměrování. Zasílání obstarává metoda flashMessage() třídy Control (tj. je možno zasílat zprávy i na úrovni komponent).

Kód presenteru nebo komponenty:

public function deleteFormSubmitted(AppForm $form)
{
Model::delete(); // něco smažeme
$this->flashMessage('Položka byla smazána.');

// nebo pokud chceme uložit zprávu přímo do presenteru
$this->getPresenter()->flashMessage('Položka byla smazána.');

$this->redirect('default');
}

Metoda flashMessage() zprávu vkládá přímo do šablony do parametru flashes (jako pole objektů stdClass). Šablona pro vypsání zpráv pak může vypadat třeba takto:

{foreach $flashes as $flash}
<div class="flash">{$flash->message}</div>
{/foreach}

Jako druhý parametr metody lze uvést typ zprávy (výchozí hodnota je „info“) nebo její kód.

$this->flashMessage('Položka nebyla smazána!', 'warning');

Typ zprávy pak lze použít například jako CSS třídu:

{foreach $flashes as $flash}
<div class="flash {$flash->type}">{$flash->message}</div>
{/foreach}

Také je možné do zprávy přidat extra informace:

$message = $this->flashMessage('Obrázek byl uložen.');
$message->image = $image;
$message->width = 123;

Nejdůležitejší samozřejmě je, že pokud po uložení zprávy flashMessage() následuje přesměrování, bude i v dalším požadavku v šabloně existovat stejný parametr flashes. Zprávy zůstanou poté živé další 3 sekundy – například pro případ, že by z důvodu chybného přenosu uživatel stránku dal obnovit. Pokud někdo dvakrát za sebou obnoví stránku (F5), tak mu zpráva tedy nezmizí, pokud klikne jinam, tak ji už neuvidí.

Příklad zpracování událostí komponenty s flashovými zprávami

Tento způsob vede k lepší znovupoužitelnosti komponenty, na událost si její vlastník reaguje zcela po svém.

class Komponenta extends Control
{
/** @var array handlery události Xyz */
public $onXyz;

public function handleLogin()
{
...
$this->onXyz(); // volej handlery
}
}

class HomepagePresenter extends Presenter
{
public function startup()
{
$komponenta = new Komponenta($this, 'k');
$komponenta->onXyz[] = array($this, 'xyzHandler'); // registruje handler
}

public function xyzHandler()
{
$this->flashMessage('Uživatel byl přihlášen.');
}
}

Viz také:


Login to submit a comment