Routage

Le routeur s'occupe de tout ce qui concerne les adresses URL, afin que vous n'ayez plus à y penser. Nous allons montrer :

  • comment configurer le routeur pour que les URL soient conformes aux attentes
  • nous parlerons de SEO et de redirection
  • et nous montrerons comment écrire votre propre routeur

Les URL conviviales (aussi appelées cool ou pretty URL) sont plus utilisables, plus faciles à mémoriser et contribuent positivement au SEO. Nette y pense et répond pleinement aux attentes des développeurs. Vous pouvez concevoir pour votre application exactement la structure d'adresses URL que vous souhaitez. Vous pouvez même la concevoir lorsque l'application est déjà terminée, car cela se fait sans intervention dans le code ou les templates. Elle est définie de manière élégante en un seul endroit, dans le routeur, et n'est donc pas dispersée sous forme d'annotations dans tous les presenters.

Le routeur dans Nette est exceptionnel car il est bidirectionnel. Il sait à la fois décoder les URL dans la requête HTTP et créer des liens. Il joue donc un rôle essentiel dans Nette Application, car il décide non seulement quel presenter et quelle action exécuteront la requête actuelle, mais il est également utilisé pour la génération d'URL dans le template, etc.

Cependant, le routeur n'est pas limité à cette seule utilisation, vous pouvez l'utiliser dans des applications où les presenters ne sont pas du tout utilisés, pour des API REST, etc. Plus d'informations dans la section Utilisation autonome.

Collection de routes

La manière la plus agréable de définir la forme des adresses URL dans l'application est offerte par la classe Nette\Application\Routers\RouteList. La définition est constituée d'une liste de routes, c'est-à-dire de masques d'adresses URL et des presenters et actions qui leur sont associés via une API simple. Nous n'avons pas besoin de nommer les routes.

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

L'exemple indique que si nous ouvrons https://domain.com/rss.xml dans le navigateur, le presenter Feed avec l'action rss sera affiché, si https://domain.com/article/12, le presenter Article avec l'action view sera affiché, etc. En cas de non-correspondance de route appropriée, Nette Application réagit en levant une exception BadRequestException, qui s'affiche à l'utilisateur comme une page d'erreur 404 Not Found.

Ordre des routes

L'ordre dans lequel les différentes routes sont listées est absolument crucial, car elles sont évaluées séquentiellement de haut en bas. La règle est que nous déclarons les routes des plus spécifiques aux plus générales :

// MAUVAIS : 'rss.xml' est capturé par la première route et interprète cette chaîne comme <slug>
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');

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

Les routes sont également évaluées de haut en bas lors de la génération de liens :

// MAUVAIS : le lien vers 'Feed:rss' générera 'admin/feed/rss'
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');

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

Nous n'allons pas vous cacher que la composition correcte des routes demande une certaine compétence. Avant de la maîtriser, le panneau de routage vous sera un outil utile.

Masque et paramètres

Le masque décrit le chemin relatif depuis le répertoire racine du site web. Le masque le plus simple est une URL statique :

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

Souvent, les masques contiennent des paramètres. Ils sont indiqués entre chevrons (par ex. <year>) et sont transmis au presenter cible, par exemple à la méthode renderShow(int $year) ou au paramètre persistant $year :

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

L'exemple indique que si nous ouvrons https://example.com/chronicle/2020 dans le navigateur, le presenter History avec l'action show et le paramètre year: 2020 sera affiché.

Nous pouvons spécifier une valeur par défaut pour les paramètres directement dans le masque, ce qui les rend facultatifs :

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

La route acceptera désormais également l'URL https://example.com/chronicle/, qui affichera à nouveau History:show avec le paramètre year: 2020.

Le paramètre peut bien sûr aussi être le nom du presenter et de l'action. Par exemple comme ceci :

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

La route spécifiée accepte par ex. des URL de la forme /article/edit ou aussi /catalog/list et les interprète comme des presenters et actions Article:edit et Catalog:list.

En même temps, elle donne aux paramètres presenter et action les valeurs par défaut Home et default et ils sont donc également facultatifs. Ainsi, la route accepte également une URL de la forme /article et l'interprète comme Article:default. Ou inversement, un lien vers Product:default générera le chemin /product, un lien vers le Home:default par défaut générera le chemin /.

Le masque peut décrire non seulement le chemin relatif depuis le répertoire racine du site web, mais aussi le chemin absolu s'il commence par une barre oblique, ou même une URL absolue entière si elle commence par deux barres obliques :

// relatif au document root
$router->addRoute('<presenter>/<action>', /* ... */);

// chemin absolu (relatif au domaine)
$router->addRoute('/<presenter>/<action>', /* ... */);

// URL absolue incluant le domaine (relative au schéma)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);

// URL absolue incluant le schéma
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);

Expressions de validation

Pour chaque paramètre, une condition de validation peut être établie à l'aide d'une expression régulière. Par exemple, pour le paramètre id, nous spécifions qu'il ne peut contenir que des chiffres à l'aide de l'expression régulière \d+ :

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

L'expression régulière par défaut pour tous les paramètres est [^/]+, c'est-à-dire tout sauf la barre oblique. Si un paramètre doit également accepter des barres obliques, nous spécifions l'expression .+ :

// accepte https://example.com/a/b/c, path sera 'a/b/c'
$router->addRoute('<path .+>', /* ... */);

Séquences facultatives

Dans le masque, les parties facultatives peuvent être marquées à l'aide de crochets. N'importe quelle partie du masque peut être facultative, elle peut également contenir des paramètres :

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

// Accepte les chemins :
//    /cs/download  => lang => cs, name => download
//    /download     => lang => null, name => download

Lorsqu'un paramètre fait partie d'une séquence facultative, il devient bien sûr également facultatif. S'il n'a pas de valeur par défaut spécifiée, il sera null.

Les parties facultatives peuvent également se trouver dans le domaine :

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

Les séquences peuvent être imbriquées et combinées librement :

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

// Accepte les chemins :
// 	/cs/hello
// 	/en-us/hello
// 	/hello
// 	/hello/page-12

Lors de la génération d'URL, on s'efforce d'obtenir la variante la plus courte, donc tout ce qui peut être omis est omis. C'est pourquoi, par exemple, la route index[.html] génère le chemin /index. Il est possible d'inverser ce comportement en ajoutant un point d'exclamation après le crochet gauche :

// accepte /hello et /hello.html, génère /hello
$router->addRoute('<name>[.html]', /* ... */);

// accepte /hello et /hello.html, génère /hello.html
$router->addRoute('<name>[!.html]', /* ... */);

Les paramètres facultatifs (c'est-à-dire les paramètres ayant une valeur par défaut) sans crochets se comportent essentiellement comme s'ils étaient encadrés de la manière suivante :

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

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

Si nous voulions influencer le comportement de la barre oblique finale, pour que par exemple /home soit généré au lieu de /home/, cela peut être réalisé comme suit :

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

Caractères génériques

Dans le masque d'un chemin absolu, nous pouvons utiliser les caractères génériques suivants et éviter ainsi, par exemple, d'avoir à écrire le domaine dans le masque, qui peut différer entre les environnements de développement et de production :

  • %tld% = domaine de premier niveau, par ex. com ou org
  • %sld% = domaine de second niveau, par ex. example
  • %domain% = domaine sans sous-domaines, par ex. example.com
  • %host% = hôte complet, par ex. www.example.com
  • %basePath% = chemin vers le répertoire racine
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action', /* ... */);

Notation étendue

La cible de la route, habituellement écrite sous la forme Presenter:action, peut également être écrite à l'aide d'un tableau qui définit les paramètres individuels et leurs valeurs par défaut :

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

Pour une spécification plus détaillée, une forme encore plus étendue peut être utilisée, où en plus des valeurs par défaut, nous pouvons également définir d'autres propriétés des paramètres, comme par exemple l'expression régulière de validation (voir le paramètre id) :

use Nette\Routing\Route;

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

Il est important de noter que si les paramètres définis dans le tableau ne sont pas spécifiés dans le masque du chemin, leurs valeurs ne peuvent pas être modifiées, même à l'aide des paramètres de requête spécifiés après le point d'interrogation dans l'URL.

Filtres et traductions

Nous écrivons le code source de l'application en anglais, mais si le site web doit avoir des URL en français, alors un routage simple du type :

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

générera des URL en anglais, comme /product/123 ou /cart. Si nous voulons que les presenters et les actions dans l'URL soient représentés par des mots français (par ex. /produit/123 ou /panier), nous pouvons utiliser un dictionnaire de traduction. Pour l'écrire, nous avons besoin de la variante “plus verbeuse” du deuxième paramètre :

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterTable => [
			// chaîne dans l'URL => presenter
			'produit' => 'Product',
			'panier' => 'Cart',
			'catalogue' => 'Catalog',
		],
	],
	'action' => [
		Route::Value => 'default',
		Route::FilterTable => [
			'liste' => 'list',
		],
	],
]);

Plusieurs clés du dictionnaire de traduction peuvent mener au même presenter. Cela crée différents alias pour lui. La variante canonique (c'est-à-dire celle qui sera dans l'URL générée) est considérée comme la dernière clé.

La table de traduction peut être utilisée de cette manière pour n'importe quel paramètre. Si la traduction n'existe pas, la valeur d'origine est prise. Ce comportement peut être modifié en ajoutant Route::FilterStrict => true et la route refusera alors l'URL si la valeur n'est pas dans le dictionnaire.

En plus du dictionnaire de traduction sous forme de tableau, des fonctions de traduction personnalisées peuvent également être utilisées.

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,
]);

La fonction Route::FilterIn convertit entre le paramètre dans l'URL et la chaîne qui est ensuite transmise au presenter, la fonction FilterOut assure la conversion dans le sens inverse.

Les paramètres presenter, action et module ont déjà des filtres prédéfinis qui convertissent entre le style PascalCase ou camelCase et le style kebab-case utilisé dans les URL. La valeur par défaut des paramètres se écrit déjà sous forme transformée, donc par exemple dans le cas du presenter, nous écrivons <presenter=ProductEdit>, et non <presenter=product-edit>.

Filtres généraux

En plus des filtres destinés à des paramètres spécifiques, nous pouvons également définir des filtres généraux qui reçoivent un tableau associatif de tous les paramètres, qu'ils peuvent modifier de n'importe quelle manière, puis les retournent. Nous définissons les filtres généraux sous la clé 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 { /* ... */ },
	],
]);

Les filtres généraux donnent la possibilité de modifier le comportement de la route de manière absolument quelconque. Nous pouvons les utiliser par exemple pour modifier des paramètres en fonction d'autres paramètres. Par exemple, la traduction de <presenter> et <action> en fonction de la valeur actuelle du paramètre <lang>.

Si un paramètre a un filtre personnalisé défini et qu'un filtre général existe également, le FilterIn personnalisé est exécuté avant le général et inversement, le FilterOut général est exécuté avant le personnalisé. Ainsi, à l'intérieur du filtre général, les valeurs des paramètres presenter ou action sont écrites dans le style PascalCase ou camelCase.

Routes unidirectionnelles OneWay

Les routes unidirectionnelles sont utilisées pour maintenir la fonctionnalité des anciennes URL que l'application ne génère plus, mais accepte toujours. Nous les marquons avec l'indicateur OneWay :

// ancienne URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', $router::ONE_WAY);
// nouvelle URL /product/123
$router->addRoute('product/<id>', 'Product:detail');

Lors de l'accès à l'ancienne URL, le presenter redirige automatiquement vers la nouvelle URL, de sorte que les moteurs de recherche n'indexeront pas ces pages deux fois (voir SEO et canonisation).

Routage dynamique avec callbacks

Le routage dynamique avec callbacks vous permet d'assigner directement des fonctions (callbacks) aux routes, qui seront exécutées lorsque le chemin donné sera visité. Cette fonctionnalité flexible vous permet de créer rapidement et efficacement différents points de terminaison (endpoints) pour votre application :

$router->addRoute('test', function () {
	echo 'vous êtes à l\'adresse /test';
});

Vous pouvez également définir des paramètres dans le masque, qui seront automatiquement transmis à votre callback :

$router->addRoute('<lang fr|en>', function (string $lang) {
	echo match ($lang) {
		'fr' => 'Bienvenue sur la version française de notre site !',
		'en' => 'Welcome to the English version of our website!',
	};
});

Modules

Si nous avons plusieurs routes qui appartiennent à un module commun, nous utilisons withModule() :

$router = new RouteList;
$router->withModule('Forum') // les routes suivantes font partie du module Forum
	->addRoute('rss', 'Feed:rss') // le presenter sera Forum:Feed
	->addRoute('<presenter>/<action>')

	->withModule('Admin') // les routes suivantes font partie du module Forum:Admin
		->addRoute('sign:in', 'Sign:in');

Une alternative est d'utiliser le paramètre module :

// L'URL manage/dashboard/default est mappée sur le presenter Admin:Dashboard
$router->addRoute('manage/<presenter>/<action>', [
	'module' => 'Admin',
]);

Sous-domaines

Nous pouvons diviser les collections de routes par sous-domaines :

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

Dans le nom de domaine, on peut également utiliser des Caractères génériques :

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

Préfixe de chemin

Nous pouvons diviser les collections de routes par chemin dans l'URL :

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

Combinaisons

Nous pouvons combiner les divisions ci-dessus :

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

Paramètres de requête

Les masques peuvent également contenir des paramètres de requête (paramètres après le point d'interrogation dans l'URL). On ne peut pas leur définir d'expression de validation, mais on peut changer le nom sous lequel ils sont transmis au presenter :

// le paramètre de requête 'cat' que nous voulons utiliser dans l'application sous le nom 'categoryId'
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);

Paramètres Foo

Maintenant, nous allons plus en profondeur. Les paramètres Foo sont essentiellement des paramètres sans nom qui permettent de faire correspondre une expression régulière. Un exemple est une route acceptant /index, /index.html, /index.htm et /index.php :

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

Il est également possible de définir explicitement la chaîne qui sera utilisée lors de la génération de l'URL. La chaîne doit être placée directement après le point d'interrogation. La route suivante est similaire à la précédente, mais génère /index.html au lieu de /index, car la chaîne .html est définie comme valeur de génération :

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

Intégration dans l'application

Pour intégrer le routeur créé dans l'application, nous devons en informer le conteneur DI. Le moyen le plus simple est de préparer une factory qui fabriquera l'objet routeur et d'indiquer dans la configuration du conteneur qu'elle doit être utilisée. Supposons que nous écrivions à cet effet la méthode 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;
	}
}

Dans la configuration, nous écrirons alors :

services:
	- App\Core\RouterFactory::createRouter

Toutes les dépendances, par exemple envers la base de données, etc., sont transmises à la méthode factory comme ses paramètres via l'autowiring :

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

SimpleRouter

Un routeur beaucoup plus simple que la collection de routes est SimpleRouter. Nous l'utilisons lorsque nous n'avons pas d'exigences particulières sur la forme de l'URL, si mod_rewrite (ou ses alternatives) n'est pas disponible ou si nous ne voulons pas encore nous préoccuper des URL conviviales.

Il génère des adresses à peu près sous cette forme :

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

Le paramètre du constructeur de SimpleRouter est le presenter & action par défaut vers lequel il faut diriger si nous ouvrons la page sans paramètres, par ex. http://example.com/.

// le presenter par défaut sera 'Home' et l'action 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');

Nous recommandons de définir SimpleRouter directement dans la configuration :

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

SEO et canonisation

Le framework contribue au SEO (optimisation pour les moteurs de recherche) en empêchant la duplication de contenu sur différentes URL. Si plusieurs adresses mènent à une certaine cible, par ex. /index et /index.html, le framework détermine la première comme étant la principale (canonique) et redirige les autres vers elle à l'aide du code HTTP 301. Grâce à cela, les moteurs de recherche n'indexeront pas vos pages deux fois et ne dilueront pas leur page rank.

Ce processus est appelé canonisation. L'URL canonique est celle générée par le routeur, c'est-à-dire la première route correspondante dans la collection sans l'indicateur OneWay. C'est pourquoi dans la collection, nous listons les routes primaires en premier.

La canonisation est effectuée par le presenter, plus d'informations dans le chapitre canonisation.

HTTPS

Pour pouvoir utiliser le protocole HTTPS, il est nécessaire de l'activer sur l'hébergement et de configurer correctement le serveur.

La redirection de l'ensemble du site vers HTTPS doit être configurée au niveau du serveur, par exemple à l'aide du fichier .htaccess dans le répertoire racine de notre application, et ce avec le code HTTP 301. La configuration peut varier en fonction de l'hébergement et ressemble à peu près à ceci :

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

Le routeur génère des URL avec le même protocole que celui avec lequel la page a été chargée, il n'y a donc rien de plus à configurer.

Cependant, si exceptionnellement nous avons besoin que différentes routes fonctionnent sous différents protocoles, nous l'indiquons dans le masque de la route :

// Générera une adresse avec HTTP
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);

// Générera une adresse avec HTTPS
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);

Débogage du routeur

Le panneau de routage affiché dans la barre Tracy est un outil utile qui affiche la liste des routes ainsi que les paramètres que le routeur a obtenus de l'URL.

La barre verte avec le symbole ✓ représente la route qui a traité l'URL actuelle, la couleur bleue et le symbole ≈ indiquent les routes qui auraient également traité l'URL si la verte ne les avait pas devancées. Ensuite, nous voyons le presenter & action actuel.

En même temps, si une redirection inattendue se produit en raison de la canonisation, il est utile de regarder le panneau dans la barre redirect, où vous découvrirez comment le routeur a initialement compris l'URL et pourquoi il a redirigé.

Lors du débogage du routeur, nous recommandons d'ouvrir les Outils de développement dans le navigateur (Ctrl+Shift+I ou Cmd+Option+I) et de désactiver le cache dans le panneau Réseau, afin que les redirections n'y soient pas enregistrées.

Performance

Le nombre de routes a une influence sur la vitesse du routeur. Leur nombre ne devrait certainement pas dépasser quelques dizaines. Si votre site a une structure d'URL trop compliquée, vous pouvez écrire un Routeur personnalisé sur mesure.

Si le routeur n'a pas de dépendances, par exemple envers la base de données, et que sa factory n'accepte aucun argument, nous pouvons sérialiser sa forme compilée directement dans le conteneur DI et ainsi accélérer légèrement l'application.

routing:
	cache: true

Routeur personnalisé

Les lignes suivantes sont destinées aux utilisateurs très avancés. Vous pouvez créer votre propre routeur et l'intégrer tout naturellement dans la collection de routes. Le routeur est une implémentation de l'interface Nette\Routing\Router se dvěma 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
	{
		// ...
	}
}

La méthode match traite la requête actuelle $httpRequest, à partir de laquelle on peut obtenir non seulement l'URL, mais aussi les en-têtes, etc., en un tableau contenant le nom du presenter et ses paramètres. Si elle ne peut pas traiter la requête, elle retourne null. Lors du traitement de la requête, nous devons retourner au minimum le presenter et l'action. Le nom du presenter est complet et contient également d'éventuels modules :

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

La méthode constructUrl assemble au contraire l'URL absolue résultante à partir du tableau de paramètres. Pour cela, elle peut utiliser les informations du paramètre $refUrl, qui est l'URL actuelle.

Vous l'ajoutez à la collection de routes à l'aide de add() :

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

Utilisation autonome

Par utilisation autonome, nous entendons l'utilisation des capacités du routeur dans une application qui n'utilise pas Nette Application et les presenters. Presque tout ce que nous avons montré dans ce chapitre s'applique, avec ces différences :

Donc, nous créons à nouveau une méthode qui nous assemblera le routeur, par ex. :

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;
	}
}

Si vous utilisez un conteneur DI, ce que nous recommandons, nous ajoutons à nouveau la méthode à la configuration et obtenons ensuite le routeur avec la requête HTTP du conteneur :

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

Ou nous créons directement les objets :

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

Maintenant, il ne reste plus qu'à laisser le routeur travailler :

$params = $router->match($httpRequest);
if ($params === null) {
	// aucune route correspondante n'a été trouvée, nous envoyons une erreur 404
	exit;
}

// nous traitons les paramètres obtenus
$controller = $params['controller'];
// ...

Et inversement, nous utilisons le routeur pour assembler un lien :

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