Routing
Il router si occupa di tutto ciò che riguarda gli indirizzi URL, così non dovete pensarci voi. Vi mostreremo:
- come configurare il router perché gli URL appaiano come volete
- parleremo di SEO e di redirect
- e mostreremo come scrivere un router personalizzato
Gli URL più amichevoli (noti anche come cool o pretty URL) sono più usabili, più facili da ricordare e contribuiscono positivamente alla SEO. Nette ne tiene conto e va pienamente incontro alle esigenze degli sviluppatori. Potete progettare per la vostra applicazione esattamente la struttura di URL che volete. Potete perfino progettarla quando l'applicazione è già finita, perché non richiede alcuna modifica al codice o ai template. Si definisce elegantemente in un unico punto, il router, invece di essere sparsa come annotazioni in tutti i presenter.
Il router in Nette è eccezionale perché è bidirezionale. Sa sia decodificare gli URL delle richieste HTTP sia creare link. Ha quindi un ruolo essenziale in Nette Application, perché non solo decide quale presenter e quale azione eseguiranno la richiesta corrente, ma serve anche a generare gli URL nei template e altrove.
Il router non è però limitato a questo uso: potete usarlo in applicazioni in cui i presenter non vengono usati affatto, per API REST e così via. Maggiori dettagli nella sezione Uso autonomo.
Collezione di route
Il modo più piacevole di definire la struttura degli indirizzi URL di un'applicazione lo offre la classe Nette\Application\Routers\RouteList. La definizione consiste in un elenco di cosiddette route, cioè di maschere di indirizzi URL e dei presenter e delle azioni a esse associati, tramite un'API semplice. Non abbiamo bisogno di dare un nome alle route.
$router = new Nette\Application\Routers\RouteList;
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('article/<id>', 'Article:view');
// ...
L'esempio mostra che, se apriamo nel browser https://domain.com/rss.xml, verrà mostrato il presenter
Feed con l'azione rss. Se apriamo https://domain.com/article/12, verrà mostrato il
presenter Article con l'azione view e così via. Se non viene trovata alcuna route adatta, Nette
Application risponde sollevando una BadRequestException, che viene
mostrata all'utente come pagina di errore 404 Not Found.
Ordine delle route
L'ordine in cui sono elencate le singole route è assolutamente essenziale, perché vengono valutate in sequenza dall'alto verso il basso. La regola è dichiarare le route dalla più specifica alla più generica:
// SBAGLIATO: 'rss.xml' viene catturato dalla prima route, che intende questa stringa come <slug>
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');
// GIUSTO
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('<slug>', 'Article:view');
Anche nella generazione dei link le route vengono valutate dall'alto verso il basso:
// SBAGLIATO: il link a 'Feed:rss' viene generato come 'admin/feed/rss'
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');
// GIUSTO
$router->addRoute('rss.xml', 'Feed:rss');
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
Non vi nasconderemo che comporre correttamente le route richiede una certa abilità. Finché non l'avrete padroneggiata, il pannello del routing vi sarà uno strumento utile.
Maschera e parametri
La maschera descrive il percorso relativo alla directory radice del sito. La maschera più semplice è un URL statico:
$router->addRoute('products', 'Products:default');
Spesso le maschere contengono i cosiddetti parametri. Sono racchiusi tra parentesi angolari (per esempio
<year>) e vengono passati al presenter di destinazione, per esempio al metodo
renderShow(int $year) oppure al parametro persistente $year:
$router->addRoute('chronicle/<year>', 'History:show');
L'esempio mostra che, se apriamo nel browser https://example.com/chronicle/2020, verrà mostrato il presenter
History con l'azione show e il parametro year: 2020.
Possiamo indicare un valore predefinito per i parametri direttamente nella maschera, rendendoli così facoltativi:
$router->addRoute('chronicle/<year=2020>', 'History:show');
La route accetterà ora anche l'URL https://example.com/chronicle/, che mostrerà di nuovo
History:show con il parametro year: 2020.
Naturalmente anche i nomi del presenter e dell'azione possono essere parametri. Per esempio:
$router->addRoute('<presenter>/<action>', 'Home:default');
La route indicata accetta, per esempio, URL nella forma /article/edit o /catalog/list e li interpreta
rispettivamente come i presenter e le azioni Article:edit e Catalog:list.
Allo stesso tempo assegna ai parametri presenter e action i valori predefiniti Home e
default, rendendoli così anch'essi facoltativi. La route accetta quindi anche un URL come /article e lo
interpreta come Article:default. Oppure, al contrario, un link a Product:default genera il percorso
/product e un link al Home:default predefinito genera il percorso /.
La maschera può descrivere non solo il percorso relativo alla directory radice del sito, ma anche un percorso assoluto se inizia con una barra, oppure perfino l'intero URL assoluto se inizia con due barre:
// relativo al document root
$router->addRoute('<presenter>/<action>', /* ... */);
// percorso assoluto (relativo al dominio)
$router->addRoute('/<presenter>/<action>', /* ... */);
// URL assoluto, dominio compreso (relativo allo schema)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);
// URL assoluto, schema compreso
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);
Espressioni di validazione
Per ogni parametro si può indicare una condizione di validazione tramite un'espressione regolare. Per esempio, per il parametro
id indichiamo che può contenere solo cifre, con la regex \d+:
$router->addRoute('<presenter>/<action>[/<id \d+>]', /* ... */);
L'espressione regolare predefinita di tutti i parametri è [^/]+, cioè tutto tranne la barra. Se un parametro
deve accettare anche le barre, impostiamo l'espressione a .+:
// accetta https://example.com/a/b/c, il percorso sarà 'a/b/c'
$router->addRoute('<path .+>', /* ... */);
Sequenze facoltative
Nella maschera le parti facoltative si possono contrassegnare con le parentesi quadre. Qualsiasi parte della maschera può essere facoltativa e può contenere parametri:
$router->addRoute('[<lang [a-z]{2}>/]<name>', /* ... */);
// accetta i percorsi:
// /en/download => lang => en, name => download
// /download => lang => null, name => download
Quando un parametro fa parte di una sequenza facoltativa, diventa naturalmente facoltativo anch'esso. Se non ha un valore predefinito indicato, sarà null.
Le parti facoltative possono trovarsi anche nel dominio:
$router->addRoute('//[<lang=en>.]example.com/<presenter>/<action>', /* ... */);
Le sequenze si possono annidare e combinare a piacere:
$router->addRoute(
'[<lang [a-z]{2}>[-<sublang>]/]<name>[/page-<page=0>]',
'Home:default',
);
// accetta i percorsi:
// /en/hello
// /en-us/hello
// /hello
// /hello/page-12
Nella generazione degli URL si preferisce la variante più breve, quindi tutto ciò che si può omettere viene omesso. Perciò,
per esempio, la route index[.html] genera il percorso /index. Questo comportamento si può invertire
mettendo un punto esclamativo dopo la parentesi quadra sinistra:
// accetta /hello e /hello.html, genera /hello
$router->addRoute('<name>[.html]', /* ... */);
// accetta /hello e /hello.html, genera /hello.html
$router->addRoute('<name>[!.html]', /* ... */);
I parametri facoltativi (cioè i parametri con un valore predefinito) senza parentesi quadre si comportano in sostanza come se fossero racchiusi nel modo seguente:
$router->addRoute('<presenter=Home>/<action=default>/<id=>', /* ... */);
// corrisponde a questo:
$router->addRoute('[<presenter=Home>/[<action=default>/[<id>]]]', /* ... */);
Se vogliamo influire sul comportamento della barra finale, in modo che per esempio venga generato /home invece di
/home/, lo si ottiene così:
$router->addRoute('[<presenter=Home>[/<action=default>[/<id>]]]', /* ... */);
Caratteri jolly
Nella maschera di un URL assoluto possiamo usare i caratteri jolly seguenti per evitare, per esempio, di dover scrivere nella maschera il dominio, che potrebbe differire tra l'ambiente di sviluppo e quello di produzione:
%tld%= dominio di primo livello, per esempiocomoorg%sld%= dominio di secondo livello, per esempioexample%domain%= dominio senza sottodomini, per esempioexample.com%host%= host intero, per esempiowww.example.com%basePath%= percorso della directory radice
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action>', /* ... */);
Notazione avanzata
La destinazione della route, di norma scritta nel formato Presenter:azione, si può scrivere anche con un array
che definisce i singoli parametri e i loro valori predefiniti:
$router->addRoute('<presenter>/<action>[/<id \d+>]', [
'presenter' => 'Home',
'action' => 'default',
]);
Per una specifica più dettagliata si può usare una forma ancora più estesa, in cui, oltre ai valori predefiniti, possiamo
impostare altre proprietà del parametro, come un'espressione regolare di validazione (vedi il parametro id):
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>[/<id>]', [
'presenter' => [
Route::Value => 'Home',
],
'action' => [
Route::Value => 'default',
],
'id' => [
Route::Pattern => '\d+',
],
]);
È importante notare che, se i parametri definiti nell'array non sono elencati nella maschera del percorso, i loro valori non si possono cambiare, nemmeno con i parametri di query indicati dopo il punto interrogativo nell'URL.
Questo è utile per i parametri fissi: dare a una pagina specifica un URL breve e facile da ricordare. Per esempio, per
far sì che /tos apra sempre Article:view con id: 123:
$router->addRoute('tos', [
'presenter' => 'Article',
'action' => 'view',
'id' => 123,
]);
Filtri e traduzioni
Il codice sorgente dell'applicazione lo scriviamo in inglese, ma se il sito deve avere URL in ceco, un routing semplice come:
$router->addRoute('<presenter>/<action>', 'Home:default');
genererà URL inglesi, come /product/123 o /cart. Se vogliamo che nell'URL i presenter e le azioni
siano rappresentati da parole ceche (per esempio /produkt/123 o /kosik), possiamo usare un dizionario di
traduzione. Per scriverlo ci serve già la variante „più prolissa“ del secondo parametro:
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>', [
'presenter' => [
Route::Value => 'Home',
Route::FilterTable => [
// stringa nell'URL => presenter
'produkt' => 'Product',
'kosik' => 'Cart',
'katalog' => 'Catalog',
],
],
'action' => [
Route::Value => 'default',
Route::FilterTable => [
'seznam' => 'list',
],
],
]);
Più chiavi del dizionario di traduzione possono portare allo stesso presenter. Si creano così vari alias per esso. L'ultima chiave è considerata la variante canonica (cioè quella che comparirà nell'URL generato).
La tabella di traduzione si può usare in questo modo per qualsiasi parametro. Se una traduzione non esiste, viene preso il
valore originale. Possiamo cambiare questo comportamento aggiungendo Route::FilterStrict => true: la route
rifiuterà allora l'URL se il valore non è nel dizionario.
Oltre al dizionario di traduzione sotto forma di array, si possono usare funzioni di traduzione personalizzate.
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 funzione Route::FilterIn converte tra il parametro presente nell'URL e la stringa che viene poi passata al
presenter; la funzione FilterOut garantisce la conversione nella direzione opposta.
I parametri presenter, action e module hanno già filtri predefiniti che convertono tra
lo stile PascalCase o camelCase e il kebab-case usato negli URL. Il valore predefinito dei parametri si scrive nella forma in cui
viene passato all'applicazione (PascalCase per presenter e module, camelCase per action), quindi per esempio, nel caso di un
presenter, scriviamo <presenter=ProductEdit>, non <presenter=product-edit>.
Filtri generali
Oltre ai filtri destinati a parametri specifici, possiamo definire anche filtri generali, che ricevono un array associativo di tutti i parametri, che possono modificare a piacere e poi restituire. I filtri generali si definiscono sotto la chiave vuota.
use Nette\Routing\Route;
$router->addRoute('<presenter>/<action>', [
'presenter' => 'Home',
'action' => 'default',
'' => [
Route::FilterIn => function (array $params): array { /* ... */ },
Route::FilterOut => function (array $params): array { /* ... */ },
],
]);
I filtri generali offrono la possibilità di modificare il comportamento della route in assolutamente qualsiasi modo. Possiamo
usarli, per esempio, per modificare parametri in base ad altri parametri. Per esempio per tradurre <presenter>
e <action> in base al valore corrente del parametro <lang>.
Se un parametro ha un proprio filtro definito ed esiste anche un filtro generale, il FilterIn personalizzato viene
eseguito prima di quello generale e, al contrario, il FilterOut generale viene eseguito prima di quello
personalizzato. Dentro il filtro generale i valori dei parametri presenter e action sono quindi scritti
rispettivamente nello stile PascalCase e camelCase.
Vedi URL leggibili con gli slug per un uso pratico di questi filtri: generare URL
adatti alla SEO come /article/123-how-to-bake-bread senza modificare alcun template.
Flag OneWay
Le route a senso unico servono a mantenere il funzionamento dei vecchi URL che l'applicazione non genera più, ma che accetta
ancora. Le contrassegniamo con il flag OneWay:
// vecchio URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', oneWay: true);
// nuovo URL /product/123
$router->addRoute('product/<id>', 'Product:detail');
All'accesso al vecchio URL, il presenter reindirizza automaticamente al nuovo, così i motori di ricerca non indicizzeranno queste pagine due volte (vedi SEO e canonizzazione).
Routing dinamico con le callback
Il routing dinamico con le callback vi permette di assegnare direttamente alle route delle funzioni (callback), che vengono eseguite quando si visita il percorso indicato. Questa funzionalità flessibile vi permette di creare rapidamente ed efficacemente vari endpoint per la vostra applicazione:
$router->addRoute('test', function () {
echo 'Vi trovate all\'indirizzo /test';
});
Nella maschera potete definire anche parametri, che vengono passati automaticamente alla vostra callback:
$router->addRoute('<lang cs|en>', function (string $lang) {
echo match ($lang) {
'cs' => 'Benvenuti nella versione ceca del nostro sito!',
'en' => 'Benvenuti nella versione inglese del nostro sito!',
};
});
Oltre ai parametri della maschera, la callback può ricevere anche servizi dal container DI. Vengono passati in base al tipo
del parametro. Inoltre il parametro $presenter riceve un'istanza di MicroPresenter, che elabora la route:
$router->addRoute('<lang cs|en>', function (string $lang, Nette\Http\Request $httpRequest, NetteModule\MicroPresenter $presenter) {
// ...
});
Moduli
Se abbiamo più route che appartengono a un modulo comune,
usiamo withModule(). Il modulo indicato viene anteposto automaticamente al presenter di ogni route del gruppo e
sparisce del tutto dall'URL:
$router = new RouteList;
$router->withModule('Forum') // le route seguenti fanno parte del modulo Forum
->addRoute('rss', 'Feed:rss') // il presenter sarà Forum:Feed
->addRoute('<presenter>/<action>')
->withModule('Admin') // le route seguenti fanno parte del modulo Forum:Admin
->addRoute('sign:in', 'Sign:in');
Un'alternativa è il parametro module, che allo stesso modo imposta un modulo fisso e lo tiene fuori dall'URL:
// l'URL manage/dashboard/default è mappato sul presenter Admin:Dashboard
$router->addRoute('manage/<presenter>/<action>', [
'module' => 'Admin',
]);
Ogni nome di presenter è completo solo insieme al proprio modulo, per esempio Front:Admin:ProductList. Ogni volta
che un nome completo del genere finisce in un parametro dell'URL, il router lo codifica con due semplici regole: ogni due punti
: (il separatore dei moduli) diventa un punto e ogni confine di parola in un nome PascalCase diventa un
trattino. Così Front:Admin:ProductList compare nell'URL come front.admin.product-list e viene
decodificato allo stesso modo. Ecco perché un'applicazione modulare, senza nessuno degli strumenti visti sopra, produce URL pieni
di punti.
Sia withModule() sia il parametro module lo evitano proprio perché tolgono dal nome del presenter un
prefisso di modulo noto prima che arrivi all'URL: poiché il modulo è una costante, non ha bisogno di essere codificato
affatto.
A volte vogliamo che il modulo stesso vari e compaia nell'URL, quindi ricorriamo direttamente a <module>
nella maschera. Attenzione a un dettaglio essenziale: <module> cattura l'intero percorso del modulo,
cioè tutto ciò che precede l'ultimo due punti del nome del presenter. Per il presenter Shop:Admin:Product questo
significa il modulo Shop:Admin e il presenter Product e, poiché i due punti diventano punti,
otteniamo:
Sottodomini
Le collezioni di route si possono suddividere per sottodomini:
$router = new RouteList;
$router->withDomain('example.com')
->addRoute('rss', 'Feed:rss')
->addRoute('<presenter>/<action>');
Nel nome del dominio si possono usare anche i caratteri jolly:
$router = new RouteList;
$router->withDomain('example.%tld%')
// ...
Prefisso del percorso
Le collezioni di route si possono suddividere in base al percorso nell'URL:
$router = new RouteList;
$router->withPath('eshop')
->addRoute('rss', 'Feed:rss') // corrisponde all'URL /eshop/rss
->addRoute('<presenter>/<action>'); // corrisponde all'URL /eshop/<presenter>/<action>
Combinazioni
I raggruppamenti visti sopra si possono combinare tra loro:
$router = (new RouteList)
->withDomain('admin.example.com')
->withModule('Admin')
->addRoute(/* ... */)
->addRoute(/* ... */)
->end()
->withModule('Images')
->addRoute(/* ... */)
->end()
->end()
->withDomain('example.com')
->withPath('export')
->addRoute(/* ... */)
// ...
Parametri di query
Le maschere possono contenere anche parametri di query (i parametri che seguono il punto interrogativo nell'URL). Per essi non si può definire un'espressione di validazione, ma si può cambiare il nome con cui vengono passati al presenter:
// vogliamo usare il parametro di query 'cat' con il nome 'categoryId' nell'applicazione
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);
Parametri foo
Ora andiamo più a fondo. I parametri foo sono in sostanza parametri senza nome, che permettono di far corrispondere
un'espressione regolare. Un esempio è una route che accetta /index, /index.html,
/index.htm e /index.php:
$router->addRoute('index<? \.html?|\.php|>', /* ... */);
È anche possibile definire esplicitamente la stringa che verrà usata nella generazione dell'URL. La stringa va collocata
subito dopo il punto interrogativo. La route seguente è simile alla precedente, ma genera /index.html invece di
/index, perché come valore di generazione è impostata la stringa .html:
$router->addRoute('index<?.html \.html?|\.php|>', /* ... */);
Integrazione
Per integrare il router creato nell'applicazione dobbiamo comunicarlo al container DI. Il modo più semplice è preparare una
factory che crei l'oggetto router e dire al container, nella configurazione, di usarla. Supponiamo di scrivere a questo scopo il
metodo 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;
}
}
Scriviamo poi nella configurazione:
services:
- App\Core\RouterFactory::createRouter
Le eventuali dipendenze, per esempio da un database, vengono passate al metodo factory come suoi parametri tramite l'autowiring:
public static function createRouter(Nette\Database\Connection $db): RouteList
{
// ...
}
SimpleRouter
Un router molto più semplice della collezione di route è SimpleRouter. Lo usiamo quando non
abbiamo esigenze particolari sul formato degli URL, se mod_rewrite (o le sue alternative) non è disponibile, oppure
se non vogliamo ancora occuparci degli URL leggibili.
Genera indirizzi più o meno in questa forma:
http://example.com/?presenter=Product&action=detail&id=123
Il parametro del costruttore di SimpleRouter è il presenter e l'azione predefiniti, cioè l'azione da eseguire se
apriamo per esempio http://example.com/ senza altri parametri.
// il presenter predefinito sarà 'Home' e l'azione 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');
Consigliamo di definire SimpleRouter direttamente nella configurazione:
services:
- Nette\Application\Routers\SimpleRouter('Home:default')
SEO e canonizzazione
Il framework contribuisce alla SEO (Search Engine Optimization) impedendo l'esistenza di contenuto duplicato su URL diversi. Se
più indirizzi portano a una certa destinazione, per esempio /index e /index.html, il framework designa
il primo come principale (canonico) e vi reindirizza gli altri con il codice HTTP 301. Grazie a questo i motori di ricerca non
indicizzano le pagine due volte e non ne diluiscono il page rank.
Questo processo si chiama canonizzazione. L'URL canonico è quello generato dal router, cioè dalla prima route corrispondente della collezione priva del flag OneWay. Nella collezione elenchiamo quindi prima le route principali.
La canonizzazione viene eseguita dal presenter, maggiori informazioni nel capitolo canonizzazione.
HTTPS
Per usare il protocollo HTTPS è necessario attivarlo sull'hosting e configurare correttamente il server.
Il redirect dell'intero sito verso HTTPS va impostato a livello di server, per esempio con il file .htaccess nella
directory radice della nostra applicazione, con il codice HTTP 301. Le impostazioni possono variare a seconda dell'hosting e
hanno più o meno questo aspetto:
<IfModule mod_rewrite.c>
RewriteEngine On
...
RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
...
</IfModule>
Il router genera gli URL con lo stesso protocollo con cui è stata caricata la pagina, quindi non serve impostare altro.
Se però, in via eccezionale, abbiamo bisogno che route diverse girino con protocolli diversi, lo indichiamo nella maschera della route:
// genererà un indirizzo HTTP
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);
// genererà un indirizzo HTTPS
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);
Debugging del router
Il pannello del routing mostrato nella Tracy Bar è un aiuto utile: mostra l'elenco delle route e anche i parametri che il router ha ricavato dall'URL.
La barra verde con il simbolo ✓ rappresenta la route che ha elaborato l'URL corrente; il colore blu e il simbolo ≈ indicano le route che avrebbero elaborato anch'esse l'URL, se quella verde non le avesse precedute. Vediamo inoltre il presenter e l'azione correnti.

Allo stesso tempo, se avviene un redirect inatteso a causa della canonizzazione, è utile guardare nel pannello la barra redirect, dove potete scoprire come il router aveva interpretato in origine l'URL e perché ha reindirizzato.
Durante il debugging del router consigliamo di aprire gli strumenti per sviluppatori del browser (Ctrl+Shift+I o Cmd+Option+I) e di disattivare la cache nel pannello Network, così che i redirect non vi vengano salvati.
Prestazioni
Il numero di route influisce sulla velocità del router. Il loro numero non dovrebbe assolutamente superare qualche decina. Se il vostro sito ha una struttura di URL troppo complicata, potete scrivere un router personalizzato.
Se il router non ha dipendenze, per esempio da un database, e la sua factory non accetta argomenti, possiamo serializzarne la forma compilata direttamente nel container DI e velocizzare così leggermente l'applicazione.
routing:
cache: true
Router personalizzato
Le righe seguenti sono destinate agli utenti molto avanzati. Potete creare un vostro router e integrarlo naturalmente nella collezione di route. Il router è un'implementazione dell'interfaccia Nette\Routing\Router, con due metodi:
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
{
// ...
}
}
Il metodo match elabora la richiesta corrente $httpRequest, dalla quale si possono
ottenere non solo l'URL ma anche gli header e altro, trasformandola in un array che contiene il nome del presenter e i suoi
parametri. Se non riesce a elaborare la richiesta, restituisce null. Elaborando la richiesta dobbiamo restituire almeno il
presenter; l'azione è facoltativa e, se non indicata, vale default. Il nome del presenter è completo e comprende
gli eventuali moduli:
[
'presenter' => 'Front:Home',
'action' => 'default',
]
Il metodo constructUrl, al contrario, costruisce l'URL assoluto risultante a partire dall'array di parametri. Può
usare le informazioni del parametro $refUrl,
che è l'URL corrente.
Lo aggiungete alla collezione di route con add():
$router = new Nette\Application\Routers\RouteList;
$router->add($myRouter);
$router->addRoute(/* ... */);
// ...
Uso autonomo
Per uso autonomo intendiamo sfruttare le capacità del router in un'applicazione che non usa Nette Application e i presenter. Vale per essa quasi tutto ciò che abbiamo mostrato in questo capitolo, con queste differenze:
- per le collezioni di route usiamo la classe Nette\Routing\RouteList
- come router semplice, la classe Nette\Routing\SimpleRouter
- poiché la coppia
Presenter:azionenon esiste, usiamo la notazione avanzata
Creiamo quindi di nuovo un metodo che ci componga il router, per esempio:
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;
}
}
Se usate un container DI, cosa che consigliamo, aggiungete di nuovo il metodo alla configurazione e ottenete poi dal container il router insieme alla richiesta HTTP:
$router = $container->getByType(Nette\Routing\Router::class);
$httpRequest = $container->getByType(Nette\Http\IRequest::class);
Oppure create direttamente gli oggetti:
$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
Ora non resta che lasciare al router il suo lavoro:
$params = $router->match($httpRequest);
if ($params === null) {
// nessuna route corrispondente trovata, invia un errore 404
exit;
}
// elabora i parametri ottenuti
$controller = $params['controller'];
// ...
E, al contrario, usate il router per costruire un link:
$params = ['controller' => 'ArticleController', 'id' => 123];
$url = $router->constructUrl($params, $httpRequest->getUrl());