Маршрутизація
Маршрутизатор відповідає за все, що стосується URL-адрес, щоб вам більше не доводилося над ними замислюватися. Ми покажемо:
- як налаштувати маршрутизатор, щоб URL були такими, як ви хочете
- поговоримо про SEO та перенаправлення
- і покажемо, як написати власний маршрутизатор
Більш людські URL (або також cool чи pretty URL) є більш зручними для використання, легше запам'ятовуються та позитивно впливають на SEO. Nette про це думає і повністю йде назустріч розробникам. Ви можете для свого застосунку розробити саме таку структуру URL-адрес, яку захочете. Ви можете її розробити навіть тоді, коли застосунок вже готовий, оскільки це обійдеться без втручань у код чи шаблони. Визначається це елегантним способом в одному єдиному місці, у маршрутизаторі, і таким чином не розкидано у вигляді анотацій у всіх презентерах.
Маршрутизатор у Nette є винятковим тим, що він двосторонній. Він вміє як декодувати URL в HTTP-запиті, так і створювати посилання. Отже, він відіграє ключову роль у Nette Application, оскільки не тільки вирішує, який презентер та дія виконуватимуть поточний запит, але також використовується для генерування URL у шаблоні тощо.
Однак маршрутизатор не обмежений лише цим використанням, ви можете його використовувати в застосунках, де взагалі не використовуються презентери, для REST API тощо. Більше в частині самостійне використання.
Колекція маршрутів
Найприємніший спосіб визначити вигляд URL-адрес у застосунку пропонує клас Nette\Application\Routers\RouteList. Визначення складається зі списку так званих маршрутів, тобто масок URL-адрес та пов'язаних з ними презентерів та дій за допомогою простого API. Маршрути не потрібно якось називати.
$router = new Nette\Application\Routers\RouteList;
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('article/<id>', 'Article:view');
// ...
Приклад говорить, що якщо в браузері відкрити https://domain.com/rss.xml
,
відобразиться презентер Feed
з дією rss
, якщо
https://domain.com/article/12
, відобразиться презентер Article
з дією
view
тощо. У разі не знаходження відповідного маршруту Nette Application
реагує викиданням винятку BadRequestException, який
користувачеві відображається як сторінка помилки 404 Not Found.
Порядок маршрутів
Абсолютно ключовим є порядок, у якому вказані окремі маршрути, оскільки вони оцінюються послідовно зверху вниз. Діє правило, що маршрути декларуємо від специфічних до загальних:
// ПОГАНО: 'rss.xml' перехопить перший маршрут і розуміє цей рядок як <slug>
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');
// ДОБРЕ
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('<slug>', 'Article:view');
Маршрути оцінюються зверху вниз також при генерації посилань:
// ПОГАНО: посилання на 'Feed:rss' згенерує як 'admin/feed/rss'
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');
// ДОБРЕ
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
Ми не будемо приховувати від вас, що правильне складання маршрутів вимагає певної вправності. Перш ніж ви в неї проникнете, вам буде корисним помічником панель маршрутизації.
Маска та параметри
Маска описує відносний шлях від кореневого каталогу веб-сайту. Найпростішою маскою є статичний URL:
$router->addRoute('products', 'Products:default');
Часто маски містять так звані параметри. Вони вказані в кутових
дужках (наприклад, <year>
) і передаються до цільового
презентера, наприклад, методу renderShow(int $year)
або до персистентного
параметра $year
:
$router->addRoute('chronicle/<year>', 'History:show');
Приклад говорить, що якщо в браузері відкрити
https://example.com/chronicle/2020
, відобразиться презентер History
з дією
show
та параметром year: 2020
.
Параметрам можна визначити значення за замовчуванням безпосередньо в масці, і тим самим вони стануть необов'язковими:
$router->addRoute('chronicle/<year=2020>', 'History:show');
Маршрут тепер прийматиме й URL https://example.com/chronicle/
, який знову
відобразить History:show
з параметром year: 2020
.
Параметром може бути, звичайно, й ім'я презентера та дії. Наприклад, так:
$router->addRoute('<presenter>/<action>', 'Home:default');
Зазначений маршрут приймає, наприклад, URL у вигляді /article/edit
або
також /catalog/list
і розуміє їх як презентери та дії Article:edit
та
Catalog:list
.
Водночас він надає параметрам presenter
та action
значення за
замовчуванням Home
та default
, і вони, отже, також є
необов'язковими. Тому маршрут приймає й URL у вигляді /article
і
розуміє його як Article:default
. Або навпаки, посилання на
Product:default
згенерує шлях /product
, посилання на стандартний
Home:default
шлях /
.
Маска може описувати не тільки відносний шлях від кореневого каталогу веб-сайту, але й абсолютний шлях, якщо починається зі слеша, або навіть цілий абсолютний URL, якщо починається з двох слешів:
// відносно до document root
$router->addRoute('<presenter>/<action>', /* ... */);
// абсолютний шлях (відносно до домену)
$router->addRoute('/<presenter>/<action>', /* ... */);
// абсолютний URL включно з доменом (відносно до схеми)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);
// абсолютний URL включно зі схемою
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);
Валідаційні вирази
Для кожного параметра можна встановити умову валідації за допомогою
регулярного виразу.
Наприклад, параметру id
визначимо, що він може набувати лише цифр
за допомогою регулярного виразу \d+
:
$router->addRoute('<presenter>/<action>[/<id \d+>]', /* ... */);
Стандартним регулярним виразом для всіх параметрів є [^/]+
,
тобто все, крім слеша. Якщо параметр має приймати й слеші, вкажемо вираз
.+
:
// приймає https://example.com/a/b/c, path буде 'a/b/c'
$router->addRoute('<path .+>', /* ... */);
Необов'язкові послідовності
У масці можна позначати необов'язкові частини за допомогою квадратних дужок. Необов'язковою може бути будь-яка частина маски, в ній можуть знаходитися й параметри:
$router->addRoute('[<lang [a-z]{2}>/]<name>', /* ... */);
// Приймає шляхи:
// /cs/download => lang => cs, name => download
// /download => lang => null, name => download
Коли параметр є частиною необов'язкової послідовності, він, зрозуміло, також стає необов'язковим. Якщо він не має вказаного значення за замовчуванням, то буде null.
Необов'язкові частини можуть бути й у домені:
$router->addRoute('//[<lang=en>.]example.com/<presenter>/<action>', /* ... */);
Послідовності можна довільно вкладати та комбінувати:
$router->addRoute(
'[<lang [a-z]{2}>[-<sublang>]/]<name>[/page-<page=0>]',
'Home:default',
);
// Приймає шляхи:
// /cs/hello
// /en-us/hello
// /hello
// /hello/page-12
При генерації URL прагнуть до найкоротшого варіанту, тому все, що можна
пропустити, пропускається. Тому, наприклад, маршрут index[.html]
генерує шлях /index
. Змінити поведінку можна, вказавши знак оклику
за лівою квадратною дужкою:
// приймає /hello та /hello.html, генерує /hello
$router->addRoute('<name>[.html]', /* ... */);
// приймає /hello та /hello.html, генерує /hello.html
$router->addRoute('<name>[!.html]', /* ... */);
Необов'язкові параметри (тобто параметри, що мають значення за замовчуванням) без квадратних дужок поводяться, по суті, так, ніби вони були взяті в дужки таким чином:
$router->addRoute('<presenter=Home>/<action=default>/<id=>', /* ... */);
// відповідає цьому:
$router->addRoute('[<presenter=Home>/[<action=default>/[<id>]]]', /* ... */);
Якщо ми хочемо вплинути на поведінку кінцевого слеша, щоб, наприклад,
замість /home/
генерувалося лише /home
, цього можна
досягти так:
$router->addRoute('[<presenter=Home>[/<action=default>[/<id>]]]', /* ... */);
Заступні знаки
У масці абсолютного шляху ми можемо використовувати наступні заступні знаки і уникнути так, наприклад, необхідності записувати в маску домен, який може відрізнятися в середовищі розробки та робочому середовищі:
%tld%
= домен верхнього рівня, наприклад,com
абоorg
%sld%
= домен другого рівня, наприклад,example
%domain%
= домен без субдоменів, наприклад,example.com
%host%
= весь хост, наприклад,www.example.com
%basePath%
= шлях до кореневого каталогу
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action', /* ... */);
Розширений запис
Ціль маршруту, зазвичай записана у вигляді Presenter:action
, може бути
також записана за допомогою масиву, який визначає окремі параметри та
їхні значення за замовчуванням:
$router->addRoute('<presenter>/<action>[/<id \d+>]', [
'presenter' => 'Home',
'action' => 'default',
]);
Для більш детальної специфікації можна використовувати ще більш
розширену форму, де крім значень за замовчуванням ми можемо встановити
й інші властивості параметрів, як-от валідаційний регулярний вираз
(див. параметр id
):
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>[/<id>]', [
'presenter' => [
Route::Value => 'Home',
],
'action' => [
Route::Value => 'default',
],
'id' => [
Route::Pattern => '\d+',
],
]);
Важливо зазначити, що якщо параметри, визначені в масиві, не вказані в масці шляху, їхні значення не можна змінити, навіть за допомогою query-параметрів, зазначених після знака питання в URL.
Фільтри та переклади
Вихідні коди застосунку ми пишемо англійською, але якщо веб-сайт повинен мати українські URL, то просте маршрутування типу:
$router->addRoute('<presenter>/<action>', 'Home:default');
буде генерувати англійські URL, як-от /product/123
або /cart
. Якщо
ми хочемо, щоб презентери та дії в URL були представлені українськими
словами (наприклад, /produkt/123
або /koshyk
), ми можемо
використати перекладацький словник. Для його запису вже потрібен
“багатослівніший” варіант другого параметра:
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>', [
'presenter' => [
Route::Value => 'Home',
Route::FilterTable => [
// рядок в URL => презентер
'produkt' => 'Product',
'koshyk' => 'Cart',
'katalog' => 'Catalog',
],
],
'action' => [
Route::Value => 'default',
Route::FilterTable => [
'spysok' => 'list',
],
],
]);
Кілька ключів перекладацького словника можуть вести на той самий презентер. Тим самим для нього створюються різні псевдоніми. За канонічний варіант (тобто той, який буде у згенерованому URL) вважається останній ключ.
Перекладацьку таблицю можна таким чином використовувати для
будь-якого параметра. При цьому, якщо переклад не існує, береться
початкове значення. Цю поведінку можна змінити, доповнивши
Route::FilterStrict => true
, і маршрут тоді відхилить URL, якщо значення
немає в словнику.
Крім перекладацького словника у вигляді масиву, можна застосувати й власні функції перекладу.
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,
]);
Функція Route::FilterIn
перетворює параметр в URL на рядок, який потім
передається до презентера, функція FilterOut
забезпечує
перетворення у зворотному напрямку.
Параметри presenter
, action
та module
вже мають
передвизначені фільтри, які перетворюють між стилем PascalCase або camelCase та
kebab-case, що використовується в URL. Значення параметрів за замовчуванням
записується вже в трансформованому вигляді, тому, наприклад, у випадку
презентера пишемо <presenter=ProductEdit>
, а не
<presenter=product-edit>
.
Загальні фільтри
Крім фільтрів, призначених для конкретних параметрів, ми можемо
визначити також загальні фільтри, які отримають асоціативний масив
усіх параметрів, які можуть будь-яким чином модифікувати, а потім їх
повернути. Загальні фільтри визначаємо під ключем 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 { /* ... */ },
],
]);
Загальні фільтри дають можливість змінити поведінку маршруту
абсолютно будь-яким способом. Ми можемо їх використовувати, наприклад,
для модифікації параметрів на основі інших параметрів. Наприклад,
переклад <presenter>
та <action>
на основі поточного
значення параметра <lang>
.
Якщо параметр має визначений власний фільтр і одночасно існує
загальний фільтр, виконується власний FilterIn
перед загальним і,
навпаки, загальний FilterOut
перед власним. Тобто всередині
загального фільтра значення параметрів presenter
або action
записані в стилі PascalCase або camelCase.
Односторонні OneWay
Односторонні маршрути використовуються для збереження
функціональності старих URL, які застосунок вже не генерує, але все ще
приймає. Позначимо їх прапорцем OneWay
:
// старий URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', $router::ONE_WAY);
// новий URL /product/123
$router->addRoute('product/<id>', 'Product:detail');
При доступі до старого URL презентер автоматично перенаправляє на новий URL, тому ці сторінки пошукові системи не проіндексують двічі (див. SEO та канонізація).
Динамічна маршрутизація з callback-функціями
Динамічна маршрутизація з callback-функціями дозволяє вам призначати маршрутам безпосередньо функції (callback-функції), які виконуються, коли відвідується відповідний шлях. Ця гнучка функціональність дозволяє швидко та ефективно створювати різні кінцеві точки (endpoints) для вашого застосунку:
$router->addRoute('test', function () {
echo 'ви на адресі /test';
});
Ви також можете визначити в масці параметри, які автоматично передадуться до вашого callback:
$router->addRoute('<lang cs|en>', function (string $lang) {
echo match ($lang) {
'cs' => 'Ласкаво просимо на українську версію нашого сайту!',
'en' => 'Welcome to the English version of our website!',
};
});
Модулі
Якщо у нас є кілька маршрутів, які належать до спільного модуля,
використаємо withModule()
:
$router = new RouteList;
$router->withModule('Forum') // наступні маршрути є частиною модуля Forum
->addRoute('rss', 'Feed:rss') // презентер буде Forum:Feed
->addRoute('<presenter>/<action>')
->withModule('Admin') // наступні маршрути є частиною модуля Forum:Admin
->addRoute('sign:in', 'Sign:in');
Альтернативою є використання параметра module
:
// URL manage/dashboard/default мапується на презентер Admin:Dashboard
$router->addRoute('manage/<presenter>/<action>', [
'module' => 'Admin',
]);
Субдомени
Колекції маршрутів ми можемо розділяти за субдоменами:
$router = new RouteList;
$router->withDomain('example.com')
->addRoute('rss', 'Feed:rss')
->addRoute('<presenter>/<action>');
У назві домену можна використовувати й заступні знаки:
$router = new RouteList;
$router->withDomain('example.%tld%')
// ...
Префікс шляху
Колекції маршрутів ми можемо розділяти за шляхом в URL:
$router = new RouteList;
$router->withPath('eshop')
->addRoute('rss', 'Feed:rss') // ловить URL /eshop/rss
->addRoute('<presenter>/<action>'); // ловить URL /eshop/<presenter>/<action>
Комбінації
Вищезгаданий поділ можна взаємно комбінувати:
$router = (new RouteList)
->withDomain('admin.example.com')
->withModule('Admin')
->addRoute(/* ... */)
->addRoute(/* ... */)
->end()
->withModule('Images')
->addRoute(/* ... */)
->end()
->end()
->withDomain('example.com')
->withPath('export')
->addRoute(/* ... */)
// ...
Query-параметри
Маски можуть також містити query-параметри (параметри після знака питання в URL). Для них не можна визначити валідаційний вираз, але можна змінити назву, під якою вони передаються до презентера:
// query-параметр 'cat' ми хочемо в застосунку використовувати під назвою 'categoryId'
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);
Foo-параметри
Тепер ми заглиблюємося. Foo-параметри — це, по суті, неіменовані
параметри, які дозволяють зіставляти регулярний вираз. Прикладом є
маршрут, що приймає /index
, /index.html
, /index.htm
та
/index.php
:
$router->addRoute('index<? \.html?|\.php|>', /* ... */);
Можна також явно визначити рядок, який буде використаний при
генерації URL. Рядок повинен бути розміщений безпосередньо за знаком
питання. Наступний маршрут схожий на попередній, але генерує
/index.html
замість /index
, оскільки рядок .html
встановлено
як значення для генерації:
$router->addRoute('index<?.html \.html?|\.php|>', /* ... */);
Включення в застосунок
Щоб створений маршрутизатор підключити до застосунку, ми повинні про
нього повідомити DI-контейнер. Найпростіший шлях — підготувати
фабрику, яка створить об'єкт маршрутизатора, і повідомити в
конфігурації контейнера, що її потрібно використовувати. Припустимо,
що для цієї мети ми напишемо метод 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;
}
}
До конфігурації потім запишемо:
services:
- App\Core\RouterFactory::createRouter
Будь-які залежності, наприклад, від бази даних тощо, передаються фабричному методу як його параметри за допомогою autowiring:
public static function createRouter(Nette\Database\Connection $db): RouteList
{
// ...
}
SimpleRouter
Набагато простішим маршрутизатором, ніж колекція маршрутів, є SimpleRouter. Ми
використовуємо його тоді, коли не маємо особливих вимог до форми URL,
якщо недоступний mod_rewrite
(або його альтернативи) або якщо поки що
не хочемо займатися гарними URL.
Генерує адреси приблизно в такому вигляді:
http://example.com/?presenter=Product&action=detail&id=123
Параметром конструктора SimpleRouter є стандартний презентер та дія, на
який слід спрямовувати, якщо відкрити сторінку без параметрів,
наприклад, http://example.com/
.
// стандартним презентером буде 'Home' та дія 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');
Рекомендуємо SimpleRouter безпосередньо визначати в конфігурації:
services:
- Nette\Application\Routers\SimpleRouter('Home:default')
SEO та канонізація
Фреймворк сприяє SEO (оптимізації знаходження в Інтернеті),
запобігаючи дублюванню контенту на різних URL. Якщо до певної цілі веде
кілька адрес, наприклад, /index
та /index.html
, фреймворк першу з
них визначає як первинну (канонічну) і решту на неї перенаправляє за
допомогою HTTP-коду 301. Завдяки цьому пошукові системи не індексують
ваші сторінки двічі і не розмивають їхній page rank.
Цей процес називається канонізацією. Канонічним URL є той, який генерує маршрутизатор, тобто перший відповідний маршрут у колекції без прапорця OneWay. Тому в колекції вказуємо первинні маршрути першими.
Канонізацію виконує презентер, більше в розділі канонізація.
HTTPS
Щоб мати можливість використовувати протокол HTTPS, необхідно його увімкнути на хостингу та правильно налаштувати сервер.
Перенаправлення всього сайту на HTTPS необхідно налаштувати на рівні сервера, наприклад, за допомогою файлу .htaccess у кореневому каталозі нашого застосунку, і це з HTTP-кодом 301. Налаштування може відрізнятися залежно від хостингу і виглядає приблизно так:
<IfModule mod_rewrite.c>
RewriteEngine On
...
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
...
</IfModule>
Маршрутизатор генерує URL з тим самим протоколом, з яким була завантажена сторінка, тому нічого більше налаштовувати не потрібно.
Але якщо винятково потрібно, щоб різні маршрути працювали під різними протоколами, вкажемо його в масці маршруту:
// Буде генерувати адресу з HTTP
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);
// Буде генерувати адресу з HTTPS
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);
Налагодження маршрутизатора
Панель маршрутизації, що відображається в Tracy Bar, є корисним помічником, який показує список маршрутів, а також параметрів, які маршрутизатор отримав з URL.
Зелена смуга із символом ✓ представляє маршрут, який обробив поточний URL, синім кольором та символом ≈ позначені маршрути, які також обробили б URL, якби їх не випередив зелений. Далі бачимо поточний презентер та дію.

Водночас, якщо відбувається неочікуване перенаправлення через канонізацію, корисно подивитися на панель у рядку redirect, де ви дізнаєтеся, як маршрутизатор спочатку зрозумів URL і чому перенаправив.
При налагодженні маршрутизатора рекомендуємо відкрити в браузері Developer Tools (Ctrl+Shift+I або Cmd+Option+I) і в панелі Network вимкнути кеш, щоб у ньому не зберігалися перенаправлення.
Продуктивність
Кількість маршрутів впливає на швидкість маршрутизатора. Їхня кількість точно не повинна перевищувати кілька десятків. Якщо ваш сайт має занадто складну структуру URL, ви можете написати на замовлення власний маршрутизатор.
Якщо маршрутизатор не має жодних залежностей, наприклад, від бази даних, і його фабрика не приймає жодних аргументів, ми можемо його зібрану форму серіалізувати безпосередньо в DI-контейнер і тим самим трохи прискорити застосунок.
routing:
cache: true
Власний маршрутизатор
Наступні рядки призначені для дуже досвідчених користувачів. Ви можете створити власний маршрутизатор і цілком природно включити його до колекції маршрутів. Маршрутизатор є реалізацією інтерфейсу Nette\Routing\Router з двома методами:
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
{
// ...
}
}
Метод match
обробляє поточний запит $httpRequest, з якого можна отримати не тільки URL,
але й заголовки тощо, до масиву, що містить назву презентера та його
параметри. Якщо запит обробити не може, повертає null. При обробці запиту
ми повинні повернути щонайменше презентер та дію. Назва презентера є
повною і містить також можливі модулі:
[
'presenter' => 'Front:Home',
'action' => 'default',
]
Метод constructUrl
навпаки складає з масиву параметрів кінцевий
абсолютний URL. Для цього він може використовувати інформацію з
параметра $refUrl
, що є
поточним URL.
До колекції маршрутів його додасте за допомогою add()
:
$router = new Nette\Application\Routers\RouteList;
$router->add($myRouter);
$router->addRoute(/* ... */);
// ...
Самостійне використання
Самостійним використанням ми маємо на увазі використання можливостей маршрутизатора в застосунку, який не використовує Nette Application та презентери. Для нього діє майже все, що ми показали в цьому розділі, з такими відмінностями:
- для колекцій маршрутів використовуємо клас Nette\Routing\RouteList
- як простий маршрутизатор клас Nette\Routing\SimpleRouter
- оскільки не існує пари
Presenter:action
, використовуємо розширений запис
Отже, знову створимо метод, який нам складе маршрутизатор, наприклад:
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;
}
}
Якщо ви використовуєте DI-контейнер, що ми рекомендуємо, знову додамо метод до конфігурації, а потім маршрутизатор разом з HTTP-запитом отримаємо з контейнера:
$router = $container->getByType(Nette\Routing\Router::class);
$httpRequest = $container->getByType(Nette\Http\IRequest::class);
Або об'єкти безпосередньо створимо:
$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
Тепер залишається лише запустити маршрутизатор до роботи:
$params = $router->match($httpRequest);
if ($params === null) {
// не знайдено відповідного маршруту, надсилаємо помилку 404
exit;
}
// обробляємо отримані параметри
$controller = $params['controller'];
// ...
І навпаки, використаємо маршрутизатор для складання посилання:
$params = ['controller' => 'ArticleController', 'id' => 123];
$url = $router->constructUrl($params, $httpRequest->getUrl());