Připojení komponenty k rodiči

Komponentou v terminologii Nette Frameworku je každá implementace Nette\ComponentModel\IComponent. O komponentách platí, že mohou mít rodiče. Ve skutečnosti tomu je tak, že ho bude mít každá (výjimku tvoří například Nette\Application\UI\Presenter, který stojí v roli nejvyššího rodiče, kořene komponentového stromu). Nás bude zajímat okamžik, kdy se komponenta ke svému rodiči připojuje.

Existují 2 způsoby, jak se může komponenta ke svému rodiči připojit: konstruktor a metoda addComponent().

Připojení přes konstruktor

Konstruktor třídy Nette\ComponentModel\Component rovnou poskytuje rozhraní pro nastavení rodiče. Prvním argumentem je instance rodiče, druhým je název komponenty. Jak vypadá využití tohoto rozhraní v praxi? Komponentu budeme typicky tvořit v továrničce:

protected function createComponentFoobar($name)
{
    $foobar = new Foobar($this, $name);
}

Naše komponenta Foobar (která samozřejmě dědí od Component) v továrničce přijímá za rodiče třídu, která ji tvoří. S takovýmto kódem se obvykle setkáváme v presenterech – a skutečně zcela logicky presenter je obvykle rodičem první generace našich komponent.

Připojení metodou addComponent()

Nette je však framework pro pohodlné a líné programátory, a tak nabízí užitečnou zkratku. Továrničky na komponenty (obecně všechny metody s prefixem createComponent) se volají v metodě getComponent($name) v případě, že požadovaná komponenta ještě nebyla vytvořena.

Pokud se podíváme do útrob této metody, zjistíme, že instance vrácená z továrničky je ještě zkontrolována, zdali už má rodiče nastaveného. Pokud ne, je rodič (i jméno) nastaven druhou možnou cestou: manuálním přidáním potomka metodou addComponent() na rodiči. Díky ní můžeme továrničku zkrátit na nezbytné minimum, a starost o rodiče a jméno komponenty nechat frameworku.

protected function createComponentFoobar()
{
    return new Foobar;
}

Tato skutečnost nám dovoluje i libovolně přepsat naší komponentě konstruktor. Ovšem vzhledem k tomu, že obvykle budeme dědit spíše od Nette\Application\UI\Control, je do verze Nette 2.0.6 best-practice vždy volat parent::__construct(), ačkoliv spoleháme na 2. způsob nastavení rodiče. Od verze 2.0.7 to již potřeba není.

Jaké jsou rozdíly?

Skoro by se chtělo říci, že 2. způsob by měl být díky své pohodlnosti jednoznačně upřednostněn. Věc se má však s komponentami krapet složitěji. Nesmíme totiž zapomenout na monitorování předků a s tím související metodu attached().

Tato protected metoda je volána v okamžiku připojení komponenty ke svému rodiči (tedy buď v konstruktoru nebo po vrácení nové komponenty z továrničky, jak jsme zmapovali ve 2. způsobu). A právě kvůli tomu je důležité, který ze způsobů připojení rodiče použijeme.

Je třeba mít na paměti, že před připojením k rodiči nemusí být komponenta v plně inicializovaném stavu (nebude mít přístup k presenteru, který je ultimátním rodičem všech apod.).

Můžeme si vzít za příklad formuláře. Obvykle používána implementace Nette\Application\UI\Form si v metodě attached() nastavuje podle aktuálního presenteru atribut action. Pokud bychom tedy chtěli s touto vygenerovanou hodnotou dále pracovat v továrničce, musíme zajistit připojení formuláře k rodiči ještě předtím, tedy pomocí konstruktoru. V opačném případě nebude ještě hodnota action nastavena.