Příklady routeru

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
A.
Člen | 87
+
0
-

Zdravim,

nedalo by se zverejnit par prikladu slozitejsich routeru?

Napr. ten co mas pro texy ci pro tento web. Jen tak prozatim nez bude tutorial, malo prace, hodne zabavy :-). Spouste lidem by to na lepsi pochopeni jiste stacilo.

Petr Daňa
Člen | 109
+
0
-

Taky bych potřeboval :) Konkrétně by mě zajímaly ty validation-expr u parametrů v routeru. Jsou to nebo nejsou klasické regexpy? Snažím se vytvořit router, který odchytí „nazevstranky.html“ a „nazevstranky.htm“ (jedná se o rozlišení těch přípon oproti jiným url), předá tento název (včetně přípony) jednomu presenteru a url bez .htm či .html předal jinému presenteru, tj. něco jako:

$router[] = new Route('<page [html?$]>', array('presenter' => 'Page', 'action' => 'default'));
$router[] = new Route('<presenter>/<action>', array('presenter' => 'Default', 'action' => 'default'));

Editoval Petr Daňa (22. 4. 2008 10:45)

David Grudl
Nette Core | 8218
+
0
-

Validační výrazy jsou klasické regulární výrazy. Vlastně se dá říct, že pokud žádný validátor neuvedete, tak se použije [^/]+.

David Grudl
Nette Core | 8218
+
0
-

Petr Daňa napsal(a):

Snažím se vytvořit router, který odchytí „nazevstranky.html“ a „nazevstranky.htm“ (jedná se o rozlišení těch přípon oproti jiným url), předá tento název (včetně přípony) jednomu presenteru a url bez .htm či .html předal jinému presenteru, tj. něco jako:

Teoreticky to můžeš spojit do jedné routy:

$router[] = new Route(
    '<page><ext (\.html|\.htm)>',
    array(
        'presenter' => 'Page',
        'action' => 'default',
        'ext' => NULL, // nyní je paramete <ext> nepovinný
    )
);
Petr Daňa
Člen | 109
+
0
-

Díky za ukázku. Nakonec jsem vytvořil pro můj požadavek ty routery takhle a funguje to dobře.

$router[] = new Route('<page [^/]*(\.html|\.htm)>', array('presenter' => 'Page', 'action' => 'default'));
$router[] = new Route('<presenter>/<action>', array('presenter' => 'Default', 'action' => 'default'));

Akorát jsem se divil, proč když dám $ na konec (tj. <page [^/]*(\.html|\.htm)$> tak to nefunguje, pak jsem to prohnal debuggerem a koukal jsem, že tam na konec přidáváš lomítko, tak se to asi tlouklo.

A.
Člen | 87
+
0
-

Co ty ukazky slozitejsich Routeru prosim? :).
Potrebuji si nejak urovnat pojmy presenter, view a control. Jeste presne nevim, jake je jejich zamyslene, idealni pouziti.

David Grudl
Nette Core | 8218
+
0
-

Petr Daňa napsal(a):

Akorát jsem se divil, proč když dám $ na konec (tj. <page [^/]*(\.html|\.htm)$> tak to nefunguje, pak jsem to prohnal debuggerem a koukal jsem, že tam na konec přidáváš lomítko, tak se to asi tlouklo.

Je to tak, znak $ není potřeba (ani možné) přidávat.

veena
Člen | 98
+
0
-

Když se podíváme na ukázku nastavení routeru z Quickstartu:

$router = $application->getRouter();

$router[] = new Route('index.php', array(
    'presenter' => 'Default',
    'action' => 'default',
), Route::ONE_WAY);

$router[] = new Route('<presenter>/<action>/<id>', array(
    'presenter' => 'Default',
    'action' => 'default',
    'id' => NULL,
));

Kdyby šlo při získání routeru mu hned předat routy, pak by mohlo vypadat nastavení takto úsporněji:

$router = $application->getRouter(
	array('index.php', array('presenter' => 'Default', 'action' => 'default'), Route::ONE_WAY);
	array('<presenter>/<action>/<id>', array('presenter' => 'Default', 'action' => 'default', 'id' => NULL)
 ... další seznam rout ...
);

Přemýšlím, jak to skloubit s moduly a připravovanými namespaces. Fajn by bylo mít moduly v oddělených adresářích, tam příslušné presentery.

Taky by šlo přidat pojmenované routy. Možná bych pro explicitní srozumitelnost přidal do rout i ^ a /$. Pak by nastavení routy i s ukázkou nepovinných parametrů (jméno routy, one way route flag) mohlo vypadat třeba takto:

array('^archiv/(\d{4})/(\d{2})/(\d{2})/([\w-]+)/$', 'blog:archive:article', 'name' => 'clanek v archivu', 'one way' => True)

Kde (\d{4}) je rok v url

(\d{2}) měsíc a den

([\w-]+) nazev clanku

Závorky by způsobily, že se předají ty parametry view (render) metodě.

blog:archive:article pak cesta typu modul:presenter:view tedy vlastně adresář:třída:metoda

clanek v archivu je jméno routy a dala by se z něj reversním routingem a předáním parametrů zase vytvořit routa.

View metoda renderArticle() by pak měla definici s parametry a jejich případnými defaultními hodnotami normálně jak jsme zvyklí:
function renderArticle($year, $month, $day, $title) {}

Nicméně je to asi spíš návrh na implementaci just another router.

Jinak mi přijde trochu skryté, podle čeho se při generování $presenter->link('hello', 123) pozná, která routa se má použít.

David Grudl
Nette Core | 8218
+
0
-

Asi tak… úspornost za každou cenu není cílem :-) Spíš srozumitelnost.

Vašku, mám pocit, že co tady popisuješ, jsou spíš Rails nebo něco podobného. Nette funguje jinak. Oba systémy pracují s URL a oba routují, ale jde o zcela jinou filosofii a jsem přesvědčen, že Nette ji má vyspělejší (kdybych o tom přesvědčen nebyl, implementuji routování, které se používá jinde).

Výhoda Nette je v tom, že nemusí pojmenovávat routy. Že má minimální závislosti mezi vrstavama (např. není vztah mezi pořadím parametrů v routě a argumenty metody presenteru) atd.

Naprosto chápu, že je těžké přijmout odlišnou filosofii, pokud je člověk zvyklý na něco jiného.

ad jmenné prostory a moduly: přesně tahle je to připravené, moduly jsou vlastně jmenné prostory, ve kterých jsou presentery. Syntax Modul:Submodul:Presenter:view je už nyní platná.

veena
Člen | 98
+
0
-

Je to trochu odlišná filosofie. Ale přijde mi přehlednější, když jsou věci dány víc explicitně než implicitně. Routování, kdy se metoda presenteru nastavuje podle „proměnné“ v url mi přijde prostě příliš magická a nepřehledná. Radši bych u routy okamžitě viděl, který presenter ji zpracovává, než „routoval“ v hlavě.

Pojmenování rout má výhodu, že je to jednoduché na zapamatování což se vyplatí při zpětném vytváření odkazů. Takhle si člověk musí pamatovat jak se jmenuje view a presenter, takže zase routovat v hlavě :-)

Když se bude routa jmenovat stále stejně tak může změnit presenter i svoji url (vše definováno na jednom místě u definici routy – DRY) a nemusí se měnit parametry funkce link().

Jak bys třeba řešil vícejazyčné routy? tak aby /article i /clanek vedlo na stejný presenter?

Ale jak říkám, třeba časem implementuji takovýto router, protože Nette je tak dobře navrženo, že výměnu routeru umožňuje.

David Grudl
Nette Core | 8218
+
0
-

V jiných systémem má routování obrovských význam, naopak v Nette se jím netřeba zabývat. To je věc, kterou řeším často až když je aplikace hotová. Odsud zřejmě pramení to nepochopení.

Unitř aplikace se odkazuje tak, jako když volám metody v OOP: Presenter::view($arg1, $arg2). Konrétně třeba Product:detail($id). Volám metodu detail třídy Product a předám ji parametr $id. Připadá mi to maximálně srozumitelné a nevím, proč do toho zanášet další identifikátor routy – je zbytečný.


Pomiňme detaily, jako že zápis Product:detail(...) vede na ProductPresenter::renderDetail(...) – obojí lze totiž změnit úpravou metod formatPresenterClass, formatRenderMethod a zavedením anotoací.

David Grudl
Nette Core | 8218
+
0
-

veena napsal(a):

Jak bys třeba řešil vícejazyčné routy? tak aby /article i /clanek vedlo na stejný presenter?

$router[] = new Route('/article/<id>', array(
    'presenter' => 'Article',
    'lang' => 'en',
));

$router[] = new Route('/clanek/<id>', array(
    'presenter' => 'Article',
    'lang' => 'cs',
));

Presenter:

class ArticlePresenter extends Presenter
{

    public function renderDefault($id, $lang)
    {
        // pseudokód
        SELECT text FROM table WHERE id = $id AND lang = $lang
        $template->lang = $lang;
        $template->article = $text;
    }

}

Šablona:

<html lang="{$lang}">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <meta http-equiv="Content-Language" content="{$lang}">
</head>

<body>
        {!article}
</body>
</html>
veena
Člen | 98
+
0
-

David Grudl napsal(a):

V jiných systémem má routování obrovských význam, naopak v Nette se jím netřeba zabývat. To je věc, kterou řeším často až když je aplikace hotová. Odsud zřejmě pramení to nepochopení.

Unitř aplikace se odkazuje tak, jako když volám metody v OOP: Presenter::view($arg1, $arg2). Konrétně třeba Product:detail($id). Volám metodu detail třídy Product a předám ji parametr $id. Připadá mi to maximálně srozumitelné a nevím, proč do toho zanášet další identifikátor routy – je zbytečný.


Pomiňme detaily, jako že zápis Product:detail(...) vede na ProductPresenter::renderDetail(...) – obojí lze totiž změnit úpravou metod formatPresenterClass, formatRenderMethod a zavedením anotoací.

Snad rozumím. Myslím to tak, že identifikátor routy se podle mě hodí pro zpětné vytvoření url v šabloně. V presenteru se samozřejmě nepoužívá. Tedy že by se nějak předávalo do parametrů. Jen může také existovat nějaká funkce, která url získá reversně ze jména pokud je třeba potřeba k přesměrování apod.

Zkusím ale popřemýšlet o tvém více programátorském přístupu, kdy hlavní, neměnné a podstatn0 jsou názvy presenterů a view.

Dík za ukázku vícejazyčných rout. Je mi to jasnější. Tohle je explicitní dost.

Mě matou případy, kdy je presenter a view dynamicky generováno podle cesty v url. Ale to je holt můj problém :-)

David Grudl
Nette Core | 8218
+
0
-

Snad rozumím. Myslím to tak, že identifikátor routy se podle mě hodí pro zpětné vytvoření url v šabloně.

Ony se také v šabloně velmi často vytvářejí (příklad s využitím filtru curlyBrackets):

...<a href="{$presenter->link('edit', 10)}">self::edit(10)</a>...
...<a href="{$presenter->link('Product:list')}">Product::list()</a>...

Experimentálně lze využít i filtr netteLinks:

...<a href="nette:edit?id=10">self::edit(10)</a>...
...<a href="nette:Product:list">Product::list()</a>...

…Tedy že by se nějak předávalo do parametrů. Jen může také existovat nějaká funkce, která url získá reversně ze jména pokud je třeba potřeba k přesměrování apod.

URL generuje v presenteru (a komponentě) funkce $this->link('edit', 10) – tedy stejně jako v šabloně. Lze vygenerovat URL sám na sebe $this->backlink(). K přesměrování slouží $this->redirect(...), k přechodu na jiný presenter/view $this->forward(...).

Mě matou případy, kdy je presenter a view dynamicky generováno podle cesty v url. Ale to je holt můj problém :-)

Což se v praxi stejně tak moc nepoužívá…

veena
Člen | 98
+
0
-

Dobře, snad jsem už pochopil tvoji filosofii routování :-)

I když nebudeme uvažovat pojmenované routy, tak tu mám návrh na jednu možnost zápisu.

Pokud presenter a view jsou vždy povinné hodnoty, tak bych je vyřadil ze společného pole s ostatními parametry a dal jako samostatné hodnoty.

$router = $application->getRouter(array(

        array('index.php', 'default', 'default'),

        array('<presenter>/<action>/<id>', 'default', 'default', array('id' => NULL), Route::ONE_WAY),

	# případně již teď používat syntaxi namespace
        array('<presenter>/<action>/<id>', 'default:default', array('id' => NULL), Route::ONE_WAY),

 ... další seznam rout ...
));
David Grudl
Nette Core | 8218
+
0
-

View není potřeba uvádět vůbec – výchozí hodnota je ‚default‘ zcela automaticky.

Presenter jako extra parametr? Popřemýšlím.

Jinak by to v podstatě šlo, jen takto:

$router = $application->getRouter(array(

        new Route('index.php', 'default'),

        new Route('<presenter>/<action>/<id>', 'default', array('id' => NULL), Route::ONE_WAY),
...
));

To vytvoření objektu je skutečně klíčové.

Můžeš si to vyzkoušet hned (bez extra presenteru), změň řádky v Application/Application.php takto:

public function getRouter($init = NULL) // přidat $init = NULL
{
    if ($this->router === NULL) {
        $this->router = new MultiRouter($init); // přidat $init
phx
Člen | 651
+
0
-

Mel bych par otazek.

  1. K cemu je tam routa s index.php ?
  2. Co rpesne dela Route::ONE_WAY (typuju ze neco jako L v Rewrite, ale nejak mi to unika…)
  3. Jak udelat nejakou vychozi chybovou stranku, kdyz pozadovana neexistuje. Resi to vubec router?
David Grudl
Nette Core | 8218
+
0
-

Routa s index.php určuje, že při požadavku na stránku index.php se otevře presenter default a view default. Lze ji použít pro zpětnou kompatibilitu – pokud na web již existují odkazy ve tvaru http://example.com/index.php, je vhodné je podchytit.

U zpětně-kompatibilních rout se nastavuje příznak Route::ONE_WAY (jednosměrka), který zajistí, že routa může požadavek přijmou (stránka index.php funguje), ale nevytváří URL. Tedy při generování URL pro presenter default a view default se nevygeneruje index.php, ale použije se další routa.

V případě nenalezení routy se vyhodí výjimka. Je možné definovat presenter (v proměnné $application->errorPresenter), který se v takovém případě zavolá.

ViliamKopecky
Nette hipster | 230
+
0
-

V případě nenalezení routy se vyhodí výjimka. Je možné definovat presenter (v proměnné $application->errorPresenter), který se v takovém případě zavolá.

Áha, to je chytřeší (samozřejmě), já to obcházel přes zachytávání FileNotFoundException, což mi bylo jasný že neni to pravé ořechové…


Jinak v errorPresenteru se získá kód chyby (případně další věci) jak?

David Grudl
Nette Core | 8218
+
0
-

errorPresenter dostane parametr exception s vyhozenou výjimkou. Je možné ho získat třeba takto:

public function renderDefault($exception)
{
    ...
}

nebo

public function renderDefault()
{
    $exception = $this->params['exception'];
    // nebo:
    $exception = $this->request->params['exception'];
}
Kenn
Člen | 110
+
0
-

Nejspíš stupidní dotaz, ale potřebuji pro funkční routování něco upravovat v souboru htaccess nebo přidat nějaké zjišťování parametrů z URL? Mám nadefinované routy, vytvoří se pěkná adresa, ale vyplivne to 404ku.

Ondřej Brejla
Člen | 746
+
0
-

Kenn napsal(a):

Nejspíš stupidní dotaz, ale potřebuji pro funkční routování něco upravovat v souboru htaccess nebo přidat nějaké zjišťování parametrů z URL? Mám nadefinované routy, vytvoří se pěkná adresa, ale vyplivne to 404ku.

Je potřeba .htaccess…viz 646-htaccess

Kenn
Člen | 110
+
0
-

.htaccss mám správně, takže chyba bude nejspíš někde jinde. No nic, asi prozatím routování oželím.

EDIT: chyba byla v nastavení apache :-)

Editoval Kenn (27. 1. 2009 15:17)

kravčo
Člen | 721
+
0
-

Kenn napsal(a):

.htaccss mám správně, takže chyba bude nejspíš někde jinde. No nic, asi prozatím routování oželím.

EDIT: chyba byla v nastavení apache :-)

Pre budúcnosť, odhaľovať chyby routovania pomáha RoutingDebugger.

Editoval kravco (27. 1. 2009 16:54)