Routování jednourovňové adresy
- Montanus
- Člen | 10
Zdravím,
//produkt
$router[] = new Route('<url>/', array(
'module' => 'Front',
'presenter' => 'Product',
'action' => 'Default',
'url'=>null
));
//categorie
$router[] = new Route('<url>/', array(
'module' => 'Front',
'presenter' => 'Category',
'action' => 'Default',
'url'=>null
));
//novinky
$router[] = new Route('<url>/', array(
'module' => 'Front',
'presenter' => 'News',
'action' => 'Default',
'url'=>null
));
pokud to dojde do prvního presenteru a url neexistuje v db, chci to redirecnout na další routu (tedy vytvořit kaskádu, dokud to nespadne na 404)
Jak?
Nepsal bych, kdyby neprošel bezpočet článků, návodů a kde prostě na tohle řešení není…
Díky
- Jan Suchánek
- Člen | 404
@Montanus: Já jsem přesně tohle vyřešil vlastním routrem, který dostane fasádu, a v případě, že nemá url (slug) nakešovaný šáhne do repository a vytáhe id či přeloží id na url (slug), tzn. nepotřebuju tuhle kaskádu, není to lepší?
Editoval jenicek (29. 11. 2013 23:07)
- enumag
- Člen | 2118
@Montanus: Protože je to holý nesmysl, respektive nechápeš jak funguje routování. Rozhodnout zda URL matchuje danou routu je úkol routy. Pokud matchuje, pošle se to presenteru a ten už si s tím nějak poradí (když to v DB nenajde tak obvykle vyhodí BadRequestException která probublá na ErrorPresenter). Zkusit jednu routu, poslat presenteru a když to nevyjde zak zkusit druhou a jiný presenter je nesmysl už kvůli rychlosti. Správné řešení (jak už zaznělo) je vlastní router který se podívá do db a vyhodnotí který presenter má danou url zpracovat. Ty routy které jsou v Nette předepsané slouží pouze pro speciální případy kdy už z URL adresy lze přesně poznat o co se jedná, což samozřejmě není případ těchto url.
Editoval enumag (29. 11. 2013 23:40)
- Jan Suchánek
- Člen | 404
@Montanus: No jednoduše máš routu, která standardně filtruje /<presenter>/<action>/<id [0–9]>, teď pomiň zda ty masky mám špatně či dobře. Já fitruju pouze parametr presenter a pokud se mi nazev shoduje podle databaze s např. tvým požadavkem např. /alfa-romeo-156 tak v db mám přímo překlad, co je to sakra za presenter a mám vytaráno, stejně tak mohu pěkně přeložit i action + zachovávam si i možnost používat id, což je fajn ne? A všechno dobře kešuj, při změně invaliduj a bude to rychlé.
Lze takhle přeložit i Sign:in na /prihlasit-se nebo Sign:in lang ⇒ en na login nebo jiné divočárny.
Editoval jenicek (29. 11. 2013 23:49)
- enumag
- Člen | 2118
@Montanus: Honza Tvrdík měl na jedné posobotě přednášku na téma databázových routerů. Videozáznam k dispozici není, ale zde je router, který Honza během přednášky sepsal: https://github.com/…omRouter.php. Pozn. tohle nemá sloužit jako vzorové ideální řešení ale spíše nástřel. Nejsou tam ošetřené speciální případy, POST parametry etc.
Editoval enumag (29. 11. 2013 23:48)
- Jan Suchánek
- Člen | 404
@enumag: Pěkně! Já to mám podobně, ale využil jsem částečně Hosiplanuv Filter Route, jen s tím rozdílem že jsem vše delegoval na Fasádu, která rozhodovala zda použije Cache či Db, ale nevím zda se nevykašlat přidávat Route přímo ten manager či to neřídit pomocí událostí.
- Jan Suchánek
- Člen | 404
@enumag: Ještě by mě zajímala jedna věc. Je to to takto rozumně?
/**
* @return \Nette\Application\IRouter
*/
public function createRouter()
{
$router = new RouteList();
$backRoutes = new RouteList('Back');
$backRoutes[] = new Route('admin/<presenter>[/<action>[/<id>]]', 'Default:default');
$frontRoutes = new RouteList('Front');
$route = new SeoRoute('[<lang [cs|en|de]{2} >/]<presenter>[/<action>][/<id [0-9]+>]', array(
'presenter' => 'Default',
'action' => 'default',
'lang' => 'cs',
'id' => NULL
));
$route->addFilter($this->routerFacade, "presenter");
$frontRoutes[] = $route;
$route = new Route('[<lang [cs|en|de]{2} >/]<presenter>[/<action>][/<id [0-9]+>]', array(
'presenter' => 'Default',
'action' => 'default',
'lang' => 'cs',
'id' => NULL,
));
$frontRoutes[] = $route;
$router[] = $backRoutes;
$router[] = $frontRoutes;
return $router;
}
v konstruktoru předávám filtr, tak aby Router věděl o lang a zároveň
aby mohl pracovat s action a id.
V případě použití třeba /<presenter>/<action>/<id>
(/kosik/pridat/1). Proto nemohu použít uvedený.
Zároveň Router umožňuje opravovat špatně zadané adresy na správné, např. /en/kosik vrátí na /kosik a naopak, ale také umožňuje překlad z /cs/basket/add/1 změnit na /kosik/pridat/1, jinak o překladech je i pěkné video z PS 36 od Pandy.
Setr $route->addFilter($this->routerFacade, „presenter“); zkusím vyměnit za Kdyby\Event a nebo se spíš hodí Kdyby\AOP?
- enumag
- Člen | 2118
Setr $route->addFilter($this->routerFacade, „presenter“); zkusím vyměnit za Kdyby\Event a nebo se spíš hodí Kdyby\AOP?
Nevidím k tomu důvod, mám pocit že by se to tím zbytečně zkomplikovalo.
Nabízí se jen zjednodušení pomocí globálních filtrů v Nette 2.1. Díky tomu už bys nemusel Route dědit.
Video od Pandy je fajn, jen práci s databází tam má úplně špatně protože dědí Selection.
Editoval enumag (30. 11. 2013 10:28)
- Jan Suchánek
- Člen | 404
@enumag: Ok, u globálních filtrů jak k nim předat lang abych mohl filtrovat podle ní?
V tuto chvíli musim předávat závislost přez ten setr. a RouteListu přez konstruktor v neonu. Prostě mě nadchlo předat to nějakému tomu Lisenteru, tak jsem ho chtěl vyzkoušet a ať si s tim poradí, když už se používá i jinde, příliš náročné?
Když už jsme u toho, jakým způsobem na cache? Prostě mít ve fasádě pro zjištění url dva repositáře jeden na cache a druhý na db? Fasáda dělá ještě nějaké mirné korekce než data předává zpět Route.
- Jan Suchánek
- Člen | 404
@enumag: Předpokládám, že takhle by to mělo být ok?
$route = new Route('[<lang [cs|en|de]{2} >/]<slug>[/<action>][/<id [0-9]+>]', array(
NULL => array(
/* překládám slug na presenter */
Route::FILTER_IN => callback($this->urlService, 'filterIn'),
/* překládám na slug a odstraňuji presenter */
Route::FILTER_OUT => callback($this->urlService, 'filterOut'),
),
));
/* tzn. deleguji vše na model, ten dostal závislosti autowiringem z DI kontejneru */
Dají se definovat defaultní hodnoty? Nebo je musím pouze dodefinovat v modelu?
Editoval jenicek (3. 12. 2013 18:05)
- Jan Suchánek
- Člen | 404
@enumag: Jo maká to pěkně, jen místo presenter musím dát slug, tak abych dostal pomlčkovou variantu (a ne název presenteru) a v modelu nastavit výchozí parametry.
Edit: funguje to i s výchozími parametry libově:
$route = new Route('[<lang [cs|en|de]{2} >/]<slug>[/<action>][/<id [0-9]+>]', array(
NULL => array(
Route::FILTER_IN => callback($this->urlService, 'filterIn'),
Route::FILTER_OUT => callback($this->urlService, 'filterOut'),
),
'presenter' => 'Default',
'action' => 'default',
'lang' => 'cs',
'id' => NULL
));
$frontRoutes[] = $route;
Editoval jenicek (3. 12. 2013 18:07)