[2009-07-13] Nette\Application\Control má ArrayAccess interface

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
David Grudl
Nette Core | 8138
+
0
-

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
+
0
-

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
+
0
-

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)

kutilm
Člen | 21
+
0
-

Wau, opravdu gunguje:) Dík

Akorát to nefunguje na widget v proměnné:
{control $abcd:xyz} → $control->getWidget($abcd)->renderXyz()

Což je asi logické, když nefunguje ani ta promměnná samotná.

brabo
Člen | 19
+
0
-

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
+
0
-

brabo napsal(a):

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? ;-)

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
+
0
-

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
+
0
-

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í…

kravčo
Člen | 721
+
0
-

Je nejaký dôvod, prečo nemôže byť ArrayAccess implementovaný už v ComponentContaineri?

David Grudl
Nette Core | 8138
+
0
-

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 | 8138
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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
+
0
-

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.