Odchycení okamžiku, kdy je komponenta připojená k presenteru

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

Chci přidat do Nette univerzální způsob, jak odchytit v továrničce okamžik, kdy se komponenta připojí k presenteru. Tedy okamžiku, kde jsou načtené její parametry, v případě formulářů hodnoty polí atd. Velmi se to hodí pro různé provázané selectboxy a podobně.

Přímo v presenteru to jde vyřešit snadno:

class MyPresenter
{
	function createComponentForm()
	{
		$form = new Form;
		$this['form'] = $form; // propojení

		$form->addSelect('first');
		$first = $form['first']->getValue();
		$form->addSelect('second', NULL, $this->getData($first));
		...
		return $form;
	}
}

Ale v komponentě už to fungovat nebude.

Původně jsem uvažoval nad vytvořením události onAttached (nebo onAnchored):

class SuperComponent // or MyPresenter
{
	function createComponentForm()
	{
		$form = new Form;
		$form->onAttached[] = function ($form) {
			// tady už je formulář připojený, známe hodnoty polí
			$form->addSelect('first');
			$first = $form['first']->getValue();
			$form->addSelect('second', NULL, $this->getData($first));
			...
		}
		return $form;
	}
}

Ale teď mě napadlo, že by se to dalo udělat i bez zanoření takřka celého kódu dovnitř closure:

class SuperComponent // or MyPresenter
{
	function createComponentForm()
	{
		$form = new Form;
		yield $form;

		// tady už je formulář připojený, známe hodnoty polí
		$form->addSelect('first');
		$first = $form['first']->getValue();
		$form->addSelect('second', NULL, $this->getData($first));
		...
	}
}

Kterou cestou jít?

Je mi jasné, že mnoho programátorů vidí yield poprvé v životě a může jim druhý způsob připadat nesrozumitelný, ale předpokládám, že se stejně začne v Nette využívat častěji. Jde o použití yield jakožto await.

newPOPE
Člen | 648
+
+7
-

Sposob 1. viac pasuje z hladiska fw. Sposob 2. viac z hladiska jazyka.

Siel by som cestou 1.

stekycz
Člen | 152
+
+14
-

Za mě je lepší event

  1. Dokážu si představit, že budu chtít dělat i jiné věci než které popisuješ
  2. Listenerů mohu chtít mít více, v případě použití Kdyby/Events nebo jiných knihoven i ten kód může být zcela jinde a nejedná se o velké zanoření
  3. Lze backportovat i pro verze Nette s podporou PHP bez yieldu
  4. Odsazení mi zase tak moc nevadí, yield sice nevidím poprvé, ale stále je to pro mě méně explicitní, že část lineárně vypadajího kódu neběží zcela linéarně
Martin Mach
Člen | 1
+
0
-

První způsob se mi zdá víc intuitivní, koresponduje s dalšími callbacky. Ano, druhý způsob sice využívá (relativně) nově přidanou feature jazyka, ale přijde mi, že jediný důvod pro implementaci tímto způsobem je „protože můžeme“.

Jan Tvrdík
Nette guru | 2595
+
+5
-

yield mám rád, ale zrovna tohle použití mi přijde dost divné. Co budeš dělat, když tam těch yield bude víc? Přijde mi to stejně nesmyslné jako spojit action* a render* metody do jedné a oddělit je jedním yieldem.

A hlavně, když bude ten kód někdo číst, tak to nemá šanci pochopit.

Eda
Backer | 220
+
+1
-

Osobně jsem spíše pro variantu 1). Je přehlednější (obzvlášť pro začátečníky), méně tricky (vzpomeňme na různé „tricky“ rádoby „hezké“ věci, které nyní z Nette\Object odstraňujeme) a rozšiřitelnější (jak už tu padlo).

Jinak: yield už ve svých projektech na několika místech mám :-)

David Grudl
Nette Core | 8227
+
0
-

Tohle je vlastně yield použitý jako await, není to nic neobvyklého. Viz třeba https://jakearchibald.com/…c-functions/,

David Grudl
Nette Core | 8227
+
+1
-

@stekycz můžeš to vnímat tak, že yield $form; nahrazuje $this[$name] = $form;, tedy propojení s rodičem. Vytvoříš komponentu, propojíš ji a pak dokončíš její nastavení. To je oč tu běží.

Postup je pak přímočarý.

Naopak event do toho vnáší složitost, odbíhá od požadavku „potřebuji propojit form s presenterem, abych mohl dokončit jeho sestavení“ a vede k otázkám, které pokládáš.

CZechBoY
Člen | 3608
+
0
-

Ja uz onAttached mam ve vsech svych BaseControl a BaseForm :)
Takze jsem jedine pro (me) mene wtf onAttached.

mkoubik
Člen | 728
+
+1
-

Víc se mi líbí ten yield, ale přesto k mi to nepřijde úplně perfektní.
Doba kdy bude většina programátorů yield znát a používat stejně jako jiné konstrukce přijde časem, o to bych se nebál.
Spíš mi na tom moc nesedí, že z toho kódu na první pohled nepoznám co se děje. Vidím, že v půlce metody předám $form nadřazené metodě aby si s ním něco udělala, ale nevidím tam proč. Ten koncept není na rozdíl od onAttached nijak pojmenovaný. Nevím co se stane když ten form yieldnu víckrát, nebo když yieldnu úplně jinou hodnotu.
Trochu mi to připomíná list($cat, $dog) = $this->getAnimals(), protože yield je původně určený pro vracení generátorů – ne pro postupné vracení různých hodnot, stejně jako return [...] je určené pro vracení iterovatelné hodnoty, ne několika různých hodnot.

blindAlley
Člen | 31
+
0
-

Mne se to tedy s tím yield také moc nezdá i když člověk ví, jak yield funguje – await – není vůbec jasné, že ten kód za yield se vykoná po připojení k presenteru. U události onAttached to je jasné na první pohled.

Využití yield vidím především jako skutečný generátor, příklad:
na stránce mám x komponent, jaké přesně se řídí konfigurací. Někde (v šabloně) pak budu v cyklu volat tenhle generátor, který mi bude vracet komponenty podle té konfigurace.

David Grudl
Nette Core | 8227
+
0
-

Název onAttached by měl být kvůli konzistenci s jinýma on... proměnnýma bez toho ed, tedy jen onAttach. Zároveň není úplně zřejmé, k čemu byla komponenta připojena.

Dalo by se použít taky onAnchor, protože se to už v této souvislosti používá.

Případné nějaké onPresenter

duke
Člen | 650
+
0
-

onAnchor zní dobře. onPresenter určitě ne, za on by mělo následovat sloveso.
Jinak rozdíl mezi onAnchor a onAttach chápu tak, že zatímco onAttach by se volalo při připojení (i zprostředkovaném) k libovolné komponentě, onAnchor jen při připojení (i zprostředkovaném) k presenteru.

potapnik
Člen | 127
+
0
-

Vetsinou preferuji delsi nazvy a delsi ale pochopitelnejsi kod a i kdyz se mi zkratka formou yield docela libi, priklanel bych se k onXXX, protoze je naprosto zrejme, kdy to nastava a co se v tu chvili deje. A nebal bych se pouzit nazev toho, co to opravdu dela, tedy treba onLinkedToPresenter[] nebo onAttachedToPresenter[], zcela jasne z toho vyplyne kdy a co se stalo. Mozna spis to linked, protoze attached se vaze na nadrazenou komponentu a mohlo by to byt mirne WTF…

CZechBoY
Člen | 3608
+
+4
-

@potapnik nebo onPresenterAttached?

Felix
Nette Core | 1245
+
0
-

Chtel jsem napsat uz drive, ale nechal jsem si to vice projit hlavou.


Yield je super vec, pouzivam ji na par veci, ale je zatim docela magie. Prijde mi, ze php programator na to zatim neni tak pripraveny, jako napriklad v Jave.

V ramci konzistentnosti „eventu“ v Nette, si myslim, ze by bylo fajn mit on<> event.

Presne nyni nastava dilema, jestli onAnchorer ci onAttacher. Ja osobne bych byl pro onAttached a to z par duvodu.

  1. V nette uz jsou zavedene metody attached/detached, coz ty co uz trochu pronikli do Nette, tak umi pouzivat. Ti lide vedi, ze tam nemusi prijit jenom presenter. Proto se tam dava klasicky tento kod.
protected function attached($obj)
{
	if ($obj instanceof Presenter) {
		// do some magic...
	}
}
  1. Muze se stat, ze bych chtel ziskat i jineho predka/komponentu nez jenom presenter. Bylo by to stejne jako u ComponentModelu. Na programatorovi by bylo si jen vyfiltrovat, ktery objekt byl attached.

Tzn, ze bych do svych projektu do BaseFormu doplnil jeste nejspise toto.

public $onPresenter = [];
public $onAnchored = [];
public $onPresenterAttached = [];


protected function attached($obj)
{
	// pro puvodni volani onAttached na formulari
	parent::attached($obj);

    // pro specificke volani (jenom kdyz prijde presenter)
	if ($presenter instanceof Presenter) {
		// Napriklad..
		$this->onPresenter($this, $obj);
		// Pripadne..
		$this->onAnchored($this, $obj);
		// Nebo..
		$this->onPresenterAttached($this, $obj);
	}
}

Editoval Felix (24. 6. 2016 8:38)

Jan Tvrdík
Nette guru | 2595
+
0
-

onPresenter je konzistentní třeba s onRequest a onResponse. Já bych se tomu zas tak nebránil.

David Grudl
Nette Core | 8227
+
+1
-

Je to tam https://github.com/…40f05a691b28.

Použil jsem nakonec $onAnchor, protože to přesněji vystihuje skutečnost, kterou chceme sledovat, tj. okamžik, kdy komponenta „zakotví“, načtou se její parametry atd.

duke
Člen | 650
+
0
-

Neměl by ten test ověřovat, že se onAnchor vůbec volá?

David Grudl
Nette Core | 8227
+
0
-

To ověřuje automaticky Tester, ale beru, že to není úplně srozumitelné.