[Best practise] Action nebo handle?
- Tomáš Votruba
- Moderator | 1114
1. Nejdříve jsem chtěl položit dotaz, proč mi základní routa ze
sandboxu nepřevádí action
pro homepage. Z toho důvodu mám
pocit, že by na homepage neměly probíhat žádné akce, když mi to tedy
defaultní routa nedovodluje. Viz:
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
// n:href="Homepage:logout" převeda na "homepage/logout/"
// což vede na neexistující homepage/logout.latte (končí chybou)
// nechápu proč preskočí action
// fix
$router[] = new Route('[<presenter>/]<action>[/<id>]', 'Homepage:default'); // nezpůsobí to něco?
// n:href="Homepage:logout" převeda na "logout/", hurá
// opět ale přeskočí action
Zkoušel jsem různé čachry, ale raději nebudu odvádět pozornost jinam. Napadl mne signál, ale jak by vypadala pěkná routa?
2. Pak mne napadlo, kdy mám použít action
a kdy
handle
? Měl jsem za to, že dokumentace
uvádí, že handle
je určeno zejména na komponenty a ajax –
tak jej do teď používám, action
pak na zbytek. Z tohoto fundovaného
vlákna mám zase dojem, že handle má mnohem širší doporučené
použití. Stejně tak z problému 1.
Děkuji za reakce na oba problémy. Jsem z toho opravdu jenel.
- nanuqcz
- Člen | 822
Jak jsem to pochopil já, handle
se používá tam, kde se
nějak mění data nebo stav aplikace, a odkud se pak přesměrovává
jinam – aby se tato „změna“, která se v handle
vykonává,
nedala provést opakovaně (například přidání nového příspěvku
v diskuzi).
Podle této logiky by se na logout měl podle mě použít
handle
a poté přesměrovat na nějakou stránku (třeba na
homepage).
Jinak, u signálu „pěknost“ routy neřeším, protože po něm vždy následuje přesměrování (na stránku, kde už pěkná URL je).
- Filip Procházka
- Moderator | 4668
Signál ti mění stav současné akce. Řazení, stránkování, … já se s ním třeba i odhlašuju.
- Nox
- Člen | 378
xxxObiWan napsal(a):
handle se používá tam, kde se nějak mění data nebo stav aplikace, a odkud se pak přesměrovává jinam
Není to naopak – když se NEpřesměrovává?
Dokumentace:
Action<Action>()
Obdoba metody render<View>(). Jsou situace, kdy presenter provede určitý úkon (přihlásí uživatele, zapíše data do databáze) a poté přesměruje jinam.
Dokumentace:
handle<Signal>()
Metoda zpracovává tzv. signály
⇒ Signál (aneb subrequest) je komunikace se serverem pod prahem normálního view, tedy akce, které se dějí, aniž by se změnilo view
- Jan Tvrdík
- Nette guru | 2595
Ono se přesměrovává, ale na aktuální view
($this->redirect('this')
), tzn. view
se
nemění.
- Patrik Votoček
- Člen | 2221
Schmutzka napsal(a):
což vede na neexistující homepage/logout.latte (končí chybou) … nechápu proč preskočí action
Nic nepřeskakuje! Action se normálně vykoná. A chyba ohledně neexistující šablony je OK a správné chování.
2. Pak mne napadlo, kdy mám použít
action
a kdyhandle
?
signál je „změna stavu aktuálního view“. Je to například odeslání
formuláře nebo ono handleFoo
. A správně chování hadle by
mělo být Post/Redirect/Get tj.
správně by se požadavek směrující na handleFoo
měl
provádět POST metodou.
- Tomáš Votruba
- Moderator | 1114
Děkuji všem za vyjádření. Zpět k mé otázce: 1. routa pro „homepage/action“ ⇒ v url pouze „action“
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
// n:href="Homepage:logout" převeda na "homepage/logout/" -> nepěkné, homepage zbytečný, chci jen "logout/"
// n:href="AnotherPresenter:logout" převeda na "another-presenterlogout/" -> pěkné a má smysl
@Patrik: Když dám:
public function actionLogout()
{
dump("test");
die;
}
nic se nevypíše a nezastaví. Tzn. že se action provedlo? Nebo jak tomu mám rozumět?
2. Action vs view
Koukám, že co člověk, to trochu jiný názor (nevím, komu mám věřit dříve :). Mohl bych poprosit o doplnění do/opravení dokumentace (nejen kvůli mně), kde bych si přečetl a bylo to jasné? Ideálně s explicitvními příklady, kde je vhodné použít. Díky.
Shrnu, co jsem pochopil, tedy v čem mám rozpor:
handle – Změna stavu daného view (je něco, co není změna?),
Post/Redirect/Get × stránkování je Post?
action – Změna stavu jiného view, např. jsem na hlavní stránce
a tam mám odkaz na „record/edit/23“. Píše tu vůbec někdo o action?
Mám dojem, že reagujete na dotaz „Co je handle?“, ale já se ptám „Kdy
použít handle a kdy action a proč?“
Jestli to někdo stihnete srozumitelně a vysvětlujícně doplnit do dokumentace, stačí link/echo.
- Felix
- Nette Core | 1196
Pokud chces mit na Homapage akce:
1. routa
example.com/
2. routa
example.com/about/
example.com/company/
3. routa
example.com/gallery/album/10
$router[] = new Route('index.php', 'Homepage:default', Route::ONE_WAY);
$router[] = new Route('<action>/<id [0-9]+>', array(
'presenter' => 'Homepage',
'id' => NULL,
));
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
Editoval Felix (12. 1. 2012 13:02)
- nanuqcz
- Člen | 822
Schmutzka napsal(a):
2. Action vs view
… Ideálně s explicitvními příklady, kde je vhodné použít. Díky.
Do dokumentace si psát netroufám, ale napíšu aspoň sem konkrétní příklady:
Signály (handle<Name>)
- Odhlášení: Mění se stav dat nebo aplikace? Ano. Potřebuju uživateli zobrazit nějakou stránku, abych ho odhlásil? Ne (stačí např smazat jeho session ze serveru). ⇒ HANDLE (např. handleLogout)
- Smazání příspěvku v diskuzi: Mění se stav dat nebo aplikace? Ano. Potřebuju uživateli zobrazit nějakou stránku, abych mohl z databáze odstranit příspěvek? Ne. ⇒ HANDLE (např. PostsPresenter::handleDelete)
- Přidání nového příspěvku: Mění se stav dat nebo aplikace? Ano. Potřebuju uživateli zobrazit nějakou stránku, abych mohl do databáze přidat příspěvek? Ne. ⇒ HANDLE (např. handlePostsFormSubmitted – plno lidí ale signály pro zpracování formulářů pojmenovává jinak)
Po provedení signálu je vhodné uživatele přesměrovat na akci, kterou
chceme, aby se mu zobrazila (třeba i s nějakou zprávou, že změna v
handle
byla provedena úspěšně)
Akce (action<Name>/render<Name>)
- Zobrazení formuláře pro nový příspěvek do diskuze: Mění se stav dat nebo aplikace? Ne. Potřebuju uživateli zobrazit nějakou stránku, abych uživateli ukázal formulář? Ano. ⇒ AKCE (např. actionCreate)
- Zobrazení výpisu článků: Mění se stav dat nebo aplikace? Ne.
Potřebuju uživateli zobrazit nějakou stránku, aby si přečetl výpis
článků? Ano. ⇒ AKCE (např. ArticlesPresenter::actionDefault –
někteří pojmenovávají jako
actionList
)
Možná tě bude později zajímat rozdíl mezi
action<Name>
a render<Name>
. O ten
doporučuju se v začátcích nestarat, je to zjednodušeně to samé
(action<Name>
se jen volá dřív).
Editoval xxxObiWan (12. 1. 2012 13:29)
- Nox
- Člen | 378
Hezký rozbor!
Možná tě bude později zajímat rozdíl mezi action<Name> a render<Name>. O ten doporučuju se v začátcích nestarat, je to zjednodušeně to samé (action<Name> se jen volá dřív).
A pokud by se i přesto někdo chtěl vzdělat, mohl bys nastínit rozdíl?
Díky
(osobně v action mám vše co nepracuje s template a v render co pracuje
s template, ale … rozhodně si rád přečtu jiný popis, třeba to dělám
špatněj)
- nanuqcz
- Člen | 822
Bohužel co se týče action<Name>
a
render<Name>
, pořád jsem si v tom ještě neutřídil
myšlenky a ani si nejsem jistý, jestli to chápu úplně dobře :-)
V základě vím to samé, co ty, že v action by měla být logika a
v render plnění šablony. Ale já všechno strkám do
render<Name>
a ještě nikdy to ničemu nevadilo…
- Patrik Votoček
- Člen | 2221
Schmutzka napsal(a):
@Patrik: Když dám:
public function actionLogout() { dump("test"); die; }
nic se nevypíše a nezastaví. Tzn. že se action provedlo? Nebo jak tomu mám rozumět?
To je divné a smrdí to problémem někde jinde…
Nicméně doporučuju v presenteru používat spíš
$this->terminate();
než die
nebo
exit
. :-)
xxxObiWan napsal(a):
…
krásně jsi to sepsal
Po provedení signálu je vhodné uživatele přesměrovat na akci, kterou chceme, aby se mu zobrazila (třeba i s nějakou zprávou, že změna v
handle
byla provedena úspěšně)
To je přesně to co zmiňuju Post/Redirect/Get :-)
Action vs. Render
Action je ta část kde by jsi měl načítat data ověřovat jejich existenci a na základě toho přesměrovávat nebo vyhazovat vyjímky.
Taky se v něm plní data (která není technicky možné – nebo by se neměly – plnit v továrničkách) do komponent (formulářů). Viz.: https://pla.nette.org/…cni-formular
Zatím co render by měla být „hloupá“ metoda která se stará pouze o přesdání dat šabloně.
(možná bych to fakt mohl sepsat do cookbooku…)
- bene
- Člen | 82
Rozdíly, možnosti, použití:
Signál (handle<Name>) oproti akci (action<Name>) lze volat jen
v rámci presenteru. Tudíž, pokud na logout použijete signál, musíte jej
definovat v nějakém AdminBasePresenter, pokud chcete dát uživateli možnost
se odhlásit z libovolné stránky.
Pokud tedy chcete provádět nějaké signály přístupné z více
presenterů, nezbývá vám než si zaprasit nejakého předka hromadou
handleXyz.
Signál se vykonává až po action. Tudíž, pokud se nacházíte např. na
renderDefault a v actionDefault máte např. vytažení záznamů z databáze
nebo něco, co stojí systémové prostředky, tak při zavolání handleDelete
se provede actionDefault, což je zbytečná zátěž serveru.
Toto chování může být někdy žádoucí, ale dle mých zkušeností spíše
výjmečně. Nejčastěji se spojením s formulářem.
Osobně signály využívám velmi výjmečně (hlavně kvůli výše
uvedeným chováním).
Použití je dobré pokud potřebujete nějakou akci přístupnou z více
presenterů a po jejím provedení je nutné se přesměrovat zpět
$this->redirect('this')
. Nenapadá mě jak jinak by se toho dalo
dosáhnout a přitom měl k dispocizi flashMessage, atp.
Předpokládám, že signály jsou nutností, pokud využíváte snipety (nepoužívám) a ajax (používám jen pokud opravdu potřebuji).
Co se týče rozdílu mezi action a render, tak v action by z principu nemělo být používání šablony a v metodě render by nemělo docházet k redirectu. Data např. pro výpis vytahuji až v metodě render a rovnou je lifruji do šablony. Do metody action vytažení dat z databáze přesunu až v případě, že tato data potřebuji v definování např. formuláře. Ten samý princip používám i na action/render pro editaci, aj.
- bene
- Člen | 82
Název metody render ve mě vzbuzuje pocit, že se něco vykresluje. A po vykreslení už redirect neuděláš, neboť už byla odeslána nějaká hlavička.
A v beforeRender už můžeš něco posílat na výstup (metody before/afterRender beru jako část vykreslování tedy metody render). Proto by jsi v metode RenderXyz už redirectovat neměl.
Ono asi není úplně šťastný název beforeRender protože to vlastně znamená „před vykreslením“. Kdežto ta metoda by vlastně měla dělat „vykresli před jakýmkoliv konkrétním vykreslením“. Ale to už je jedno, s beforeRender nemám problém :)
Ale to je zase moje dedukce a možná není správná ;-) Pouze ji dodržuji.
- 22
- Člen | 1478
@xxxObiWan: rozdíl mezi action
a
render
poznáš, až začneš používat například AJAX… tam
opravdu nevím, jestli se svým
"render mi stačí"
vystačíš.. Ono se to tady
přestalo nějak zdůrazňovat, že Presenter
má nějaký
životní cyklus..
btw: HosipLan a jeho Nette školka na scénu :-)
Editoval 22 (12. 1. 2012 23:50)
- Patrik Votoček
- Člen | 2221
Nox napsal(a):
Patrik Votoček
V případě že data načtená v action hned nepoužiješ např. v tom formuláři, ale chceš je vložit do šablony, tak si na ta data uděláš properties v Presenteru a data zpřístupníš přes ně metodě render?
Ano to je jedna z možností. Druhou je spoléhání se na ResultCache / IdentityMap v Modelové vrstvě.
- bojovyletoun
- Člen | 667
Také by mohl být rozdíl mezi action a render vidět na protipřípladech:
- Pokud definujete (vytvoříte a připojíte) komponentu v render, pak nebude moci přijmout signál(protože handle je před render, komponenta neexistuje) a ukáže se Badrequest.
- Pokud si data k zobrazení vytáhnete v action a ne v render a zároveň voláte signál, který mění data, tak se vám na výstupu zobrazí data před změnou
PS: vždycky mě zajímal názor, kterou ze dvou možností řešíte toggle něčeho:
- dáváte pouze
{link toggleněco!}
a aplikace si sama zjistí předchozí stav a nastaví opačnou hodnotu - dáváte
{link toggleněco!, !$state}
a tedy v linku již posíláte stav, do kterého se má přepnout - abych byl kompletní ,tak je tu i 3. možnost
{link toggleněco!, $state}
- Jan Suchánek
- Člen | 404
Pokud chci zobrazit formulář na úpravu např. /article/edit/1 v výpisu článků pomocí Ajaxu musím místo action použít handle?
Editoval jenicek (27. 1. 2012 13:24)