[Best practise] Action nebo handle?

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Tomáš Votruba
Moderator | 1114
+
0
-

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

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

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

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

hrach
Člen | 1838
+
0
-

koukam, ze dokumentace je v tomto zavadejici :D

Jan Tvrdík
Nette guru | 2595
+
0
-

Ono se přesměrovává, ale na aktuální view ($this->redirect('this')), tzn. view se nemění.

nanuqcz
Člen | 822
+
0
-

Tj, v nové dokumentaci je to nějaké zvláštní. Myslím, že tam autor jen trochu nesrozumitelně vysvětluje rozdíl mezi action<Action> a render<Action>.

Buď ve staré dokumentaci, anebo v ještě starším seriálu na zdrojáku, to ale bylo cca tak, jak jsem napsal výše.

nanuqcz
Člen | 822
+
0
-

Tak jsem trochu pohledal, tady je to podle mě skvěle vysvětlené ;-)

Patrik Votoček
Člen | 2221
+
0
-

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 kdy handle?

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

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

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

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

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

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…

Aurielle
Člen | 1281
+
0
-

V action by se mělo případně redirectovat nebo nastavovat jiný view. Nikdy by se v něm neměla plnit šablona. Vše ostatní patří do render, nebo jsem o tom aspoň já přesvědčen :D

nanuqcz
Člen | 822
+
0
-

gmvasek: Nj, otázka je ale, proč zrovna takhle? :-) Tohle je podle mě na zvláštní téma, nebo článek v kuchařce.

Patrik Votoček
Člen | 2221
+
0
-

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

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.

Nox
Člen | 378
+
0
-

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?

nanuqcz
Člen | 822
+
0
-

bene napsal(a):

v metodě render by nemělo docházet k redirectu.

Redirect je, co se týče MVC, starost View. Takže bych ho logicky viděl právě v metodě render, která by měla obstarávat právě tu „View“ část. Nebo se pletu?

Nox
Člen | 378
+
0
-

Je to opravdu tak? Nevim jestli se to někde píše, ale moc mi to nezní – změna stavu aplikace (nebo jak ten redirect nazvat) přece nemá s výstupem, prezentací, nic moc společného … přijde mi to spíš jako záležitost logiky aplikace, ke které má action blíž

nanuqcz
Člen | 822
+
0
-

Nevím to jistě, tohle jsem si vydedukoval sám :-) Ale s výstupem to IMHO má dost společného, protože ten redirect se provádí odesláním stránky spolu s hlavičkou pro přesměrování.

bene
Člen | 82
+
0
-

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

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

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

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:

  1. dáváte pouze {link toggleněco!} a aplikace si sama zjistí předchozí stav a nastaví opačnou hodnotu
  2. dáváte {link toggleněco!, !$state} a tedy v linku již posíláte stav, do kterého se má přepnout
  3. abych byl kompletní ,tak je tu i 3. možnost {link toggleněco!, $state}
nanuqcz
Člen | 822
+
0
-

@bojovyletoun: první možnost, ale nikdy mě nenapadlo nad tím přemýšlet :-)

duke
Člen | 650
+
0
-

bojovyletoun napsal:

PS: vždycky mě zajímal názor, kterou ze dvou možností řešíte toggle něčeho:

Druhou možnost, akorát se to pak nejmenuje toggle, ale např. set. Důvod je ten, že chci přepínat podle zobrazené hodnoty a nikoli podle aktuální (která se může průběžně měnit).

tany
Člen | 31
+
0
-

toogle je nebezpečný, dva lidi ti po sobě deaktivujou něco .. a je to zpátky aktivní. U set je jedno kolik lidí deaktivuje položku …

Jan Suchánek
Člen | 404
+
0
-

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)