Routowanie
Router odpowiada za wszystko związane z adresami URL, abyś Ty już nie musiał się nad nimi zastanawiać. Pokażemy:
- jak ustawić router, aby URL były zgodne z oczekiwaniami
- powiemy o SEO i przekierowaniach
- i pokażemy, jak napisać własny router
Bardziej ludzkie URL (lub też cool czy pretty URL) są bardziej użyteczne, łatwiejsze do zapamiętania i pozytywnie wpływają na SEO. Nette o tym myśli i w pełni wychodzi naprzeciw deweloperom. Możesz dla swojej aplikacji zaprojektować dokładnie taką strukturę adresów URL, jaką będziesz chciał. Możesz ją zaprojektować nawet w chwili, gdy aplikacja jest już gotowa, ponieważ obejdzie się to bez ingerencji w kod czy szablony. Definiuje się ją bowiem w elegancki sposób w jednym jedynym miejscu, w routerze, i nie jest rozproszona w formie adnotacji we wszystkich presenterach.
Router w Nette jest wyjątkowy tym, że jest dwukierunkowy. Potrafi zarówno dekodować URL w żądaniu HTTP, jak i tworzyć linki. Odgrywa więc kluczową rolę w Nette Application, ponieważ nie tylko decyduje o tym, który presenter i akcja będzie wykonywać aktualne żądanie, ale także wykorzystuje się go do generowania URL w szablonie itp.
Jednak router nie jest ograniczony tylko do tego zastosowania, można go używać w aplikacjach, gdzie w ogóle nie używa się presenterów, dla REST API, itd. Więcej w części Samostatné použití.
Kolekcja tras
Najprzyjemniejszy sposób definiowania postaci adresów URL w aplikacji oferuje klasa Nette\Application\Routers\RouteList. Definicja składa się z listy tzw. tras (routes), czyli masek adresów URL i przypisanych do nich presenterów i akcji za pomocą prostego API. Tras nie musimy w żaden sposób nazywać.
$router = new Nette\Application\Routers\RouteList;
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('article/<id>', 'Article:view');
// ...
Przykład mówi, że jeśli w przeglądarce otworzymy https://domain.com/rss.xml
, wyświetli się presenter
Feed
z akcją rss
, jeśli https://domain.com/article/12
, wyświetli się presenter
Article
z akcją view
itd. W przypadku nieznalezienia odpowiedniej trasy Nette Application reaguje
wyrzuceniem wyjątku BadRequestException, który
użytkownikowi wyświetli się jako strona błędu 404 Not Found.
Kolejność tras
Absolutnie kluczowa jest kolejność, w jakiej są wymienione poszczególne trasy, ponieważ są one ewaluowane kolejno od góry do dołu. Obowiązuje zasada, że trasy deklarujemy od szczegółowych do ogólnych:
// ŹLE: 'rss.xml' przechwyci pierwsza trasa i rozumie ten ciąg jako <slug>
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');
// DOBRZE
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('<slug>', 'Article:view');
Trasy są ewaluowane od góry do dołu również przy generowaniu linków:
// ŹLE: link do 'Feed:rss' wygeneruje jako 'admin/feed/rss'
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');
// DOBRZE
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
Nie będziemy przed Tobą ukrywać, że prawidłowe zestawienie tras wymaga pewnej wprawy. Zanim ją opanujesz, użytecznym pomocnikiem będzie panel routingu.
Maska i parametry
Maska opisuje ścieżkę względną od katalogu głównego strony internetowej. Najprostszą maską jest statyczny URL:
$router->addRoute('products', 'Products:default');
Często maski zawierają tzw. parametry. Są one podane w nawiasach ostrych (np. <year>
) i są
przekazywane do docelowego presentera, na przykład do metody renderShow(int $year)
lub do trwałego parametru
$year
:
$router->addRoute('chronicle/<year>', 'History:show');
Przykład mówi, że jeśli w przeglądarce otworzymy https://example.com/chronicle/2020
, wyświetli się
presenter History
z akcją show
i parametrem year: 2020
.
Parametrom możemy określić wartość domyślną bezpośrednio w masce i tym samym stają się one opcjonalne:
$router->addRoute('chronicle/<year=2020>', 'History:show');
Trasa będzie teraz akceptować również URL https://example.com/chronicle/
, które ponownie wyświetli
History:show
z parametrem year: 2020
.
Parametrem może być oczywiście również nazwa presentera i akcji. Na przykład tak:
$router->addRoute('<presenter>/<action>', 'Home:default');
Podana trasa akceptuje np. URL w postaci /article/edit
lub także /catalog/list
i rozumie je jako
presentery i akcje Article:edit
i Catalog:list
.
Jednocześnie nadaje parametrom presenter
i action
wartości domyślne Home
i
default
, a zatem są one również opcjonalne. Tak więc trasa akceptuje również URL w postaci
/article
i rozumie go jako Article:default
. Lub odwrotnie, link do Product:default
wygeneruje ścieżkę /product
, link do domyślnego Home:default
ścieżkę /
.
Maska może opisywać nie tylko ścieżkę względną od katalogu głównego strony internetowej, ale także ścieżkę absolutną, jeśli zaczyna się od ukośnika, lub nawet cały absolutny URL, jeśli zaczyna się od dwóch ukośników:
// względnie do document root
$router->addRoute('<presenter>/<action>', /* ... */);
// ścieżka absolutna (względna do domeny)
$router->addRoute('/<presenter>/<action>', /* ... */);
// absolutny URL włącznie z domeną (względny do schematu)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);
// absolutny URL włącznie ze schematem
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);
Wyrażenia walidacyjne
Dla każdego parametru można ustalić warunek walidacyjny za pomocą wyrażenia regularnego. Na przykład dla parametru
id
określimy, że może przyjmować tylko cyfry za pomocą wyrażenia regularnego \d+
:
$router->addRoute('<presenter>/<action>[/<id \d+>]', /* ... */);
Domyślnym wyrażeniem regularnym dla wszystkich parametrów jest [^/]+
, tj. wszystko oprócz ukośnika. Jeśli
parametr ma akceptować również ukośniki, podamy wyrażenie .+
:
// akceptuje https://example.com/a/b/c, path będzie 'a/b/c'
$router->addRoute('<path .+>', /* ... */);
Sekwencje opcjonalne
W masce można oznaczać opcjonalne części za pomocą nawiasów kwadratowych. Opcjonalna może być dowolna część maski, mogą się w niej znajdować również parametry:
$router->addRoute('[<lang [a-z]{2}>/]<name>', /* ... */);
// Akceptuje ścieżki:
// /cs/download => lang => cs, name => download
// /download => lang => null, name => download
Gdy parametr jest częścią sekwencji opcjonalnej, staje się oczywiście również opcjonalny. Jeśli nie ma podanej wartości domyślnej, będzie miał wartość null.
Opcjonalne części mogą być również w domenie:
$router->addRoute('//[<lang=en>.]example.com/<presenter>/<action>', /* ... */);
Sekwencje można dowolnie zagnieżdżać i kombinować:
$router->addRoute(
'[<lang [a-z]{2}>[-<sublang>]/]<name>[/page-<page=0>]',
'Home:default',
);
// Akceptuje ścieżki:
// /cs/hello
// /en-us/hello
// /hello
// /hello/page-12
Przy generowaniu URL dąży się do najkrótszej warianty, więc wszystko, co można pominąć, jest pomijane. Dlatego na
przykład trasa index[.html]
generuje ścieżkę /index
. Odwrócić zachowanie można przez podanie
wykrzyknika za lewym nawiasem kwadratowym:
// akceptuje /hello i /hello.html, generuje /hello
$router->addRoute('<name>[.html]', /* ... */);
// akceptuje /hello i /hello.html, generuje /hello.html
$router->addRoute('<name>[!.html]', /* ... */);
Parametry opcjonalne (tj. parametry mające wartość domyślną) bez nawiasów kwadratowych zachowują się w zasadzie tak, jakby były ujęte w nawiasy w następujący sposób:
$router->addRoute('<presenter=Home>/<action=default>/<id=>', /* ... */);
// odpowiada temu:
$router->addRoute('[<presenter=Home>/[<action=default>/[<id>]]]', /* ... */);
Jeśli chcielibyśmy wpłynąć na zachowanie końcowego ukośnika, aby np. zamiast /home/
generowało się tylko
/home
, można to osiągnąć w ten sposób:
$router->addRoute('[<presenter=Home>[/<action=default>[/<id>]]]', /* ... */);
Symbole wieloznaczne
W masce ścieżki absolutnej możemy użyć następujących symboli wieloznacznych i uniknąć w ten sposób np. konieczności zapisywania w masce domeny, która może się różnić w środowisku deweloperskim i produkcyjnym:
%tld%
= top level domain, np.com
luborg
%sld%
= second level domain, np.example
%domain%
= domena bez subdomen, np.example.com
%host%
= cały host, np.www.example.com
%basePath%
= ścieżka do katalogu głównego
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action', /* ... */);
Zapis rozszerzony
Cel trasy, zazwyczaj zapisywany w postaci Presenter:action
, może być również zapisany za pomocą tablicy,
która definiuje poszczególne parametry i ich wartości domyślne:
$router->addRoute('<presenter>/<action>[/<id \d+>]', [
'presenter' => 'Home',
'action' => 'default',
]);
Dla bardziej szczegółowej specyfikacji można użyć jeszcze bardziej rozszerzonej formy, gdzie oprócz wartości domyślnych
możemy ustawić również inne właściwości parametrów, takie jak na przykład walidacyjne wyrażenie regularne (zobacz
parametr id
):
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>[/<id>]', [
'presenter' => [
Route::Value => 'Home',
],
'action' => [
Route::Value => 'default',
],
'id' => [
Route::Pattern => '\d+',
],
]);
Ważne jest zauważenie, że jeśli parametry zdefiniowane w tablicy nie są wymienione w masce ścieżki, ich wartości nie można zmienić, nawet za pomocą parametrów query podanych za znakiem zapytania w URL.
Filtry i tłumaczenia
Kody źródłowe aplikacji piszemy w języku angielskim, ale jeśli strona ma mieć polskie URL, to proste routowanie typu:
$router->addRoute('<presenter>/<action>', 'Home:default');
będzie generować angielskie URL, takie jak /product/123
lub /cart
. Jeśli chcemy mieć presentery
i akcje w URL reprezentowane polskimi słowami (np. /produkt/123
lub /koszyk
), możemy wykorzystać
słownik tłumaczeń. Do jego zapisu potrzebujemy już “bardziej gadatliwej” warianty drugiego parametru:
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>', [
'presenter' => [
Route::Value => 'Home',
Route::FilterTable => [
// ciąg w URL => presenter
'produkt' => 'Product',
'koszyk' => 'Cart',
'katalog' => 'Catalog',
],
],
'action' => [
Route::Value => 'default',
Route::FilterTable => [
'lista' => 'list',
],
],
]);
Wiele kluczy słownika tłumaczeń może prowadzić do tego samego presentera. W ten sposób tworzy się dla niego różne aliasy. Za wariant kanoniczny (czyli ten, który będzie w wygenerowanym URL) uważa się ostatni klucz.
Tabelę tłumaczeń można w ten sposób użyć dla dowolnego parametru. Przy czym jeśli tłumaczenie nie istnieje, bierze
się pierwotną wartość. To zachowanie możemy zmienić dodając Route::FilterStrict => true
i trasa wtedy
odrzuci URL, jeśli wartość nie jest w słowniku.
Oprócz słownika tłumaczeń w postaci tablicy można zastosować również własne funkcje tłumaczące.
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,
]);
Funkcja Route::FilterIn
konwertuje między parametrem w URL a ciągiem, który następnie jest przekazywany do
presentera, funkcja FilterOut
zapewnia konwersję w przeciwnym kierunku.
Parametry presenter
, action
i module
już mają predefiniowane filtry, które
konwertują między stylem PascalCase resp. camelCase a kebab-case używanym w URL. Wartość domyślna parametrów zapisuje się
już w przekształconej postaci, więc na przykład w przypadku presentera piszemy <presenter=ProductEdit>
, a
nie <presenter=product-edit>
.
Filtry ogólne
Oprócz filtrów przeznaczonych dla konkretnych parametrów możemy zdefiniować również filtry ogólne, które otrzymają
tablicę asocjacyjną wszystkich parametrów, które mogą dowolnie modyfikować, a następnie je zwrócą. Filtry ogólne
definiujemy pod kluczem null
.
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 { /* ... */ },
],
]);
Filtry ogólne dają możliwość modyfikacji zachowania trasy w absolutnie dowolny sposób. Możemy je użyć na przykład do
modyfikacji parametrów na podstawie innych parametrów. Na przykład tłumaczenie <presenter>
i
<action>
na podstawie aktualnej wartości parametru <lang>
.
Jeśli parametr ma zdefiniowany własny filtr i jednocześnie istnieje filtr ogólny, wykonuje się własny
FilterIn
przed ogólnym i odwrotnie ogólny FilterOut
przed własnym. Zatem wewnątrz filtra ogólnego
wartości parametrów presenter
resp. action
są zapisane w stylu PascalCase resp. camelCase.
Jednokierunkowe OneWay
Trasy jednokierunkowe używa się do zachowania funkcjonalności starych URL, których aplikacja już nie generuje, ale nadal
akceptuje. Oznaczamy je flagą OneWay
:
// stare URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', $router::ONE_WAY);
// nowe URL /product/123
$router->addRoute('product/<id>', 'Product:detail');
Przy dostępie do starego URL presenter automatycznie przekierowuje na nowy URL, dzięki czemu wyszukiwarki nie zaindeksują tych stron dwukrotnie (zobacz SEO a kanonizace).
Dynamiczne routowanie z callbackami
Dynamiczne routowanie z callbackami pozwala przypisać trasom bezpośrednio funkcje (callbacki), które zostaną wykonane, gdy dana ścieżka zostanie odwiedzona. Ta elastyczna funkcjonalność pozwala szybko i efektywnie tworzyć różne punkty końcowe (endpoints) dla Twojej aplikacji:
$router->addRoute('test', function () {
echo 'jesteś pod adresem /test';
});
Możesz również zdefiniować w masce parametry, które zostaną automatycznie przekazane do Twojego callbacku:
$router->addRoute('<lang cs|en>', function (string $lang) {
echo match ($lang) {
'cs' => 'Witaj na czeskiej wersji naszej strony!',
'en' => 'Welcome to the English version of our website!',
};
});
Moduły
Jeśli mamy więcej tras, które należą do wspólnego modułu, wykorzystamy
withModule()
:
$router = new RouteList;
$router->withModule('Forum') // następujące trasy są częścią modułu Forum
->addRoute('rss', 'Feed:rss') // presenter będzie Forum:Feed
->addRoute('<presenter>/<action>')
->withModule('Admin') // następujące trasy są częścią modułu Forum:Admin
->addRoute('sign:in', 'Sign:in');
Alternatywą jest użycie parametru module
:
// URL manage/dashboard/default mapuje się na presenter Admin:Dashboard
$router->addRoute('manage/<presenter>/<action>', [
'module' => 'Admin',
]);
Subdomeny
Kolekcje tras możemy dzielić według subdomen:
$router = new RouteList;
$router->withDomain('example.com')
->addRoute('rss', 'Feed:rss')
->addRoute('<presenter>/<action>');
W nazwie domeny można użyć również Zástupné znaky:
$router = new RouteList;
$router->withDomain('example.%tld%')
// ...
Prefiks ścieżki
Kolekcje tras możemy dzielić według ścieżki w URL:
$router = new RouteList;
$router->withPath('eshop')
->addRoute('rss', 'Feed:rss') // łapie URL /eshop/rss
->addRoute('<presenter>/<action>'); // łapie URL /eshop/<presenter>/<action>
Kombinacje
Powyższe podziały możemy wzajemnie kombinować:
$router = (new RouteList)
->withDomain('admin.example.com')
->withModule('Admin')
->addRoute(/* ... */)
->addRoute(/* ... */)
->end()
->withModule('Images')
->addRoute(/* ... */)
->end()
->end()
->withDomain('example.com')
->withPath('export')
->addRoute(/* ... */)
// ...
Parametry Query
Maski mogą również zawierać parametry query (parametry za znakiem zapytania w URL). Nie można im zdefiniować wyrażenia walidacyjnego, ale można zmienić nazwę, pod którą zostaną przekazane do presentera:
// parametr query 'cat' chcemy w aplikacji użyć pod nazwą 'categoryId'
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);
Parametry Foo
Teraz już idziemy głębiej. Parametry Foo to w zasadzie nienazwane parametry, które umożliwiają dopasowanie wyrażenia
regularnego. Przykładem jest trasa akceptująca /index
, /index.html
, /index.htm
i
/index.php
:
$router->addRoute('index<? \.html?|\.php|>', /* ... */);
Można również jawnie zdefiniować ciąg, który będzie użyty przy generowaniu URL. Ciąg musi być umieszczony
bezpośrednio za znakiem zapytania. Następująca trasa jest podobna do poprzedniej, ale generuje /index.html
zamiast
/index
, ponieważ ciąg .html
jest ustawiony jako wartość generująca:
$router->addRoute('index<?.html \.html?|\.php|>', /* ... */);
Włączenie do aplikacji
Aby włączyć utworzony router do aplikacji, musimy o nim powiedzieć kontenerowi DI. Najłatwiejszą drogą jest
przygotowanie fabryki, która wyprodukuje obiekt routera, i poinformowanie w konfiguracji kontenera, że ma jej użyć.
Powiedzmy, że w tym celu napiszemy metodę App\Core\RouterFactory::createRouter()
:
namespace App\Core;
use Nette\Application\Routers\RouteList;
class RouterFactory
{
public static function createRouter(): RouteList
{
$router = new RouteList;
$router->addRoute(/* ... */);
return $router;
}
}
Do konfiguracji następnie zapiszemy:
services:
- App\Core\RouterFactory::createRouter
Wszelkie zależności, na przykład od bazy danych itp., zostaną przekazane do metody fabrycznej jako jej parametry za pomocą autowiringu:
public static function createRouter(Nette\Database\Connection $db): RouteList
{
// ...
}
SimpleRouter
Znacznie prostszym routerem niż kolekcja tras jest SimpleRouter. Użyjemy go wtedy,
gdy nie mamy szczególnych wymagań co do kształtu URL, gdy nie jest dostępny mod_rewrite
(lub jego alternatywy)
lub gdy na razie nie chcemy zajmować się ładnymi URL.
Generuje adresy mniej więcej w tym kształcie:
http://example.com/?presenter=Product&action=detail&id=123
Parametrem konstruktora SimpleRoutera jest domyślny presenter & akcja, na który ma kierować, jeśli otworzymy stronę
bez parametrów, np. http://example.com/
.
// domyślnym presenterem będzie 'Home' a akcja 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');
Zalecamy SimpleRouter bezpośrednio zdefiniować w konfiguracji:
services:
- Nette\Application\Routers\SimpleRouter('Home:default')
SEO i kanonizacja
Framework przyczynia się do SEO (optymalizacji dla wyszukiwarek internetowych) przez zapobieganie duplikacji treści pod
różnymi URL. Jeśli do określonego celu prowadzi więcej adresów, np. /index
i /index.html
,
framework pierwszy z nich określa jako podstawowy (kanoniczny) i pozostałe na niego przekierowuje za pomocą kodu HTTP
301. Dzięki temu wyszukiwarki nie indeksują stron dwukrotnie i nie rozdrabniają ich page rank.
Ten proces nazywa się kanonizacją. Kanonicznym URL jest ten, który generuje router, tj. pierwsza pasująca trasa w kolekcji bez flagi OneWay. Dlatego w kolekcji podajemy podstawowe trasy jako pierwsze.
Kanonizację przeprowadza presenter, więcej w rozdziale kanonizacja.
HTTPS
Aby móc używać protokołu HTTPS, konieczne jest jego włączenie na hostingu i prawidłowe skonfigurowanie serwera.
Przekierowanie całej strony na HTTPS należy ustawić na poziomie serwera, na przykład za pomocą pliku .htaccess w katalogu głównym naszej aplikacji, i to z kodem HTTP 301. Ustawienie może się różnić w zależności od hostingu i wygląda mniej więcej tak:
<IfModule mod_rewrite.c>
RewriteEngine On
...
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
...
</IfModule>
Router generuje URL z tym samym protokołem, z jakim została załadowana strona, więc nic więcej nie trzeba ustawiać.
Jeśli jednak wyjątkowo potrzebujemy, aby różne trasy działały pod różnymi protokołami, podamy go w masce trasy:
// Będzie generować adres z HTTP
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);
// Będzie generować adres z HTTPS
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);
Debugowanie routera
Panel routingu wyświetlający się w Tracy Bar jest użytecznym pomocnikiem, który wyświetla listę tras oraz parametrów, które router uzyskał z URL.
Zielony pasek z symbolem ✓ reprezentuje trasę, która przetworzyła aktualny URL, niebieskim kolorem i symbolem ≈ są oznaczone trasy, które również przetworzyłyby URL, gdyby zielona ich nie wyprzedziła. Dalej widzimy aktualny presenter & akcję.

Jednocześnie jeśli dojdzie do nieoczekiwanego przekierowania z powodu kanonizacji, warto spojrzeć do panelu w pasku redirect, gdzie dowiesz się, jak router pierwotnie zrozumiał URL i dlaczego przekierował.
Podczas debugowania routera zalecamy otwarcie w przeglądarce Developer Tools (Ctrl+Shift+I lub Cmd+Option+I) i w panelu Network wyłączenie cache, aby nie zapisywały się w niej przekierowania.
Wydajność
Liczba tras ma wpływ na szybkość routera. Ich liczba zdecydowanie nie powinna przekraczać kilkudziesięciu. Jeśli Twoja strona ma zbyt skomplikowaną strukturę URL, możesz napisać na miarę Vlastní router.
Jeśli router nie ma żadnych zależności, na przykład od bazy danych, a jego fabryka nie przyjmuje żadnych argumentów, możemy jego skompilowaną postać zserializować bezpośrednio do kontenera DI i tym samym nieznacznie przyspieszyć aplikację.
routing:
cache: true
Własny router
Poniższe linijki są przeznaczone dla bardzo zaawansowanych użytkowników. Możesz stworzyć własny router i całkowicie naturalnie włączyć go do kolekcji tras. Router jest implementacją interfejsu Nette\Routing\Router z dwiema metodami:
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
{
// ...
}
}
Metoda match
przetwarza aktualne żądanie $httpRequest,
z którego można uzyskać nie tylko URL, ale i nagłówki itp., do tablicy zawierającej nazwę presentera i jego parametry.
Jeśli nie potrafi przetworzyć żądania, zwraca null. Przy przetwarzaniu żądania musimy zwrócić co najmniej presenter
i akcję. Nazwa presentera jest pełna i zawiera również ewentualne moduły:
[
'presenter' => 'Front:Home',
'action' => 'default',
]
Metoda constructUrl
odwrotnie, składa z tablicy parametrów wynikowy absolutny URL. Do tego może wykorzystać
informacje z parametru $refUrl
, który
jest aktualnym URL.
Do kolekcji tras dodasz go za pomocą add()
:
$router = new Nette\Application\Routers\RouteList;
$router->add($myRouter);
$router->addRoute(/* ... */);
// ...
Samostatné použití
Samodzielnym użyciem rozumiemy wykorzystanie możliwości routera w aplikacji, która nie wykorzystuje Nette Application i presenterów. Dotyczy go prawie wszystko, co pokazaliśmy w tym rozdziale, z tymi różnicami:
- dla kolekcji tras używamy klasy Nette\Routing\RouteList
- jako simple router klasy Nette\Routing\SimpleRouter
- ponieważ nie istnieje para
Presenter:action
, używamy Zápis rozšířený
Więc ponownie tworzymy metodę, która nam zbuduje router, np.:
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;
}
}
Jeśli używasz kontenera DI, co zalecamy, ponownie dodamy metodę do konfiguracji, a następnie router wraz z żądaniem HTTP uzyskamy z kontenera:
$router = $container->getByType(Nette\Routing\Router::class);
$httpRequest = $container->getByType(Nette\Http\IRequest::class);
Albo obiekty bezpośrednio wyprodukujemy:
$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
Teraz już pozostaje puścić router do pracy:
$params = $router->match($httpRequest);
if ($params === null) {
// nie znaleziono pasującej trasy, wysyłamy błąd 404
exit;
}
// przetwarzamy uzyskane parametry
$controller = $params['controller'];
// ...
I odwrotnie użyjemy routera do zbudowania linku:
$params = ['controller' => 'ArticleController', 'id' => 123];
$url = $router->constructUrl($params, $httpRequest->getUrl());