Komponentový model
Důležitým pojmem v Nette je komponenta. Do stránek vkládáme vizuální interaktivní komponenty, komponentami jsou i formuláře nebo
všechny jejich prvky. Základní dvě třídy, od kterých všechny tyto komponenty dědí, jsou součástí balíčku
nette/component-model
a mají za úkol vytvářet stromovou hierarchii komponent.
Component
Nette\ComponentModel\Component je
společným předkem všech komponent. Obsahuje metody getName()
vracející název kompoenty a metodu
getParent()
vracející jejího rodiče. Obojí lze nastavit metodou setParent()
– první parametr je
rodič a druhý název komponenty.
lookup(string $type): ?Component
Vyhledá v hierarchii směrem nahoru objekt požadované třídy nebo rozhraní. Například
$component->lookup(Nette\Application\UI\Presenter::class)
vrací presenter, pokud je k němu, i přes několik
úrovní, komponenta připojena.
lookupPath(string $type): ?string
Vrací tzv. cestu, což je řetězec vzniklý spojením jmen všech komponent na cestě mezi aktuální a hledanou komponentou.
Takže např. $component->lookupPath(Nette\Application\UI\Presenter::class)
vrací jedinečný identifikátor
komponenty vůči presenteru.
Container
Nette\ComponentModel\Container je
rodičovská komponenta, tj. komponenta obsahující potomky a tvořící tak stromovou strukturu. Disponuje metodami pro snadné
přidávání, získávání a odstraňování objektů. Je předkem například formuláře či tříd Control
a
Presenter
.
getComponent(string $name): ?Component
Vrací komponentu. Při pokusu o získání nedefinovaného potomka je zavolána továrna createComponent($name)
.
Metoda createComponent($name)
zavolá v aktuální komponentě metodu
createComponent<název komponenty>
a jako parametr jí předá název komponenty. Vytvořená komponenta je
poté přidána do aktuální komponenty jako její potomek. Těmto metodám říkáme továrny na komponenty a mohou je
implementovat potomci třídy Container
.
getComponents(): array
Vrací přímé potomky jako pole. Klíče obsahují názvy těchto komponent. Poznámka: ve verzi 3.0.x metoda namísto pole vracela iterátor a její první parametr určoval, zda se mají komponenty procházet do hloubky, a druhý představoval typový filtr. Tyto parametry jsou deprecated.
getComponentTree(): array
Získá celou hierarchii komponent včetně všech vnořených podřízených komponent jako indexované pole. Prohledávání jde nejprve do hloubky.
Monitorování předků
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 (v konstruktoru) znám rodič, rodič rodiče atd. Většinou totiž rodič při vytvoření vůbec známý není.
Jak poznat, kdy byla komponenta připojena do stromu presenteru? Sledovat změnu rodiče nestačí, protože k presenteru mohl
být připojen třeba rodič rodiče. Pomůže metoda monitor($type, $attached,
$detached). Každá komponenta může monitorovat libovolný počet tříd a rozhraní. Připojení nebo odpojení je
ohlášeno zavoláním callbacku $attached
resp. $detached
, a předáním objektu
sledované třídy.
Pro lepší pochopení příklad: třída UploadControl
, reprezentující formulářový prvek pro upload souborů
v Nette Forms, musí formuláři nastavit atribut enctype
na hodnotu multipart/form-data
. V době
vytvoření objektu ale k žádnému formuláři připojena být nemusí. Ve kterém okamžiku tedy formulář modifikovat?
Řešení je jednoduché – v konstruktoru se požádá o monitoring:
class UploadControl extends Nette\Forms\Controls\BaseControl
{
public function __construct($label)
{
$this->monitor(Nette\Forms\Form::class, function ($form): void {
$form->setHtmlAttribute('enctype', 'multipart/form-data');
});
// ...
}
// ...
}
a jakmile je formulář k dispozici, zavolá se callback. (Dříve se místo něj používala společná metoda
attached
resp. detached
).