Routing

A Router felelős mindenért, ami az URL címekkel kapcsolatos, hogy Önnek már ne kelljen gondolkodnia rajtuk. Megmutatjuk:

  • hogyan állítsuk be a routert, hogy az URL-ek az elképzeléseinknek megfeleljenek
  • beszélünk a SEO-ról és az átirányításról
  • és megmutatjuk, hogyan írjunk saját routert

Az emberibb URL-ek (vagy cool vagy pretty URL-ek) használhatóbbak, megjegyezhetőbbek és pozitívan hozzájárulnak a SEO-hoz. A Nette erre gondol, és teljes mértékben támogatja a fejlesztőket. Pontosan olyan URL-struktúrát tervezhet az alkalmazásához, amilyet csak szeretne. Akár akkor is megtervezheti, amikor az alkalmazás már kész, mert ez nem igényel beavatkozást a kódba vagy a sablonokba. Ugyanis elegáns módon egy egyetlen helyen definiálódik, a routerben, és így nincs szétszórva annotációk formájában az összes presenterben.

A Nette routere kivételes abban, hogy kétirányú. Képes dekódolni a HTTP kérésben lévő URL-t, és linkeket is létrehozni. Tehát kulcsfontosságú szerepet játszik a Nette Applicationben, mert egyrészt eldönti, hogy melyik presenter és akció fogja végrehajtani az aktuális kérést, másrészt pedig a URL generálására használatos a sablonban stb.

Azonban a router nem korlátozódik csak erre a felhasználásra, használhatja olyan alkalmazásokban is, ahol egyáltalán nem használnak presentereket, REST API-khoz stb. További információk a Önálló használat részben.

Route gyűjtemény

Az alkalmazás URL címeinek formájának definiálásának legkellemesebb módját a Nette\Application\Routers\RouteList osztály kínálja. A definíció ún. route-ok listájából áll, azaz URL cím maszkokból és a hozzájuk rendelt presenterekből és akciókból, egy egyszerű API segítségével. A route-okat nem kell elneveznünk.

$router = new Nette\Application\Routers\RouteList;
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('article/<id>', 'Article:view');
// ...

A példa azt mondja, hogy ha a böngészőben megnyitjuk a https://domain.com/rss.xml címet, akkor a Feed presenter jelenik meg az rss akcióval, ha a https://domain.com/article/12 címet, akkor az Article presenter jelenik meg a view akcióval stb. Ha nem található megfelelő route, a Nette Application BadRequestException kivételt dob, amely a felhasználónak 404 Not Found hibaoldalként jelenik meg.

Route-ok sorrendje

Teljesen kulcsfontosságú a sorrend, amelyben az egyes route-ok fel vannak sorolva, mert sorban fentről lefelé értékelődnek ki. Az a szabály érvényes, hogy a route-okat a specifikusaktól az általánosakig deklaráljuk:

// ROSSZ: az 'rss.xml'-t az első route fogja el, és ezt a stringet <slug>-ként értelmezi
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');

// JÓ
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('<slug>', 'Article:view');

A route-ok fentről lefelé értékelődnek ki a linkek generálásakor is:

// ROSSZ: a 'Feed:rss' linket 'admin/feed/rss'-ként generálja
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');

// JÓ
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');

Nem titkoljuk Ön elől, hogy a route-ok helyes összeállítása némi ügyességet igényel. Mielőtt elsajátítaná, hasznos segítő lesz a routing panel.

Maszk és paraméterek

A maszk a web gyökérkönyvtárától számított relatív utat írja le. A legegyszerűbb maszk egy statikus URL:

$router->addRoute('products', 'Products:default');

Gyakran a maszkok ún. paramétereket tartalmaznak. Ezek hegyes zárójelekben vannak megadva (pl. <year>), és átadódnak a cél presenternek, például a renderShow(int $year) metódusnak vagy a $year perzisztens paraméternek:

$router->addRoute('chronicle/<year>', 'History:show');

A példa azt mondja, hogy ha a böngészőben megnyitjuk a https://example.com/chronicle/2020 címet, akkor a History presenter jelenik meg a show akcióval és a year: 2020 paraméterrel.

A paramétereknek közvetlenül a maszkban adhatunk alapértelmezett értéket, és ezzel opcionálissá válnak:

$router->addRoute('chronicle/<year=2020>', 'History:show');

A route mostantól elfogadja a https://example.com/chronicle/ URL-t is, amely szintén a History:show-t jeleníti meg a year: 2020 paraméterrel.

A paraméter természetesen lehet a presenter és az akció neve is. Például így:

$router->addRoute('<presenter>/<action>', 'Home:default');

Az említett route elfogadja pl. az /article/edit vagy az /catalog/list formátumú URL-eket, és ezeket Article:edit és Catalog:list presenterekként és akciókként értelmezi.

Ugyanakkor a presenter és action paramétereknek alapértelmezett értékként Home-ot és default-ot ad, így ezek is opcionálisak. Tehát a route elfogadja az /article formátumú URL-t is, és azt Article:default-ként értelmezi. Vagy fordítva, a Product:default link az /product utat generálja, az alapértelmezett Home:default link pedig a / utat.

A maszk nemcsak a web gyökérkönyvtárától számított relatív utat írhatja le, hanem abszolút utat is, ha perjellel kezdődik, vagy akár teljes abszolút URL-t is, ha két perjellel kezdődik:

// relatív a document roothoz
$router->addRoute('<presenter>/<action>', /* ... */);

// abszolút út (relatív a domainhez)
$router->addRoute('/<presenter>/<action>', /* ... */);

// abszolút URL domainnel együtt (relatív a sémához)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);

// abszolút URL sémával együtt
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);

Validációs kifejezések

Minden paraméterhez meg lehet határozni egy validációs feltételt reguláris kifejezéssel. Például az id paraméternek meghatározzuk, hogy csak számjegyeket tartalmazhat a \d+ reguláris kifejezéssel:

$router->addRoute('<presenter>/<action>[/<id \d+>]', /* ... */);

Minden paraméter alapértelmezett reguláris kifejezése [^/]+, azaz minden, kivéve a perjelet. Ha egy paraméternek perjeleket is el kell fogadnia, adjuk meg a .+ kifejezést:

// elfogadja a https://example.com/a/b/c címet, a path 'a/b/c' lesz
$router->addRoute('<path .+>', /* ... */);

Opcionális szekvenciák

A maszkban szögletes zárójelekkel lehet jelölni az opcionális részeket. A maszk bármely része lehet opcionális, és tartalmazhatnak paramétereket is:

$router->addRoute('[<lang [a-z]{2}>/]<name>', /* ... */);

// Elfogadott utak:
//    /cs/download  => lang => cs, name => download
//    /download     => lang => null, name => download

Ha egy paraméter egy opcionális szekvencia része, természetesen maga is opcionálissá válik. Ha nincs megadva alapértelmezett értéke, akkor null lesz.

Az opcionális részek a domainben is lehetnek:

$router->addRoute('//[<lang=en>.]example.com/<presenter>/<action>', /* ... */);

A szekvenciákat tetszőlegesen lehet egymásba ágyazni és kombinálni:

$router->addRoute(
	'[<lang [a-z]{2}>[-<sublang>]/]<name>[/page-<page=0>]',
	'Home:default',
);

// Elfogadott utak:
// 	/cs/hello
// 	/en-us/hello
// 	/hello
// 	/hello/page-12

Az URL generálásakor a legrövidebb változatra törekszünk, tehát minden, amit ki lehet hagyni, kihagyásra kerül. Ezért például az index[.html] route az /index utat generálja. A viselkedés megfordítása a bal szögletes zárójel utáni felkiáltójellel lehetséges:

// elfogadja a /hello és /hello.html címeket, /hello-t generál
$router->addRoute('<name>[.html]', /* ... */);

// elfogadja a /hello és /hello.html címeket, /hello.html-t generál
$router->addRoute('<name>[!.html]', /* ... */);

Az opcionális paraméterek (azaz az alapértelmezett értékkel rendelkező paraméterek) szögletes zárójelek nélkül lényegében úgy viselkednek, mintha a következőképpen lennének zárójelezve:

$router->addRoute('<presenter=Home>/<action=default>/<id=>', /* ... */);

// megfelel ennek:
$router->addRoute('[<presenter=Home>/[<action=default>/[<id>]]]', /* ... */);

Ha befolyásolni szeretnénk a záró perjel viselkedését, hogy pl. a /home/ helyett csak /home generálódjon, azt így lehet elérni:

$router->addRoute('[<presenter=Home>[/<action=default>[/<id>]]]', /* ... */);

Helyettesítő karakterek

Az abszolút út maszkjában használhatjuk a következő helyettesítő karaktereket, és így elkerülhetjük például annak szükségességét, hogy a maszkba írjuk a domaint, amely eltérhet a fejlesztői és az éles környezetben:

  • %tld% = top level domain, pl. com vagy org
  • %sld% = second level domain, pl. example
  • %domain% = domain aldomainek nélkül, pl. example.com
  • %host% = teljes host, pl. www.example.com
  • %basePath% = út a gyökérkönyvtárhoz
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action', /* ... */);

Bővített jelölés

A route célja, amelyet általában Presenter:action formában írunk, tömbként is megadható, amely definiálja az egyes paramétereket és azok alapértelmezett értékeit:

$router->addRoute('<presenter>/<action>[/<id \d+>]', [
	'presenter' => 'Home',
	'action' => 'default',
]);

Részletesebb specifikációhoz használható egy még bővebb forma, ahol az alapértelmezett értékeken kívül beállíthatjuk a paraméterek további tulajdonságait is, mint például a validációs reguláris kifejezést (lásd az id paramétert):

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>[/<id>]', [
	'presenter' => [
		Route::Value => 'Home',
	],
	'action' => [
		Route::Value => 'default',
	],
	'id' => [
		Route::Pattern => '\d+',
	],
]);

Fontos megjegyezni, hogy ha a tömbben definiált paraméterek nincsenek megadva az út maszkjában, értéküket nem lehet megváltoztatni, még az URL-ben a kérdőjel után megadott query paraméterekkel sem.

Szűrők és fordítások

Az alkalmazás forráskódjait angolul írjuk, de ha a weboldalnak magyar URL-ekkel kell rendelkeznie, akkor az egyszerű routing típus:

$router->addRoute('<presenter>/<action>', 'Home:default');

angol URL-eket fog generálni, mint például /product/123 vagy /cart. Ha azt szeretnénk, hogy a presenterek és akciók az URL-ben magyar szavakkal legyenek reprezentálva (pl. /produkt/123 vagy /kosik), használhatunk fordítási szótárat. Ennek megadásához már a második paraméter “beszédesebb” változatára van szükség:

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterTable => [
			// string az URL-ben => presenter
			'produkt' => 'Product',
			'kosik' => 'Cart',
			'katalog' => 'Catalog',
		],
	],
	'action' => [
		Route::Value => 'default',
		Route::FilterTable => [
			'lista' => 'list',
		],
	],
]);

A fordítási szótár több kulcsa is ugyanarra a presenterhez vezethet. Ezzel különböző aliasokat hozunk létre hozzá. Kanonikus változatnak (tehát annak, amely a generált URL-ben lesz) az utolsó kulcs számít.

A fordítási táblát így bármelyik paraméterre lehet alkalmazni. Ha a fordítás nem létezik, az eredeti érték veszi át. Ezt a viselkedést megváltoztathatjuk a Route::FilterStrict => true hozzáadásával, és a route elutasítja az URL-t, ha az érték nincs a szótárban.

A tömb formájú fordítási szótár mellett saját fordítási függvényeket is bevethetünk.

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>/<id>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterIn => function (string $s): string { /* ... */ },
		Route::FilterOut => function (string $s): string { /* ... */ },
	],
	'action' => 'default',
	'id' => null,
]);

A Route::FilterIn függvény átalakít az URL-ben lévő paraméter és a presenternek átadott string között, a FilterOut függvény pedig az ellenkező irányú átalakítást biztosítja.

A presenter, action és module paramétereknek már vannak előre definiált szűrőik, amelyek átalakítanak a PascalCase ill. camelCase stílus és az URL-ben használt kebab-case között. A paraméterek alapértelmezett értéke már az átalakított formában íródik, tehát például a presenter esetében <presenter=ProductEdit>-et írunk, nem pedig <presenter=product-edit>-et.

Általános szűrők

A konkrét paraméterekhez szánt szűrők mellett definiálhatunk általános szűrőket is, amelyek megkapják az összes paraméter asszociatív tömbjét, amelyet tetszőlegesen módosíthatnak, majd visszaadják. Az általános szűrőket a null kulcs alatt definiáljuk.

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => 'Home',
	'action' => 'default',
	null => [
		Route::FilterIn => function (array $params): array { /* ... */ },
		Route::FilterOut => function (array $params): array { /* ... */ },
	],
]);

Az általános szűrők lehetővé teszik a route viselkedésének teljesen tetszőleges módosítását. Használhatjuk őket például paraméterek módosítására más paraméterek alapján. Például a <presenter> és <action> lefordítása az aktuális <lang> paraméter értéke alapján.

Ha egy paraméternek van saját szűrője definiálva, és egyidejűleg létezik általános szűrő is, akkor a saját FilterIn hajtódik végre az általános előtt, és fordítva, az általános FilterOut a saját előtt. Tehát az általános szűrőn belül a presenter ill. action paraméterek értékei PascalCase ill. camelCase stílusban vannak megadva.

Egyirányú OneWay

Az egyirányú route-okat a régi URL-ek funkcionalitásának megőrzésére használják, amelyeket az alkalmazás már nem generál, de még mindig elfogad. OneWay jelzővel jelöljük őket:

// régi URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', $router::ONE_WAY);
// új URL /product/123
$router->addRoute('product/<id>', 'Product:detail');

A régi URL-re való hozzáféréskor a presenter automatikusan átirányít az új URL-re, így ezeket az oldalakat a keresőmotorok nem indexelik kétszer (lásd SEO a kanonizace).

Dinamikus routing callbackekkel

A dinamikus routing callbackekkel lehetővé teszi, hogy a route-okhoz közvetlenül függvényeket (callbackeket) rendeljen, amelyek akkor hajtódnak végre, amikor az adott utat meglátogatják. Ez a rugalmas funkcionalitás lehetővé teszi, hogy gyorsan és hatékonyan hozzon létre különböző végpontokat (endpoints) az alkalmazásához:

$router->addRoute('test', function () {
	echo 'a /test címen van';
});

Definiálhat paramétereket is a maszkban, amelyek automatikusan átadódnak a callbacknek:

$router->addRoute('<lang cs|en>', function (string $lang) {
	echo match ($lang) {
		'cs' => 'Üdvözöljük weboldalunk cseh verzióján!',
		'en' => 'Welcome to the English version of our website!',
	};
});

Modulok

Ha több route-unk van, amelyek egy közös modulba tartoznak, használjuk a withModule()-t:

$router = new RouteList;
$router->withModule('Forum') // a következő route-ok a Forum modul részei
	->addRoute('rss', 'Feed:rss') // a presenter Forum:Feed lesz
	->addRoute('<presenter>/<action>')

	->withModule('Admin') // a következő route-ok a Forum:Admin modul részei
		->addRoute('sign:in', 'Sign:in');

Alternatívaként használható a module paraméter:

// Az URL manage/dashboard/default az Admin:Dashboard presenterhez map-el
$router->addRoute('manage/<presenter>/<action>', [
	'module' => 'Admin',
]);

Aldomainek

A route gyűjteményeket aldomainek szerint is tagolhatjuk:

$router = new RouteList;
$router->withDomain('example.com')
	->addRoute('rss', 'Feed:rss')
	->addRoute('<presenter>/<action>');

A domain névben használhatunk zástupné znaky helyettesítő karaktereket is:

$router = new RouteList;
$router->withDomain('example.%tld%')
	// ...

Útvonal prefix

A route gyűjteményeket az URL útvonala szerint is tagolhatjuk:

$router = new RouteList;
$router->withPath('eshop')
	->addRoute('rss', 'Feed:rss') // elfogja az /eshop/rss URL-t
	->addRoute('<presenter>/<action>'); // elfogja az /eshop/<presenter>/<action> URL-t

Kombinációk

A fenti tagolásokat kölcsönösen kombinálhatjuk:

$router = (new RouteList)
	->withDomain('admin.example.com')
		->withModule('Admin')
			->addRoute(/* ... */)
			->addRoute(/* ... */)
		->end()
		->withModule('Images')
			->addRoute(/* ... */)
		->end()
	->end()
	->withDomain('example.com')
		->withPath('export')
			->addRoute(/* ... */)
			// ...

Query paraméterek

A maszkok tartalmazhatnak query paramétereket is (paraméterek a kérdőjel után az URL-ben). Ezekhez nem lehet validációs kifejezést definiálni, de meg lehet változtatni a nevüket, amely alatt a presenternek átadódnak:

// a 'cat' query paramétert az alkalmazásban 'categoryId' néven szeretnénk használni
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);

Foo paraméterek

Most már mélyebbre megyünk. A Foo paraméterek lényegében névtelen paraméterek, amelyek lehetővé teszik reguláris kifejezések illesztését. Példa egy route-ra, amely elfogadja a /index, /index.html, /index.htm és /index.php címeket:

$router->addRoute('index<? \.html?|\.php|>', /* ... */);

Explicit módon is definiálható a string, amelyet az URL generálásakor használni kell. A stringnek közvetlenül a kérdőjel után kell elhelyezkednie. A következő route hasonló az előzőhöz, de /index.html-t generál /index helyett, mert a .html string van beállítva generálási értékként:

$router->addRoute('index<?.html \.html?|\.php|>', /* ... */);

Integrálás az alkalmazásba

Ahhoz, hogy a létrehozott routert bekapcsoljuk az alkalmazásba, szólnunk kell róla a DI konténernek. A legegyszerűbb út egy factory elkészítése, amely a router objektumot létrehozza, és a konfigurációban közölni a konténerrel, hogy azt használja. Tegyük fel, hogy erre a célra megírjuk az App\Core\RouterFactory::createRouter() metódust:

namespace App\Core;

use Nette\Application\Routers\RouteList;

class RouterFactory
{
	public static function createRouter(): RouteList
	{
		$router = new RouteList;
		$router->addRoute(/* ... */);
		return $router;
	}
}

konfigurációba pedig beírjuk:

services:
	- App\Core\RouterFactory::createRouter

Bármilyen függőség, például adatbázisra stb., átadódik a factory metódusnak annak paramétereiként autowiring segítségével:

public static function createRouter(Nette\Database\Connection $db): RouteList
{
	// ...
}

SimpleRouter

Sokkal egyszerűbb router, mint a route gyűjtemény, a SimpleRouter. Akkor használjuk, ha nincsenek különösebb igényeink az URL formájára, ha nincs mod_rewrite (vagy annak alternatívái) elérhető, vagy ha még nem akarunk szép URL-ekkel foglalkozni.

Körülbelül ilyen formátumú címeket generál:

http://example.com/?presenter=Product&action=detail&id=123

A SimpleRouter konstruktorának paramétere az alapértelmezett presenter & akció, amelyre irányítani kell, ha paraméterek nélkül nyitjuk meg az oldalt, pl. http://example.com/.

// az alapértelmezett presenter 'Home' lesz, az akció pedig 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');

Javasoljuk a SimpleRouter közvetlen definiálását a konfigurációban:

services:
	- Nette\Application\Routers\SimpleRouter('Home:default')

SEO és kanonizáció

A keretrendszer hozzájárul a SEO-hoz (keresőoptimalizálás) azáltal, hogy megakadályozza a duplikált tartalom létezését különböző URL-eken. Ha egy bizonyos célhoz több cím vezet, pl. /index és /index.html, a keretrendszer az elsőt elsődlegesnek (kanonikusnak) határozza meg, a többit pedig 301-es HTTP kóddal átirányítja rá. Ennek köszönhetően a keresőmotorok nem indexelik kétszer az oldalakat, és nem osztják meg a page rankjüket.

Ezt a folyamatot kanonizációnak nevezik. A kanonikus URL az, amelyet a router generál, azaz az első megfelelő route a gyűjteményben OneWay jelző nélkül. Ezért a gyűjteményben az elsődleges route-okat adjuk meg először.

A kanonizációt a presenter végzi, további információk a kanonizáció fejezetben.

HTTPS

Ahhoz, hogy a HTTPS protokollt használhassuk, engedélyezni kell a hostingen és helyesen kell konfigurálni a szervert.

Az egész weboldal HTTPS-re való átirányítását a szerver szintjén kell beállítani, például a .htaccess fájl segítségével az alkalmazásunk gyökérkönyvtárában, 301-es HTTP kóddal. A beállítás eltérhet a hostingtól függően, és kb. így néz ki:

<IfModule mod_rewrite.c>
	RewriteEngine On
	...
	RewriteCond %{HTTPS} off
	RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
	...
</IfModule>

A router ugyanazzal a protokollal generálja az URL-eket, amellyel az oldal betöltődött, így semmi mást nem kell beállítani.

Ha azonban kivételesen szükségünk van arra, hogy különböző route-ok különböző protokollok alatt fussanak, azt a route maszkjában adjuk meg:

// HTTP-vel fog címet generálni
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);

// HTTPS-sel fog címet generálni
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);

Router debuggolása

Tracy Barban megjelenő routing panel hasznos segítő, amely megjeleníti a route-ok listáját és azokat a paramétereket is, amelyeket a router az URL-ből nyert.

A zöld sáv a ✓ szimbólummal azt a route-ot jelöli, amely feldolgozta az aktuális URL-t, a kék szín és a ≈ szimbólum azokat a route-okat jelöli, amelyek szintén feldolgozták volna az URL-t, ha a zöld nem előzte volna meg őket. Továbbá látjuk az aktuális presentert & akciót.

Ugyanakkor, ha váratlan átirányítás történik a kanonizáció miatt, hasznos megnézni a redirect sávban lévő panelt, ahol megtudhatja, hogyan értelmezte a router eredetileg az URL-t, és miért irányított át.

A router debuggolásakor javasoljuk a Developer Tools (Ctrl+Shift+I vagy Cmd+Option+I) megnyitását a böngészőben, és a Network panelen a cache kikapcsolását, hogy az átirányítások ne kerüljenek bele.

Teljesítmény

A route-ok száma befolyásolja a router sebességét. Számuknak semmiképpen sem szabadna meghaladnia a néhány tucatot. Ha a weboldalának túl bonyolult az URL struktúrája, írhat saját, testreszabott vlastní router routert.

Ha a routernek nincsenek függőségei, például adatbázisra, és a factory-ja nem fogad argumentumokat, akkor az összeállított formáját közvetlenül a DI konténerbe szerializálhatjuk, és ezzel kissé felgyorsíthatjuk az alkalmazást.

routing:
	cache: true

Saját router

A következő sorok nagyon haladó felhasználóknak szólnak. Létrehozhat saját routert, és teljesen természetesen beillesztheti a route gyűjteménybe. A router a Nette\Routing\Router interfész implementációja két metódussal:

use Nette\Http\IRequest as HttpRequest;
use Nette\Http\UrlScript;

class MyRouter implements Nette\Routing\Router
{
	public function match(HttpRequest $httpRequest): ?array
	{
		// ...
	}

	public function constructUrl(array $params, UrlScript $refUrl): ?string
	{
		// ...
	}
}

A match metódus feldolgozza az aktuális kérést $httpRequest, amelyből nemcsak az URL-t, hanem a fejléceket stb. is meg lehet szerezni, egy tömbbe, amely tartalmazza a presenter nevét és annak paramétereit. Ha nem tudja feldolgozni a kérést, null-t ad vissza. A kérés feldolgozásakor legalább a presentert és az akciót vissza kell adnunk. A presenter neve teljes, és tartalmazza az esetleges modulokat is:

[
	'presenter' => 'Front:Home',
	'action' => 'default',
]

A constructUrl metódus fordítva, a paraméterek tömbjéből állítja össze a végső abszolút URL-t. Ehhez felhasználhatja a $refUrl paraméterből származó információkat, ami az aktuális URL.

A route gyűjteményhez az add() segítségével adhatja hozzá:

$router = new Nette\Application\Routers\RouteList;
$router->add($myRouter);
$router->addRoute(/* ... */);
// ...

Önálló használat

Önálló használat alatt azt értjük, hogy a router képességeit olyan alkalmazásban használjuk, amely nem használja a Nette Applicationt és a presentereket. Szinte minden érvényes rá, amit ebben a fejezetben megmutattunk, a következő különbségekkel:

Tehát ismét létrehozunk egy metódust, amely összeállítja nekünk a routert, pl.:

namespace App\Core;

use Nette\Routing\RouteList;

class RouterFactory
{
	public static function createRouter(): RouteList
	{
		$router = new RouteList;
		$router->addRoute('rss.xml', [
			'controller' => 'RssFeedController',
		]);
		$router->addRoute('article/<id \d+>', [
			'controller' => 'ArticleController',
		]);
		// ...
		return $router;
	}
}

Ha DI konténert használ, amit javasolunk, ismét hozzáadjuk a metódust a konfigurációhoz, majd a routert a HTTP kéréssel együtt megszerezzük a konténerből:

$router = $container->getByType(Nette\Routing\Router::class);
$httpRequest = $container->getByType(Nette\Http\IRequest::class);

Vagy közvetlenül létrehozzuk az objektumokat:

$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();

Most már csak hagyni kell a routert dolgozni:

$params = $router->match($httpRequest);
if ($params === null) {
	// nem találtunk megfelelő route-ot, 404-es hibát küldünk
	exit;
}

// feldolgozzuk a kapott paramétereket
$controller = $params['controller'];
// ...

És fordítva, a routert használjuk a link összeállításához:

$params = ['controller' => 'ArticleController', 'id' => 123];
$url = $router->constructUrl($params, $httpRequest->getUrl());