Nette\Application\Route
Úkolem routy je nejen URL adresu naparsovat a vytvořit z ní interní požadavek, ale i přesný opak – z interního požadavku vygenerovat URL.
Třída Route implementující rozhraní IRouter je
nástrojem pro tvorbu user-friendly URL adres. Že nejde o nic
složitého se můžete přesvědčit sami níže.
Definice cest
Prvním parametrem při tvorbě routy je maska cesty. Ta může být doplněna o validační podmínky ve formě klasických regulárních výrazů. Druhým parametrem je pole výchozích a fixních hodnot.
// akceptuje URL cestu ve tvaru např. admin/edit/10 nebo catalog/
$router[] = new Route('<presenter>/<view>/<id [0-9]+>', array(
'presenter' => 'Article',
'view' => 'show',
'id' => NULL,
));
Příklad ukazuje masku sestávající se ze tří parametrů, přičemž
všechny jsou volitelné, neboť mají definovánu výchozí hodnotu. Parametr
id má navíc specifikovánu validační podmínku
[0-9]+, tj. akceptuje jen číslo (u ostatních parametrů je
použita výchozí podmínka [^/]+).
Definice rout obvykle umístímě do souboru bootstrap.php:
$application = Environment::getApplication();
$router = $application->getRouter();
// nebo all-in-one row
$router = Environment::getApplication()->getRouter();
// vytvoření jednosměrné routy, která bude odchytávat
// všechny dotazy směrující na index.php
// a přesměrovávat na routu níže do cool-url tvaru
// automaticky zohledňuje SEO,
// takže se vám tyto stránky nezaindexují dvakrát
$router[] = new Route('index.php', array(
'presenter' => 'Article',
'view' => 'show',
), Route::ONE_WAY);
// deklarace obecné dvousměrné routy s cool-url tvarem
$router[] = new Route('<presenter>/<view>/<id>', array(
'presenter' => 'Article',
'view' => 'show',
'id' => NULL,
));
// vytvoříme odkaz
$presenter->link('Article:'); // ekvivalentní s Article:show
Routa s maskou index.php určuje, že při požadavku na
stránku index.php se otevře presenter Article a
pohled show. Příznak Route::ONE_WAY (jednosměrka)
zajistí, že routa může požadavek přijmout (stránka index.php
existuje), ale aplikace takové URL nevytvoří. Tedy při
generování URL pro presenter Article a pohled show
se použije vhodná následující routa.
Jednosměrné routy se používají třeba pro zachování zpětné
kompatibility – pokud na web již existují odkazy ve tvaru
http://example.com/index.php, budou tyto nadále funkční. Navíc
dojde k automatickému přesměrování na nový tvar URL.
Má-li být parametrem routy cesta filesystému, pak maskou
.*? povolíme všechny znaky včetně lomítek.
Například: new Route('/storage/<path .*?>', ...)
V případě nenalezení routy se vyhodí výjimka.
Pokud se žádná routa nenastaví, tak se o správné chování postará
automaticky SimpleRouter.
Uvnitř aplikace se odkazuje tak, jako když jsou volány metody v OOP:
Presenter::view($arg1, $arg2). Konrétně třeba
Product:detail($id). Voláme metodu detail třídy
Product a předáme jí parametr $id. Podrobně je
filosofie routování popsána v jiném
článku.
Foo parametry
Foo parametry rozšiřují možnosti definice rout. Narozdíl od klasických parametrů nemají název (místo něj se použije otazník), nepředávají se presenteru a slouží k tomu, aby bylo možné do masky přidat regulární výraz.
Příklad: jednosměrná routa akceptující index.html,
index.htm a index.php.
$router[] = new Route('index<? \.html?|\.php>', array(
'presenter' => 'Homepage',
'view' => 'default',
), Route::ONE_WAY);
Pokud by uvedená routa byla obousměrná, generovala by cestu index, kterou
však sama neumí akceptovat. Výraz by se proto musel rozšířit
i o prázdnou hodnotu na 'index<? \.html?|\.php|>'.
Nebo lze explicitně definovat řetězec, který bude při generování cesty použit (obdoba výchozí hodnoty u skutečných parametrů). Řetězec se vloží ihned za otazník:
$router[] = new Route('feed<?.xml \.xml|>', array(
'presenter' => 'Feed',
'view' => 'rss',
));
Tato routa akceptuje cesty feed.xml a feed,
přičemž generuje feed.xml.
Používání rout/odkazů v šablonách
Rozlišujeme více možností vytvoření odkazu, proto není jedno
na jakém objektu metodu link() voláme. Jelikož view
může měnit pouze presenter, komponenty pracují vždy pod tímto prahem.
Navíc se prohledávají odkazy v hierarchii směrem dolů k potomkům.
Tudíž $component->link() vede na signál,
$presenter->link() obvykle na view (nebo signál, je-li označen
vykřičníkem). Pro úplnost, i komponenta může volat
$this->presenter->link('view').
V šabloně se odkazy 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>
<a href="{$control->link('Article:view')}">Zobrazit články</a> // jedna z možností
<a href="{$presenter->link('Article:view')}">Zobrazit články</a> // další z možností
<a href="{$component->link('Article:view')}">Zobrazit články</a> // a do třetice
// jiná možnost: použít všechny možnosti filtru curly brackets
<a href="{link Article:view}">Zobrazit články</a> // control link
<a href="{plink Article:view}">Zobrazit články</a> // presenter link
<a href="{ajaxlink Article:view}">Zobrazit články</a> // ajax link / subrequest
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>
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(...). Rozdíl je v tom,
že redirect provede přesměrování na jinou stránku pomocí
HTTP a forward jen přepošle zpracování jinam.
Odkaz na jiný presenter
Pro odkazování se do jiného než aktuálního presenteru se používá
zápis ve tvaru:
$link->(destination [,arg [,arg ...]]) kde
destination je:
'anotherView'(odkaz na aktuální presenter aanotherView)'AnotherPresenter:anotherView'(odkaz naAnotherPresenteraanotherView)'AnotherPresenter:'(ozkaz naAnotherPresentera výchozí view'default')'AnotherModule:Presenter:view'(odkaz do jiného modulu)
Viz také:
Dynamické přidávání rout
Nyní si ukážeme, jak zaroutovat do naší aplikace nějaký existující modul.
Dejme tomu, že do website programované v Nette chceme přidat fórum.
Stačí, aby fórum disponovalo instalační funkcí
createRoutes():
class Forum
{
function createRoutes($router, $prefix)
{
$router[] = new Route($prefix . 'index.php', array(
'presenter' => 'Forum:Homepage',
'view' => 'default',
));
$router[] = new Route($prefix . 'admin.php', array(
'presenter' => 'Forum:Admin',
'view' => 'default',
));
...
}
}
„Zaroutování“ fóra do existující aplikace je pak velmi jednoduché.
bootstrap.php:
$router = $application->getRouter();
// přidáme své routy
...
// přidáme modul forum
Forum::createRoutes($router, '//forum.example.com/');
Multijazyčnost
Nette Framework nikomu nevnucuje konkrétní řešení. Otázkou mnohých složitějších systémů je multijazyčnost. Základem k jejímu vyřešení je dobrý návrh rout. Možností jak vyřešit tento požadavek je spostu a vše záleží jen na Vaší představivosti. Můžete se inspirovat na pár příkladech:
// nejjednodušší způsob řešení
$router[] = new Route('/article/<id>', array(
'presenter' => 'Article',
'lang' => 'en',
));
$router[] = new Route('/clanek/<id>', array(
'presenter' => 'Article',
'lang' => 'cs',
));
// další z možností: název jazyka ve tvaru doménu 3. řádu
$router[] = new Route('//<lang {?cs|en}>.example.com/<id>/<view>', array( ... ), Route::ONE_WAY);
$router[] = new Route('//<lang [a-z]{2}>.example.com/<id>/<view>', array( ... ), Route::ONE_WAY);
// další možnost: povinné a volitelné parametry
// - module je zadán a není v masce => fixní
// - lang není zadán a podléhá masce => povinný
$router[] = new Route('<lang [a-z]{2}>/<id>/<view>', array(
'module' => 'Front',
'presenter' => 'Homepage',
'view' => 'default',
'id' => NULL // takto definovaný parametr je volitelný
));
// poté někde ve startup() zavoláme: $this->lang = $this->getParam('lang');
Viz také:
