Odchycení okamžiku, kdy je komponenta připojená k presenteru
- David Grudl
- Nette Core | 8227
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.
- stekycz
- Člen | 152
Za mě je lepší event
- Dokážu si představit, že budu chtít dělat i jiné věci než které popisuješ
- 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í
- Lze backportovat i pro verze Nette s podporou PHP bez yieldu
- 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
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
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 yield
em.
A hlavně, když bude ten kód někdo číst, tak to nemá šanci pochopit.
- Eda
- Backer | 220
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
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
@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áš.
- mkoubik
- Člen | 728
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
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
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
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
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…
- Felix
- Nette Core | 1245
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.
- 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...
}
}
- 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 bylattached
.
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
onPresenter je konzistentní třeba s onRequest a onResponse. Já bych se tomu zas tak nebránil.
- David Grudl
- Nette Core | 8227
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.
- David Grudl
- Nette Core | 8227
To ověřuje automaticky Tester, ale beru, že to není úplně srozumitelné.