Routování, jak docílit těchto tvarů

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

Zdravím všechny,

ve svém prázdninovém tažení po tajích nette jsem konečně došel k routám. Ale nevím si rady, jak co nejefektivněji napsat routy, pokud chci docílit takovýchto tvarů:

Předvedu nějaké příklady:

  • domena.cz/user/jirda/

    User:default … id=jirda

  • domena.cz/user/change-password/

    User:changePassword

  • domena.cz/product/hp-notebook/

    product:default … id=hp-notebook

  • domena.cz/product/edit/hp-notebook/ nebo domena.cz/product/hp-notebook/edit/

    (je mi jedno, na ktere z techto pozic bude edit)

    product:edit … id=hp-notebook

  • domena.cz/product/info/

    product:info

Snažil jsem se napsat více příkladů, aby bylo jasnější o co mi jde.

Možná by se to dalo shrnout takto:

  • Nechci, aby se jakkoli v adrese zobrazil default (viz. 1. a 3. příklad)
  • Pokud možno nniverzálně, ne psát routy zvlášť pro každý presenter
  • Předejít situaci, kdy by mohlo třeba v příkladě 2 dojít k volání User:default s id=change-password

Jak jsem bojoval já?

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

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

Těmto routám vyhovoval:

  • domena.cz/user/jirda/

    User:default … id=jirda

  • domena.cz/product/hp-notebook/

    product:default … id=hp-notebook

  • domena.cz/product/edit/hp-notebook/

    product:edit … id=hp-notebook

Nevyhovoval:

  • domena.cz/user/change-password/

    místo User:changePassword došlo k User:default … id=change-password

  • domena.cz/product/info/

    místo product:info došlo k Product:info … id=info

Je mi vcelku jasné, proč dochází k tomu, že tyto tvary adres nesplní to, co bych chtěl. Bohužel ale nevím, jak pokrýt všechny podoby adres, které jsem prezentoval a to především co nejefektivněji s minimálním počtem rout.

Závěrem se omlouvám za trochu delší příspěvek, ale snažil jsem se, aby byl co nejobsáhlejší a aby se v něm (snad) dalo dobře zorientovat.

Děkuji všem, za jejich případné rady.

Jan Tvrdík
Nette guru | 2595
+
0
-

Napadají mě dvě možnosti: 1. Napsat si vlastní router (ideální varianta, tak jsem to řešil já) 2. Přidat manuální routy

$router[] = new Route('user/change-password/', array(
	'presenter' => 'User',
	'action' => 'changePassword',
));
Ondřej Mirtes
Člen | 1536
+
0
-

No, musíš routeru dát vědět, že neexistuje uživatel s ID change-password a product s ID info (a zajistit v administraci, aby takové položky nešly do databáze přidat).

Určitě ti tu někdo navrhne vytvoření vlastního routu (k čemuž jsem se zatím neodvážil), já podobný problém řešil nějak takto (snad jsem se nijak neuklepl, nezkoušel jsem to):

$routingModel = new Models\RoutingModel(); //cached

//matches username
$router[] = new Route('user/<id ' . implode('|', $routingModel->getUsers()) . '>/', array(
    'presenter' => 'User',
    'action' => 'default',
));

//matches product (also its editing)
$router[] = new Route('product/<id ' . implode('|', $routingModel->getProducts()) . '>/<action>', array(
    'presenter' => 'Product',
    'action' => 'default',
));

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

Ty metody routing modelu vrací jednoduché pole s jednotlivými položkami databáze, aby se vytvořil vzor pro routu v tomto tvaru:

'user/<id jarda|pepa|franda>/'
Jirda
Člen | 103
+
0
-

Jan Tvrdík napsal(a):

Napadají mě dvě možnosti: 1. Napsat si vlastní router (ideální varianta, tak jsem to řešil já) 2. Přidat manuální routy

$router[] = new Route('user/change-password/', array(
	'presenter' => 'User',
	'action' => 'changePassword',
));

Myslíš ten, co jsi prezentoval zde ?

Jan Tvrdík
Nette guru | 2595
+
0
-

Jirda napsal(a):

Myslíš ten, co jsi prezentoval zde ?

Tak přesně ten jsem nemyslel, ale měl by fungovat, akorát budeš muset použít jeho rozšířenou variantu + případně i upravit celý router, pokud nechceš tu action=edit za otazníkem.

Jirda
Člen | 103
+
0
-

Jan Tvrdík napsal(a):

Jirda napsal(a):

Myslíš ten, co jsi prezentoval zde ?

Tak přesně ten jsem nemyslel, ale měl by fungovat, akorát budeš muset použít jeho rozšířenou variantu + případně i upravit celý router, pokud nechceš tu action=edit za otazníkem.

Ještě mě napadla třetí možnost a to v případě, že detekuji stav, kdy je třeba id rovno change-password, tak dojde k zavolání daného view. De facto by došlo k situaci, kdy bych si v defaultu vytvořil takový mini router pro presenter. Akorát si myslím, že takové řešení by nebylo moudré a začalo by mě unášet někam, kam bych neměl jít.

Co se týše ale toho manuálního nastavení, tam nevidím problém tolik s realizaci, ale spíše se obávám té osudné věty v dokumentaci:
Počet rout má vliv na rychlost aplikace, zejména při generování odkazů.

Editoval Jirda (31. 7. 2009 23:52)

Jirda
Člen | 103
+
0
-

LastHunter napsal(a):

No, musíš routeru dát vědět, že neexistuje uživatel s ID change-password a product s ID info (a zajistit v administraci, aby takové položky nešly do databáze přidat).

Určitě ti tu někdo navrhne vytvoření vlastního routu (k čemuž jsem se zatím neodvážil), já podobný problém řešil nějak takto (snad jsem se nijak neuklepl, nezkoušel jsem to):

$routingModel = new Models\RoutingModel(); //cached

//matches username
$router[] = new Route('user/<id ' . implode('|', $routingModel->getUsers()) . '>/', array(
    'presenter' => 'User',
    'action' => 'default',
));

//matches product (also its editing)
$router[] = new Route('product/<id ' . implode('|', $routingModel->getProducts()) . '>/<action>', array(
    'presenter' => 'Product',
    'action' => 'default',
));

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

Ty metody routing modelu vrací jednoduché pole s jednotlivými položkami databáze, aby se vytvořil vzor pro routu v tomto tvaru:

'user/<id jarda|pepa|franda>/'

Zajímavé řešení, ale říkám si, co když je třeba 1000 uživatelů. Jak to pak ovlivní rychlost?

Jan Tvrdík
Nette guru | 2595
+
0
-

Jirda napsal(a):

Ještě mě napadla třetí možnost a to v případě, že detekuji stav, kdy je třeba id rovno change-password, tak dojde k zavolání daného view. De facto by došlo k situaci, kdy bych si v defaultu vytvořil takový mini router pro presenter. Akorát si myslím, že takové řešení by nebylo moudré a začalo by mě unášet někam, kam bych neměl jít.

Není to sice čisté z hlediska návrhu, ale určitě to bude fungovat. Místo změny view je vhodné použít $this->forward.

Co se týše ale toho manuálního nastavení, tam nevidím problém tolik s realizaci, ale spíše se obávám té osudné věty v dokumentaci:
Počet rout má vliv na rychlost aplikace, zejména při generování odkazů.

Tak zrovna toho bych se nebál. I kdyby jsi těch statických rout měl 10, tak to na výkonu nepoznáš (schválně to zkus změřit). Pokud by jsi to chtěl super rychlé, tak lze vytvořit speciální StaticRoute, který bude ještě rychlejší (i když téměř neměřitelně).

Jirda
Člen | 103
+
0
-

Jan Tvrdík napsal(a):

Jirda napsal(a):

Ještě mě napadla třetí možnost a to v případě, že detekuji stav, kdy je třeba id rovno change-password, tak dojde k zavolání daného view. De facto by došlo k situaci, kdy bych si v defaultu vytvořil takový mini router pro presenter. Akorát si myslím, že takové řešení by nebylo moudré a začalo by mě unášet někam, kam bych neměl jít.

Není to sice čisté z hlediska návrhu, ale určitě to bude fungovat. Místo změny view je vhodné použít $this->forward.

Co se týše ale toho manuálního nastavení, tam nevidím problém tolik s realizaci, ale spíše se obávám té osudné věty v dokumentaci:
Počet rout má vliv na rychlost aplikace, zejména při generování odkazů.

Tak zrovna toho bych se nebál. I kdyby jsi těch statických rout měl 10, tak to na výkonu nepoznáš (schválně to zkus změřit). Pokud by jsi to chtěl super rychlé, tak lze vytvořit speciální StaticRoute, který bude ještě rychlejší (i když téměř neměřitelně).

Dobře, ještě to promyslím, jakým směrem se uberu. Ale i tak, díky!

Patrik Votoček
Člen | 2221
+
0
-

Přidávám se k možnosti kde máš pár krajních stavů (change-password, edit) udělat statické routy přesně pro tyto případy. Moc to aplikaci nezpomalí a pro dynamická data nechat dynamické routy. Sám to tak řeším.

Oggy
Člen | 306
+
0
-

Mám takový dotaz..
dejme tomu,že máme v db strukturu webu..nějak takto: id,url,presenter
potom bych viděl možné řešení s url např. takto

<?php
	$sekce = new Sekce();
        Route::addStyle('#presenter', presenter);
        Route::setStyleProperty('#presenter', Route::FILTER_IN, array($sekce,'getPresenterName'));

	$router[] = new Route('<presenter #presenter>/<action>/<id>', array(
                'module' => 'Front',
		'presenter' => 'Home',
		'action' => 'default',
		'id' => NULL,
	));
?>

kde getPresenterName podle url vrátí který presenter se má volat..

čekal bych že pokud zavolám

doména/neco (stránku neco = presenter např. Product)

url bude ve tvaru doména/něco a filtr mi vrátil presenter Product.. který bude zavolán
ale stále se v url dostávám na tvar:
doména/product ..

nevím, kde dělám chybu..nebo překladový slovník na tohle nelze použít?

Jan Tvrdík
Nette guru | 2595
+
0
-

Nechce se mi nad tím přemýšlet, ale téměř určitě je potřeba použít i Router::FILTER_OUT.

Editoval Jan Tvrdík (30. 8. 2009 0:54)

Oggy
Člen | 306
+
0
-

Jan Tvrdík napsal(a):

Nechce se mi nad tím přemýšlet, ale téměř určitě je potřeba použít i Router::FILTER_OUT.

To já ale nepotřebuji.. nebo dsi to moc nedokáži představit..většinu stránek bude „obhospodařovat“ jeden presenetr..např. page.. a pak by bylo pár jiných..Home, Product nebo něco jiného.. tzn.. funkce podle presenteru vrať url by nešla.. není to 1:1

edit:

tak jsem trošku experimentoval..a do filtr out jsem dal stejnou fci..getPresenterName .. a url už je ve správném tvaru..ale teď to nemůže najít odpovídající routu..

url: neco.cz/vrtulnik/objednavka/1

chyba: No route for Front:Page:objednavka(id=1)

routa:

<?php
$router[] = new Route('<presenter>/<action>/<id>', array(
                'module' => 'Front',
		'presenter' => 'Home',
		'action' => 'default',
		'id' => NULL,
	));
?>

Editoval Oggy (30. 8. 2009 8:03)