[ Webhosting ProFiTux.cz ] [ Sex chat ] [ Oblečení s garancí ceny ] [ Erotické linky ] [ SPORTOVNÍ VÝŽIVA ] [ Ústav práva a právní vědy ] [ Nestresuj se! ] [ ILike.Cz Online hry ] [ Pánské, dámské a dětské oblečení ]
[ Bomberman ] [ Oblíkačky ] [ Chat s amatérkama ] [ Pánské, dámské a dětské oblečení ] [ Jewel Quest ] [ AZobchod.cz ] [ 1000her ] [ Půjčka online! ] [ Logické hry ]

Proč ne reverzní routování

05.09.2008 ve 02:00
Programování
7 komentářů

Všichni, kdo se trochu více zajímají o frameworky, jistě mají nějaké ty zkušenosti s routingem. Ano, díky němu máme ty krásné adresy, to krásné oddělení na controllery apod. Dnes bude řeč ale o něčem specifičtějším, o reverzním routingu, neboli o zpětném sestavení URL adres. Můj názor je zřejmě ovlivněn nepochopením, nezkušeností, snad i mou neschopností, přesto myslím, že není ojedinělý. Snad. ;)

Reverzní routing, dále jako tvorba url, implementuje určitě více frameworků. Co vím, tak něco má CakePHP a třeba takové Nette je na něm celé postaveno. Já jsem s ním samozřejmě také kdysi experimentoval a dnes mě můžete přesvědčit, abych se k tomu zase vrátil. Ale teď mám slovo já.

Na úvod je ale důležité zmínit tento fakt. Frameworky používáme proto, aby nám pomohly, ne proto, abychom s nimi jedno url napsali na 5 řádků. Tedy, zápis musí být jasný, jednoduchý a přitom dostatečně univerzální.
Kupříkladu si vezměme routing mého blogu:

  • první segment url je metoda controlleru (clanek, clanky) – to jsou action
  • nebo zde máme url pro administraci (/admin) – to je zase namespace (jinde by to nazvaly spíše modulem)

V Háefku routing vypadá velmi zjednodušeně takhle:

Router::connect('/:action{clanek|clanky}/*', array('controller' => 'posts'));
Router::connect('/:namespace{admin}/:controller/:action/*');

Nyní si vypišme možnosti – typy – odkazů:

  • z rootu na článek
  • z rootu na seznam článků
  • z článku na seznam článků

První problém na sebe nenechá dlouho čekat. Jsme na rootu, a chceme jíti do článku. Podle jakého pravidla má framework url vytvořit??? Možné řešení: Defaultně podle aktuálního, jinak si routy pojmenujeme. Stejný problém se opakuje při všech jiných přechodech na jinou routu. Dobře, nutně si tedy musíme routy pojmenovat, a protože jsme na rootu, a žádná routa není aktivní, musíme už zde nutně propašovat název routy do metody, jenž url vytváří.

Další typ odkazů je přecházení na jiné view v rámci stejné routy. Uvažujme, že se všechny parametry-proměnné v url automaticky dědí. V našem příkladu je ovšem dědit nechceme. Musíme je tedy vynulovat, nebo přidat volitelný parametr na dědění. A taky chceme nějakou tu proměnnou přidat. Zde vyplývá další nutnost – mít pojmenované všechny proměnné v routingu.

Tedy, kdybych chtěl jít z toho článku na seznam článků kategorie, ve které je zařazen, musel bych napsat třeba něco takového:

<a href="<?= $this->url('jmeno-prvni-routy', 'posts', 'clanky',
array('kategorie' => $post->category->url), false) ?>">
Seznam článů kategorie</a>

Snad je jasné, co který argument představuje. Poslední je onen povinný/nepovinný argument řešící otázku dědičnosti. Ano, tohoto argumentu bychom se mohli zbavit. Ale ne jednoduše, museli bychom pak vypsat „totální routing“ úplně pro každou „blbost“ a posléze kontrolovat klíče/počty argumentů atp.

Závěrem

Nemíním si routy nijak pojmenovávat, nijak je identifikovat. Proč? No protože bych si ony názvy musel pamatovat, a kdykoliv při psaní odkazů si vzpomínat. Mimo to, zápis url by se prodloužil, a byl by z toho ještě větší maglajs. Dále místo jednoduchého napsání url musím přemýšlet, kde píšu jaký parametr… jestli chcu něco dědit, jak se jmenuje ta proměnná, jestli to náhodou nedědím něco bokem a nějak tak podobně.

Je také ale jasné, že s klasickou ruční tvorbou odkaz se vystačit nedá. Proto na závěr ukázka, jak řešíme podobný problém v Háefku:

<a href="<?= $controller->url('clanky/' . $post->category->title) ?>">
Odkaz na kategorie</a>

Hm, to nic moc, že? :) No jistě. Tady právě není co příliš řešit. Dědit ale Háefko umí.

<a href="<?= $controller->url('clanek/{:post-name}/edit') ?>">
Editovat článek</a>
// respektive
<?= $this->link('clanek/{:post-name}/edit', 'Editovat článek') ?>

Jako výhoda reverzního routingu se stále hází větami typu: „Stačí změnit jen routing, url se pak generují automaticky nová“.
Tak mi prosím ukažte nějaký větší projekt, kde si jen tak změnili url. He, ehm, ne, url se prostě tak často nemění. Jo, ano, možná jednou, dvakrát. Ale aby došla tato feature naplnění, pak by to mělo být spíše každý den. Cena je totiž vysoká. Nejvíc ji žene nahoru komplikovanost zápisu. Vždy totiž musíme nějak něco více či méně specifikovat.

Přijde mi jednoduší psát rovnou url, s určitými pomocnými vychytávkami, než url nějak „skládat“. Neodpustím si na závěr malé porovnání. Je to jako zápis SQL, někteří ho prostě raději napíšou ručně, jiní ho musí prostě skládat přes všemožné objekty, recordy, fluent interfacy atp. Děkuji, můžete se posadit.


Komentáře

[1] – 05.09.2008 - 04:19

David Grudl

Faktem je, že vymyslet reverzní routování tak, aby fungovalo bez všech obezliček, co jsi zmínil (jako je pojmenování rout) a aby byl zápis odkazů dostatečně stručný, mi trvalo pár let. Podařilo se a dnes jsem s ním zcela spokojen.

Takže v Nette se odkaz zapisuje takto:

$this->link('delete', $id, TRUE)

což odpovídá zavolání metody delete na aktuálním presenteru/con­troleru. Tj. vznikne odkaz, na který když se klikne, tak to je jako zavolat ` $this->delete($id, TRUE)`;

Nebo

$this->link('Catalog:show', $id, 'en')

Což odpovídá volání metody show třídy Catalog s uvedenými parametry, takže něco jako Catalog::show($id, 'en') (záměrně trošku zjednodušuju, ale podstatné platí).

Šlo mi o to, aby odkaz vypadal v podstatě jako normální volání funkce v PHP, či možná spíše jako použití call_user_func(). Jen s tím, že se zavolá, až když uživatel klikne. URL z toho úplně vypadly. Věc se tedy nemá tak, že bych si odstraněním URL zkomplikoval tvorbu odkazů – ale právě naopak.

(Nechci působit namachrovaně, ale) myslím že tohle žádný jiný framework na světě nemá :-)

[2] – 05.09.2008 - 10:28

Hrach

Jaký machrování :) Je to ojedinělý a velmi propracovaný.

Pokud se nepletu, ty odkazuješ přímo na metody-action a controller. To je pěkné a přímočaré, na druhou stranu nevím, jak dalece je to odstíněno od různých niancí, které v url chceme aby bylo opravdu cool.

Otázka: jak Nette ví, že Posts::show(…) je pod /clanek/proc-ne-reverzni-routovani.

[3] – 05.09.2008 - 13:56

David Grudl

Z definic ví, že pod clanek/proc-ne-reverzni-routovani je Posts::show(...), přesněji pod clanek/{id} je Posts::show($id), takže lze i zpětně říct, že když budu odkazovat na tento controller/action s jedním parametrem, bude tomu vyhovovat maska clanek/{id}.

Jestli to bude fungovat včetně různých niancí, to byla otázka – ale zdá se, že jo. Zajímavé ovšem je, že hodně lidí se to zdráhá přijmout, jako by měli nějaký vnitřní blok, něco jako neochotu zasednout do auta řízeného strojem. Třeba tu http://forum.nettephp.com/…iewtopic.php?…. Je to zajímavé…

[4] – 05.09.2008 - 22:28

bukaj

První problém na sebe nenechá dlouho čekat. Jsme na rootu, a chceme jíti do článku. Podle jakého pravidla má framework url vytvořit??? Možné řešení: Defaultně podle aktuálního, jinak si routy pojmenujeme. Stejný problém se opakuje při všech jiných přechodech na jinou routu.

Budu krutý, ale takovéhle obtíže jsou způsobeny podle mě přinejmenším podivnou implementací routingu v Háefku :o) (Ale je to taky možnost, neříkám, že je úplně spatná, pouze se mi zdá „nedobrá“ přávě pro tenhle případ.)

Pro reverzní routing potřebuješ, aby jsi s routami mohl pracovat i po tom, co se „doroutuje“ (jakmile routa odpovídá adrese). Proto je podle mě potřeba si všechny routy někam uložit/odložit pro pozdější dobu (až bude potřeba získávat adresy) a ne je jen tak zahodit („udělaly jste holky svoje, teď váš už nepotřebuju“).

[5] – 05.09.2008 - 22:53

Hrach

Ale kdepak, reaguješ velmi mylně. Já neřeším to, že nemám podle čeho sestavit url, ale to, co mám za routu vybrat. To, že je teď už neukládám, je naopak velmi dobře, protože by to bylo naprosto zbytečné, a šetřím tam systémové zdroje. Víš? :)

[6] – 09.09.2008 - 04:28

sh

Davide nechci ti rejpat do namachrovanosti, ale třeba link_to(‚článek‘, ‚article/show?id=­‘.$article->getId()) už drahnou dobu používám v symfony… pravda má to jiný zápis, ale analogicky stejně to volá articleAction­s::executeShow($re­quest), s tim že všechny parametry jsou pak v requestu.

[7] – 16.09.2008 - 00:37

David Grudl

[6] jo, to vypadá velmi podobně. Jsem rád, že se to používá i jinde. Připadá mi to totiž jako nejšikovnější řešení.


Přidat komentář


Zde formátuje Texy!