Ako fungujú signály?
- fiso
- Člen | 32
Viem že Nette podporuje signály, ale nenašiel som zatiaľ nejaký podrobnejší popis toho ako fungujú. Ak tomu správne rozumiem, tak sú to v podstate udalosti prenášené medzi klientom a serverom, áno? Alebo som možno úplne mimo :-) Celkom ma to totiž zaujalo, dalo by sa pomocou nich robiť také triky ako javascript autocompletion (na základe js udalosti onkeydown) apod? Prípadne na čo sú určené? Vďaka.
- Panda
- Člen | 569
Co jsem já pochopil, tak to jsou skutečně události mezi klientem a
serverem předávané v URL (parametr ?do
), ať už jde o
‚normální‘ požadavek, nebo přes AJAX.
Presenter během svého životního cyklu, konkrétně ve 3. fázi –
SIGNAL HANDLING
(předchozí 2 jsou STARTUP
(inicializace globálních parametrů (mimo jiné i zpracování parametrů,
které se týkají signálů), volání startup
a
action{Action}
), volá metodu processSignal
, která si
bere na starosti vyřízení signálu – vezme komponentu, která se určila v
initParams
jako příjemce signálu (pokud není určen příjemce
signálu, je to presenter samotný) a pošle jí signál. V podstatě to
vypadá tak, že pokud daný objekt implementuje rozhraní
ISignalReceiver
, tak se zavolá metoda signalReceived
se jménem signálu v parametru. Další zpracování je na daném objektu.
Objekty, které dědí od PresenterControl
(zajímavé jsou hlavně
objekty dědící od Control
a Presenter
) reagují
tak, že se snaží zavolat metodu handle{signal}
s příslušnými parametry (= vezmou se všechny parametry, které přišly
s požadavkem, vezme se definice funkce handle{signal}
,
k argumentům se podle jména dosadí parametry z URL a pokusí se danou
metodu zavolat – např. jako prametr $id
se předá hodnota
z parametru id
v URL, jako $something
se předá
something
z URL…). Pokud metoda neexistuje, metoda
signalReceived
vyvolá výjimku. Signál tedy může přijímat
jakákoliv komponenta, presenter nebo objekt, který implementuje
ISignalReceiver
. David to prostě navrhl téměř dokonale.
Jak bylo řečeno, signál může přijímat cokoliv, co implementuje
ISignalReceiver
. Mezi hlavní příjemce signálů budou patřit
Presentery a vizuální komponenty dědící od Control
(a ty se
při přijetí signálu automaticky invalidují, což je důležité pro AJAX).
Signál má sloužit jako signál pro objekt, že má něco udělat – anketa
si má započítat hlas od uživatele, blok s novinkami se má rozbalit a
zobrazit dvakrát tolik novinek, formulář byl odeslán a má zpracovat data,
čtvereček ve hře ‚fifteen‘ se má posunout na prázdné místo…
V ‚obyčejné neAjaxové‘ aplikaci budou putovat nejčastěji přes odkazy nebo jinou akci, která vyvolá přechod na nové URL (odeslání formuláře). Jak již bylo zmíněno, signál je ve své podstatě normální požadavek, který má jen parametr navíc, takže se celá stránka načítá znovu a na straně serveru se znovu projde celý životní cyklus aplikace a presenteru, jen si to ve vhodný okamžik odskočí zpracovat signál.
U ‚Ajaxové‘ aplikace je situace kousek jiná, vyslání signálu lze navázat na jakoukoliv JavaScriptovou aplikaci, takže můžeme mít zprávu o každém pohybu myší uživatele (pokud by ovšem síťové spojení a zpracování scriptů na straně serveru bylo dostatečně rychlé). Také je zde důležitý fakt, že komponenta přijímající signál se automaticky invaliduje, takže se posílá klientovi znovu její kód, nezávisle na tom, ať už v něm signál vyvolal nějakou změnu, nebo ne. Někdy se to hodí, jindy však bude toto chování nežádoucí.
URL pro signál vytváříme pomocí metody
PresenterComponent::link
. Jako parametr $destination
předáme řetězec {signal}!
a jako $args
pole
argumentů, které chceme signálu předat. Signál se vždy volá na aktuální
view s aktuálními parametry, parametry signálu se jen přidají. Navíc se
přidává hned na začátku zmiňovaný parametr ?do
, který
určuje signál.
Jeho formát je buď {signal}
, nebo
{signalReceiver}-{signal}
. {signalReceiver}
je název
komponenty v presenteru. Proto nemůže být v názvu komponenty pomlčka –
používá se k oddělení názvu komponenty a signálu.
Dobře je použití signálů vidět v příkladu ‚fifteen‘ u Nette.
Snad jsem postihl vše, co jsem postihnout chtěl a snad je to alespoň trochu srozumitelné. A snad jsem problematiku pochopil dobře.
Na závěr postu odpověď na položenou otázku:
Autocompletion by s pomocí signálů šlo udělat naprosto v pohodě, stačí
na to udělat vhodnou komponentu/snippet, která/který se bude správně
invalidovat (v případě komponenty je invalidace automatická) se správným
obsahem a volání Ajaxového požadavku navázat na správnou událost.
A slouží třeba právě k vytvoření autocompletion.
- fiso
- Člen | 32
Panda: Vrelá vďaka za popis!
Je možné spraviť signál mimo aktuálnu view? tzn niečo
ako {presenter}:{view}:{signal}!
Rozmýšľam ešte nad tým, kde je použitie signálov správne a kde už
nie. IMHO by sa malo jednať výsostne o veci ktoré nemajú nejaký side
effect na serveri. Ak som správne rozumel, tak signály sa prenášajú
iba cez GET požiadavky, ktoré by nemali mať nikdy
potenciálne nebezpečné vedľajšie efekty (pozri 9.1.1 Safe Methods, HTTP 1.1, RFC 2616) Tzn. signály by sa
nemali používať na nič iné ako na zobrazovanie. Mazanie (niečo ako
http://example.com/?do=delete&item=1
) by sa
nikdy nemalo robiť cez GET, to isté by malo platiť aj pre
rôzne ankety a podobne, lebo sa cez to dá spraviť taký CSRF že sa človek
z toho môže po… A ťahať autorizačné tokeny do GET nie je nič moc,
takže takéto veci treba riešiť cez POST.
Dobře je použití signálů vidět v příkladu ‚fifteen‘ u Nette.
Toto by som robil celé v javascripte. Snáď lepší príklad by bolo to autocompletion.
Osobne si neviem moc dobre predstaviť použitie signálov inde ako na udalosti vyvolané v javascripte. Ak máte nejaký príklad, kľudne sem s ním.
- Panda
- Člen | 569
fiso napsal(a):
Panda: Vrelá vďaka za popis!
Je možné spraviť signál mimo aktuálnu view? tzn niečo ako
{presenter}:{view}:{signal}!
Není, alespoň v současném Nette to nejde. David to někde psal, nevím, jestli plánuje dodělat podporu pro signály jinam, ale spíš ne.
Rozmýšľam ešte nad tým, kde je použitie signálov správne a kde už nie. IMHO by sa malo jednať výsostne o veci ktoré nemajú nejaký side effect na serveri. Ak som správne rozumel, tak signály sa prenášajú iba cez GET požiadavky, ktoré by nemali mať nikdy potenciálne nebezpečné vedľajšie efekty (pozri 9.1.1 Safe Methods, HTTP 1.1, RFC 2616) Tzn. signály by sa nemali používať na nič iné ako na zobrazovanie. Mazanie (niečo ako
http://example.com/?do=delete&item=1
) by sa nikdy nemalo robiť cez GET, to isté by malo platiť aj pre rôzne ankety a podobne, lebo sa cez to dá spraviť taký CSRF že sa človek z toho môže po… A ťahať autorizačné tokeny do GET nie je nič moc, takže takéto veci treba riešiť cez POST.
Není pravda, že se posílají jen přes GET požadavky. Ano, základní
upozornění na signál je v URL požadavku, ale to neznamená, že není
možné použít POST a data samotná poslat právě v něm. Třeba formulář
si také posílá signál, že byl odeslán, ale data samotná putují v POST.
Nebo AJAX v Nette s knihovnou nette.js
: každý požadavek je
POST, i když jeho tělo je třeba prázdné a data samotná jsou v URL.
Jinak souhlasím, akce s vedlejšími účinky by se měly vykonávat přes
POST, ale někdy nemusí být 50 formulářů na stránce nebo odkaz na další
stránku, kde bude formulář umožňující akci s položkou/vybranými
položkami, žádoucí a je lepší to nahradit klasickým odkazem. Pokud se to
udělá správně, tak CSRF nehrozí. Nic Ti nebrání udělat
token
jako persistentní parametr presenteru, jeho ověření
nandat do metody processSignal
a vytvoření nového tokenu a
invalidaci starého do saveState
. Pak už se Ti autorizační
tokeny generují, přidávají do URL, ověřují a invalidují naprosto samy a
Ty se o nic nemusíš starat. Tím si také současně zabezpečíš
formuláře, protože jejich odeslání probíhá právě přes signál. Řešil
jsem třeba takto změny pořadí objektů na stránce – měl jsem tabulku
s objekty, které měly být na stránce, a u každého 2 odkazy s šipkami:
nahoru a dolů. Když měl uživatel JavaScript, šlo to přes AJAX, jinak přes
normální refresh stránky. Zdálo se mi to lepší, než kopa formulářů
nebo přesměrovat uživatele na jinou stránku, kde ten formulář bude.
Toto by som robil celé v javascripte. Snáď lepší príklad by bolo to autocompletion.
Ten příklad původně Ajaxový tuším nebyl, to pak přišlo jako demonstrace toho, jak snadno lze z neAjaxové aplikace udělat krásnou dynamickou aplikačku.
Osobne si neviem moc dobre predstaviť použitie signálov inde ako na udalosti vyvolané v javascripte. Ak máte nejaký príklad, kľudne sem s ním.
Třeba tabulka s hlavičkou, kde klikáním na hlavičku budeš moct měnit způsob řazení. Nebo nějaký seznam produktů, kde kliknutím na název produktu rozbalíš další detaily konkrétního produktu… A nebo již zmiňovaný formulář, který si v signálu posílá upozornění, že se odesílá.
- vlki
- Člen | 218
Jak je to se signalem, ktery posle formular v komponente?
Vytvari to signal jako [komponenta]-[idformulare]-[signal]
a pri
zpracovani signalu to hleda komponentu [komponenta]-[idformulare]
,
ktera samozrejme neexistuje…
Je to bug, ktery je opraven dale nebo jen spatne pouziti formularu?
Poznamenavam, ze pouzivam revizi 61, kterou posledni jsem rozjel na php 5.2.0.
- David Grudl
- Nette Core | 8218
Nemám sílu zkoumat, jak to fungovalo ve starších revizích, zkus to prosím sám v aktuální.