[2009-07-13] Nette\Application\Control má ArrayAccess interface
- David Grudl
- Nette Core | 8218
Nette\Application\Control implementuje rozhraní ArrayAccess, přes které lze přistupovat k jeho subkomponentám. Tutéž funkcionalitu měl doposud jen formulář (resp. FormContainer).
Hlavní výhodou je, že místo
$presenter->getComponent('abcd')
lze psát
$presenter['abcd']
.
Dále od revize 403 je ve třídě Control chytřejší továrna na
komponenty. Pokud požádáme o komponentu $presenter['abcd']
a
tato ještě nebyla vytvořena, podívá se framework, zda existuje metoda
createComponentAbcd()
a zavolá ji. V metodě komponentu
vytvoříme a buď vrátíme pomocí return, nebo rovnou připojíme
k rodičovskému objektu.
Mění se tak postup, jak vytvářet v presenteru (a nejen v něm)
komponenty. Použití metod beforePrepare()
a
prepare<View>()
je považováno za
zastaralé. Nahradily je továrničky. Komponenty dnes také není
potřeba předávat do šablon, lze k nim přistupovat přes
$presenter['abcd']
. Pro renderování existuje nové makro
{control abcc}
, které se přeloží jako
$presenter['abcd']->render()
.
Nové postupy jsou obsaženy i v příkladech v distribuci.
- kutilm
- Člen | 21
Ahoj,
mohly by být widgety uložené v promměné?
Příklad:
{control $myWidget}
Využití:
{foreach $myWidgets as $myWidget}
{control $myWidget}
{/foreach}
A pak ještě jeden nápad, dalo by se volitelně volat jinou renderovací
funkci?
Například:
{control abcd:xyz}
by volala
$control->getWidget("abcd")->renderXyz()
. Jen tím
oddělovačem si nejsem jist, jaký by měl být.
Děkuji
- jasir
- Člen | 746
kutilm napsal(a):
A pak ještě jeden nápad, dalo by se volitelně volat jinou renderovací funkci?
Například:
{control abcd:xyz}
by volala$control->getWidget("abcd")->renderXyz()
. Jen tím oddělovačem si nejsem jist, jaký by měl být.
Tohle funguje. Dokonce i ten oddělovač jsi trefil… :-)
Editoval jasir (22. 7. 2009 11:21)
- brabo
- Člen | 19
Ahoj,
je nezbytné, aby byly metody rozhraní ArrayAccess
třídy
Control
označeny za final
?
Mám problém v tom, že mám již z dřívějška vlastní control
(renderovatelný), který implementuje ArrayAccess
. Verze 0.9 mi
teď nefunguje, protože nové metody z Control
nemůžu
překrýt.
Teoreticky podle mě není důvod, aby metody byly finální? Z principu
podle mě není chybné, aby si nějaký potomek Control
udělal
přístup po svém – jako to mám teď já. Přece to nebudu muset celý
předělávat, že ne? ;-)
- brabo
- Člen | 19
brabo napsal(a):
Ahoj,
je nezbytné, aby byly metody rozhraní
ArrayAccess
třídyControl
označeny zafinal
?Mám problém v tom, že mám již z dřívějška vlastní control (renderovatelný), který implementuje
ArrayAccess
. Verze 0.9 mi teď nefunguje, protože nové metody zControl
nemůžu překrýt.Teoreticky podle mě není důvod, aby metody byly finální? Z principu podle mě není chybné, aby si nějaký potomek
Control
udělal přístup po svém – jako to mám teď já. Přece to nebudu muset celý předělávat, že ne? ;-)
Když jsem si ručně v Nette Control
zrušil ty metody jako
finální, tak všechno funguje bez problémů. Jak Nette, tak můj extendovaný
Control. Jenže problém je, že bych musel editovat takhle jádro, což
rozhodně není košer ;). Šlo by to v jádře Nette upravit?
- romansklenar
- Člen | 655
Myslím, že ne. Dočasně byla tahle feature zneaktivována, dokud se
neupravil DataGrid
, který si taky implementoval rozhraní po
svém, ale po jeho refaktoringu se to vrátilo zpátky. A je to rozhodně
plus – donutilo mě to udělat vnitřní refactoring, který jsem dlouho
odkládal, a vnitřní strom komponent se stal hned čitelnějším.
- brabo
- Člen | 19
OK, strávil jsem několik hodin s pokusy to přepsat, ale vždycky narazím na další omezení někde jinde, kde je nějaká metoda nevhodná a taky finální.
Abyste byli v obraze. Mám udělanou kontrukci stromu, který se skládá z uzlů (Component). Každý uzel má referenci na rodiči a pole potomků. To je OK. Celé to zastřešuje ale renderovatelný Control stromu, co jednak umí se stromem různě pracovat, ale i poskytuje přes ArrayAccess přístup k uzlům podle ID.
No a to je ten problém. Díky finálním metodám mi teď tenhle přístup nejde použít a když to přepíšu aby uzly byly klasicky komponenty kontejneru tak narazím na to, že jméno komponenty musí (pro mě nepochopilelně) být jenom nečíselné. Jenže já mám uzly očíslovány právě číselně… Tohle omezení samozřejmě zrušit nemůžu, protože je opět finální…
- David Grudl
- Nette Core | 8218
brabo napsal(a):
No a to je ten problém. Díky finálním metodám mi teď tenhle přístup nejde použít
V podstatě právě proto je to final, aby existovala záruka, že array access přístup v každé Control dělá to, co se očekává, přesněji co očekává i samotný framework.
a když to přepíšu aby uzly byly klasicky komponenty kontejneru tak narazím na to, že jméno komponenty musí (pro mě nepochopilelně) být jenom nečíselné.
Čísla by měly fungovat.
- David Grudl
- Nette Core | 8218
kravco napsal(a):
Je nejaký dôvod, prečo nemôže byť ArrayAccess implementovaný už v ComponentContaineri?
To by se mi zdálo jako docela omezující prvek pro obecné komponenty.
- kravčo
- Člen | 721
Totiž, napadlo mi to, keď som skúmal implementácie
ArrayAccessu
v Control
a FormContainer
(obe dedia ComponentContainer
) a implementujú ho rovnako.
Samozrejme toto nie je argument, no keď som sa zamyslel, prišlo mi to
logické.
Všeobecný kontajner komponentov pristupuje k svojim „deťom“ v tom istom duchu, podľa mena. Nejde mi o kratší, či prehľadnejší zápis, skôr o jednotnosť v rámci rámca.
- Honza Marek
- Člen | 1664
David Grudl napsal(a):
kravco napsal(a):
Je nejaký dôvod, prečo nemôže byť ArrayAccess implementovaný už v ComponentContaineri?
To by se mi zdálo jako docela omezující prvek pro obecné komponenty.
Nešlo by to udělat v ComponentContaineru nefinálně a v PresenterComponent to zfinalizovat?
- Davelister
- Člen | 28
Zdravím,
Mám dotaz k implementaci metody ComponentContainer::createComponent($name):
<?php
/**
* Component factory. Delegates the creation of components to a createComponent<Name> method.
* @param string component name
* @return void
*/
protected function createComponent($name)
{
$ucname = ucfirst($name);
$method = 'createComponent' . $ucname;
if ($ucname !== $name && method_exists($this, $method) && $this->getReflection()->getMethod($method)->getName() === $method) {
$component = $this->$method($name);
if ($component instanceof IComponent && $component->getParent() === NULL) {
$this->addComponent($component, $name);
}
}
}
?>
Z implementace vyplívá, že pokud budu chtít načíst komponentu s velkým písmenem na začítků mám smůlu.
Když jsem začínal s nette, pojmenoval jsem si komponentu s velkým písmenem na začátku a problém byl na světe.
O něčem takovém jsem neměl potuchy,a když se mi komponenty pořád nenačítaly dospěl z závěru že createComponent<name>() nefunguje a tak jsem si přepsal implementaci createComponent($name) za jinou kterou jsem našel tady na foru.
Teď už chapu, že je potřeba sjednotit velikost písmen na začátku názvu komponenty, ale jako začátečník jsem měl jiné starosti.
CO tím chci říci je, že by bylo by dobré, kdyby by createComponent($name) při pokusu načíst komponentu s velkým písmenem na začátku vygenerovala nějaký E_USER_NOTICE, aby odpadl tento problém. To že neudělá nic je matoucí.
Editoval Davelister (2. 1. 2010 17:42)
- v6ak
- Člen | 206
Honza Marek napsal(a):
Nešlo by to udělat v ComponentContaineru nefinálně a v PresenterComponent to zfinalizovat?
Vzhledem ke znovuotevření si dovolím komentovat toto starší téma.
Přijde mi to jako heavy hack, neboť by sice ComponentContainer tyto metody definoval, ale umožňoval by je změnit a přiřadit jim úplně jinou logiku. (Proč by jinak nebyly ty metody finální již v ComponentContaineru?) Mohlo by to vést k polymorfnímu WTF – pracoval bych s obecným ComponentContainerem, předpokládal bych jeho obecné chování ohledně ArrayAccess a místo toho bych dostal chování úplně jiné. Tomu rozhodně neříkám správný OOP návrh.