Nette Documentation Preview

syntax
Usmerjanje
**********

<div class=perex>

Usmerjevalnik je odgovoren za vse, kar zadeva naslove URL, tako da vam o njih ni treba več razmišljati. Prikazali bomo:

- kako nastaviti usmerjevalnik, da bodo naslovi URL videti tako, kot želite
- nekaj opomb o preusmeritvi SEO
- in pokazali vam bomo, kako lahko napišete svoj usmerjevalnik

</div>


Bolj človeški URL-ji (ali kul ali lepi URL-ji) so bolj uporabni, bolj zapomnljivi in pozitivno prispevajo k SEO. Nette to upošteva in v celoti izpolnjuje želje razvijalcev. Strukturo URL za svojo aplikacijo lahko oblikujete točno tako, kot želite.
Oblikujete jo lahko celo po tem, ko je aplikacija že pripravljena, saj to lahko storite brez kakršnih koli sprememb kode ali predloge. Opredeljena je na eleganten način na [enem samem mestu |#Integration], v usmerjevalniku, in ni razpršena v obliki opomb v vseh predstavitvah.

Usmerjevalnik v programu Nette je poseben, ker je **dvosmeren**, saj lahko tako dekodira URL-je zahtevkov HTTP kot tudi ustvarja povezave. Zato ima v [aplikaciji Nette |how-it-works#Nette Application] pomembno vlogo, saj odloča, kateri predstavnik in dejanje bosta izvedla trenutno zahtevo, uporablja pa se tudi za [ustvarjanje URL-jev |creating-links] v predlogi itd.

Vendar usmerjevalnik ni omejen na to uporabo, uporabite ga lahko v aplikacijah, kjer se predstavniki sploh ne uporabljajo, za API REST itd. Več v razdelku [ločena uporaba |#separated usage].


Zbiranje poti .[#toc-route-collection]
======================================

Najprijetnejši način za določanje naslovov URL v aplikaciji je prek razreda [api:Nette\Application\Routers\RouteList]. Opredelitev je sestavljena iz seznama tako imenovanih poti, tj. mask naslovov URL in z njimi povezanih predstavnikov ter akcij z uporabo preprostega API. Poti nam ni treba poimenovati.

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

Primer pravi, da če v brskalniku odpremo `https://any-domain.com/rss.xml` z akcijo `rss`, če `https://domain.com/article/12` z akcijo `view` itd. Če ne najdemo ustrezne poti, se aplikacija Nette Application odzove tako, da vrže izjemo [BadRequestException |api:Nette\Application\BadRequestException], ki se uporabniku prikaže kot stran z napako 404 Not Found.


Vrstni red poti .[#toc-order-of-routes]
---------------------------------------

Vrstni red, v katerem so poti navedene, je **zelo pomemben**, saj se ocenjujejo zaporedno od zgoraj navzdol. Velja pravilo, da poti prijavljamo **od posebnih do splošnih**:

```php
// Napačno: 'rss.xml' ustreza prvi poti in to napačno razume kot <slug>
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');

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

Tudi pri ustvarjanju povezav se poti ocenjujejo od zgoraj navzdol:

```php
// NAPAKA: ustvari povezavo do 'Feed:rss' kot 'admin/feed/rss'
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');

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

Ne bomo vam skrivali, da je za pravilno oblikovanje seznama potrebno nekaj spretnosti. Dokler se v to ne boste spoprijeli, bo [plošča za usmerjanje |#Debugging Router] uporabno orodje.


Maska in parametri .[#toc-mask-and-parameters]
----------------------------------------------

Maska opisuje relativno pot, ki temelji na korenu spletnega mesta. Najpreprostejša maska je statični URL:

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

Maske pogosto vsebujejo tako imenovane **parametre**. Ti so zaprti v oglatih oklepajih (npr. `<year>`) in se posredujejo ciljnemu predstavniku, na primer metodi `renderShow(int $year)` ali trajnemu parametru `$year`:

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

Primer pravi, da če v brskalniku odpremo `https://any-domain.com/chronicle/2020` in dejanje `show` s parametrom `year: 2020`.

Neposredno v maski lahko določimo privzeto vrednost parametrov in tako postane neobvezna:

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

Pot bo zdaj sprejela naslov URL `https://any-domain.com/chronicle/` s parametrom `year: 2020`.

Seveda sta lahko parametra tudi ime predstavnika in akcija. Na primer:

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

Ta pot sprejme na primer naslov URL v obliki `/article/edit` oz. `/catalog/list` in ga prevede v predstavnike in dejanja `Article:edit` oz. `Catalog:list`.

Parametroma `presenter` in `action` daje tudi privzete vrednosti`Home` in `default`, zato sta neobvezna. Tako pot sprejme tudi naslov URL `/article` in ga prevede kot `Article:default`. Ali obratno, povezava na `Product:default` ustvari pot `/product`, povezava na privzeto `Home:default` pa ustvari pot `/`.

Maska lahko opiše ne le relativno pot na podlagi korena spletnega mesta, temveč tudi absolutno pot, kadar se začne s poševnico, ali celo celoten absolutni naslov URL, kadar se začne z dvema poševnicama:

```php
// relativna pot do korena dokumenta aplikacije
$router->addRoute('<presenter>/<action>', /* ... */);

// absolutna pot, relativna glede na gostiteljsko ime strežnika
$router->addRoute('/<presenter>/<action>', /* ... */);

// absolutni naslov URL, vključno z imenom gostitelja (vendar relativno glede na shemo)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);

// absolutni URL, vključno s shemo
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);
```


Izrazi za potrjevanje .[#toc-validation-expressions]
----------------------------------------------------

Za vsak parameter lahko določite pogoj za preverjanje z uporabo [regularnega izraza |https://www.php.net/manual/en/reference.pcre.pattern.syntax.php]. Na primer, z uporabo regexp `\d+` določimo, da je `id` samo številski parameter:

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

Privzet regularni izraz za vse parametre je `[^/]+`tj. vse razen poševnice. Če naj bi se parameter ujemal tudi s poševnico, nastavimo regularni izraz na `.+`.

```php
// sprejme https://example.com/a/b/c, pot je 'a/b/c'
$router->addRoute('<path .+>', /* ... */);
```


Neobvezna zaporedja .[#toc-optional-sequences]
----------------------------------------------

V oglatih oklepajih so označeni neobvezni deli maske. Vsak del maske je lahko nastavljen kot neobvezen, vključno s tistimi, ki vsebujejo parametre:

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

// Sprejeti naslovi URL:      Parametri:
//  /en/download lang => en, name => download
//  /download lang => null, ime => download
```

Če je parameter del neobveznega zaporedja, seveda postane tudi neobvezen. Če nima privzete vrednosti, bo nič.

Neobvezni odseki so lahko tudi v domeni:

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

Sekvence se lahko poljubno gnezdijo in kombinirajo:

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

// Sprejeti naslovi URL:
//  /en/hello
//  /en-us/hello
//  /hello
//  /hello/stran-12
```

generator URL poskuša ohraniti čim krajši URL, zato je tisto, kar je mogoče izpustiti, izpuščeno. Zato je na primer pot `index[.html]` ustvari pot `/index`. To vedenje lahko obrnete tako, da za levim oglatim oklepajem napišete vzklikalnik:

```php
// sprejme tako /hello kot /hello.html in ustvari /hello
$router->addRoute('<name>[.html]', /* ... */);

// sprejme tako /hello kot /hello.html in ustvari /hello.html
$router->addRoute('<name>[!.html]', /* ... */);
```

Izbirni parametri (tj. parametri s privzeto vrednostjo) brez oglatih oklepajev se obnašajo, kot da bi bili zaviti na ta način:

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

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

Če želite spremeniti način generiranja skrajne desne poševnice, tj. namesto `/home/` dobite `/home`, prilagodite pot na ta način:

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


Zaščitne črke .[#toc-wildcards]
-------------------------------

V maski absolutne poti lahko uporabimo naslednje nadomestne črke, da se na primer izognemo potrebi po zapisu domene v masko, ki se lahko razlikuje v razvojnem in produkcijskem okolju:

- `%tld%` = domena najvišje ravni, npr. `com` ali `org`
- `%sld%` = domena druge ravni, npr. `example`
- `%domain%` = domena brez poddomen, npr. `example.com`
- `%host%` = celoten gostitelj, npr. `www.example.com`
- `%basePath%` = pot do korenskega imenika

```php
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action', /* ... */);
```


Napredni zapis .[#toc-advanced-notation]
----------------------------------------

Cilj poti, ki je običajno zapisan v obliki `Presenter:action`, je mogoče izraziti tudi s poljem, ki določa posamezne parametre in njihove privzete vrednosti:

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

Za podrobnejšo specifikacijo je mogoče uporabiti še bolj razširjeno obliko, v kateri lahko poleg privzetih vrednosti nastavite tudi druge lastnosti parametrov, na primer regularni izraz za preverjanje (glejte parameter `id` ):

```php
use Nette\Routing\Route;

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

Pomembno je opozoriti, da če parametri, opredeljeni v polju, niso vključeni v masko poti, njihovih vrednosti ni mogoče spremeniti, niti z uporabo parametrov poizvedbe, določenih za vprašalnim znakom v naslovu URL.


Filtri in prevodi .[#toc-filters-and-translations]
--------------------------------------------------

Dobra praksa je, da izvorno kodo pišete v angleščini, a kaj, če potrebujete, da je URL vašega spletnega mesta preveden v drug jezik? Preproste poti, kot so npr:

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

bodo ustvarile angleške naslove URL, kot sta `/product/123` ali `/cart`. Če želimo, da so predstavniki in dejanja v naslovu URL prevedeni v nemščino (npr. `/produkt/123` ali `/einkaufswagen`), lahko uporabimo prevajalski slovar. Za njegovo dodajanje že potrebujemo "bolj zgovorno" različico drugega parametra:

```php
use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterTable => [
			// niz v naslovu URL => presenter
			'produkt' => 'Product',
			'einkaufswagen' => 'Cart',
			'katalog' => 'Catalog',
		],
	],
	'action' => [
		Route::Value => 'default',
		Route::FilterTable => [
			'liste' => 'list',
		],
	],
]);
```

Za isti predstavnik lahko uporabimo več ključev slovarja. Z njimi bodo zanj ustvarjeni različni vzdevki. Zadnji ključ velja za kanonično različico (tj. tisto, ki bo v ustvarjenem naslovu URL).

Na ta način je mogoče prevajalno tabelo uporabiti za kateri koli parameter. Če prevod ne obstaja, se vzame izvirna vrednost. To obnašanje lahko spremenimo tako, da dodamo `Route::FilterStrict => true` in pot bo nato zavrnila URL, če vrednosti ni v slovarju.

Poleg slovarja prevodov v obliki polja je mogoče nastaviti tudi lastne prevajalske funkcije:

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

Funkcija `Route::FilterIn` pretvori parameter v naslovu URL v niz, ki se nato posreduje predstavniku, funkcija `FilterOut` pa poskrbi za pretvorbo v nasprotni smeri.

Parametri `presenter`, `action` in `module` imajo že vnaprej določene filtre, ki pretvarjajo med slogom PascalCase oz. camelCase in kebab-case, uporabljenim v naslovu URL. Privzeta vrednost parametrov je že zapisana v pretvorjeni obliki, tako da na primer v primeru predvajalnika zapišemo `<presenter=ProductEdit>` namesto `<presenter=product-edit>`.


Splošni filtri .[#toc-general-filters]
--------------------------------------

Poleg filtrov za določene parametre lahko določite tudi splošne filtre, ki prejmejo asociativno polje vseh parametrov, ki jih lahko poljubno spremenijo in nato vrnejo. Splošni filtri so opredeljeni pod ključem `null`.

```php
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 { /* ... */ },
	],
]);
```

Splošni filtri vam dajejo možnost, da prilagodite obnašanje poti na popolnoma poljuben način. Uporabimo jih lahko na primer za spreminjanje parametrov na podlagi drugih parametrov. Na primer, prevod `<presenter>` in `<action>` na podlagi trenutne vrednosti parametra `<lang>`.

Če ima parameter opredeljen filter po meri in hkrati obstaja splošni filter, se filter po meri `FilterIn` izvede pred splošnim in obratno, splošni `FilterOut` se izvede pred filtrom po meri. Tako so znotraj splošnega filtra vrednosti parametrov `presenter` oz. `action` zapisane v slogu PascalCase oz. camelCase.


Enosmerna zastavica .[#toc-oneway-flag]
---------------------------------------

Enosmerne poti se uporabljajo za ohranjanje funkcionalnosti starih URL-jev, ki jih aplikacija ne ustvarja več, vendar jih še vedno sprejema. Označimo jih z `OneWay`:

```php
// stari URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', $router::ONE_WAY);
// novi URL /product/123
$router->addRoute('product/<id>', 'Product:detail');
```

Pri dostopu do starega naslova URL predstavnik samodejno preusmeri na novi naslov URL, tako da iskalniki teh strani ne indeksirajo dvakrat (glejte [SEO in kanonizacijo |#SEO and canonization]).


Dinamično usmerjanje s povratnimi klici .[#toc-dynamic-routing-with-callbacks]
------------------------------------------------------------------------------

Dinamično usmerjanje s povratnimi klici omogoča neposredno dodeljevanje funkcij (povratnih klicev) na poti, ki se bodo izvedle, ko bo obiskana določena pot. Ta prilagodljiva funkcija vam omogoča hitro in učinkovito ustvarjanje različnih končnih točk za vašo aplikacijo:

```php
$router->addRoute('test', function () {
	echo 'You are at the /test address';
});
```

V maski lahko določite tudi parametre, ki bodo samodejno posredovani povratnemu klicu:

```php
$router->addRoute('<lang cs|en>', function (string $lang) {
	echo match ($lang) {
		'cs' => 'Welcome to the Czech version of our website!',
		'en' => 'Welcome to the English version of our website!',
	};
});
```


Moduli .[#toc-modules]
----------------------

Če imamo več poti, ki pripadajo enemu [modulu |modules], jih lahko z uporabo `withModule()` združimo v skupine:

```php
$router = new RouteList;
$router->withModule('Forum') // naslednji usmerjevalniki so del modula Forum
	->addRoute('rss', 'Feed:rss') // predstavnik je Forum:Feed
	->addRoute('<presenter>/<action>')

	->withModule('Admin') // Naslednji usmerjevalniki so del modula Forum:Admin
		->addRoute('sign:in', 'Sign:in');
```

Druga možnost je uporaba parametra `module`:

```php
// URL upravljam/dashboard/default se prikaže v predstavniku Admin:Dashboard
$router->addRoute('manage/<presenter>/<action>', [
	'module' => 'Admin',
]);
```


Poddomene .[#toc-subdomains]
----------------------------

Zbirke poti lahko združite po poddomenah:

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

V imenu domene lahko uporabite tudi [nadomestne znake |#wildcards]:

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


Predpona poti .[#toc-path-prefix]
---------------------------------

Zbirke poti lahko združite po poti v URL:

```php
$router = new RouteList;
$router->withPath('eshop')
	->addRoute('rss', 'Feed:rss') // ustreza naslovu URL /eshop/rss
	->addRoute('<presenter>/<action>'); // ustreza naslovu URL /eshop/<presenter>/<action>
```


Kombinacije .[#toc-combinations]
--------------------------------

Zgornje načine uporabe je mogoče kombinirati:

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


Parametri poizvedbe .[#toc-query-parameters]
--------------------------------------------

Maske lahko vsebujejo tudi parametre poizvedbe (parametri za vprašalnim znakom v naslovu URL). Ne morejo opredeliti izraza za preverjanje, lahko pa spremenijo ime, pod katerim so posredovani predstavniku:

```php
// uporabite parameter poizvedbe 'cat' kot 'categoryId' v aplikaciji
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);
```


Foo Parametri .[#toc-foo-parameters]
------------------------------------

Zdaj se bomo poglobili. Parametri Foo so pravzaprav neimenovani parametri, ki omogočajo ujemanje z regularnim izrazom. Naslednja pot ustreza `/index`, `/index.html`, `/index.htm` in `/index.php`:

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

Prav tako je mogoče izrecno določiti niz, ki bo uporabljen za generiranje URL-jev. Niz mora biti nameščen neposredno za vprašalnim znakom. Naslednja pot je podobna prejšnji, vendar generira `/index.html` namesto `/index`, ker je niz `.html` nastavljen kot "generirana vrednost".

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


Integracija .[#toc-integration]
===============================

Da bi naš usmerjevalnik povezali z aplikacijo, moramo o tem obvestiti vsebnik DI. Najlažje je pripraviti tovarno, ki bo zgradila objekt usmerjevalnika, in povedati konfiguraciji vsebnika, naj jo uporabi. Recimo, da v ta namen napišemo metodo `App\Core\RouterFactory::createRouter()`:

```php
namespace App\Core;

use Nette\Application\Routers\RouteList;

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

Nato zapišemo v [konfiguracijo |dependency-injection:services]:

```neon
services:
	- App\Core\RouterFactory::createRouter
```

Vse odvisnosti, kot je povezava s podatkovno bazo itd., se metodi tovarne posredujejo kot njeni parametri z uporabo [samodejnega povezovanja |dependency-injection:autowiring]:

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


SimpleRouter .[#toc-simplerouter]
=================================

Precej preprostejši usmerjevalnik od zbirke poti je [SimpleRouter |api:Nette\Application\Routers\SimpleRouter]. Uporabimo ga lahko, kadar ni potrebe po posebni obliki URL, kadar `mod_rewrite` (ali alternative) ni na voljo ali kadar se preprosto še ne želimo ukvarjati z uporabniku prijaznimi URL-ji.

Generira naslove v približno takšni obliki:

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

Parameter konstruktorja `SimpleRouter` je privzeti predstavnik in dejanje, tj. dejanje, ki se izvede, če odpremo npr. `http://example.com/` brez dodatnih parametrov.

```php
// privzeto za predstavitelja 'Home' in akcijo 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');
```

Priporočamo, da se SimpleRouter opredeli neposredno v [konfiguraciji |dependency-injection:services]:

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


SEO in kanonizacija .[#toc-seo-and-canonization]
================================================

Okvir izboljša SEO (optimizacijo za iskalnike), saj preprečuje podvajanje vsebine na različnih URL-jih. Če je več naslovov povezanih z istim ciljem, npr. `/index` in `/index.html`, ogrodje določi prvega kot primarnega (kanoničnega) in nanj preusmeri druge z uporabo kode HTTP 301. Zaradi tega iskalniki strani ne indeksirajo dvakrat in ne porušijo njihovega ranga strani. .

Ta postopek se imenuje kanonizacija. Kanonični URL je tisti, ki ga ustvari usmerjevalnik, tj. prva ustrezna pot v [zbirki |#route-collection] brez oznake OneWay. Zato v zbirki najprej navedemo **primarne poti**.

Kanonizacijo izvede predstavnik, več v poglavju [Kanonizacija |presenters#Canonization].


HTTPS .[#toc-https]
===================

Za uporabo protokola HTTPS ga je treba aktivirati na gostovanju in konfigurirati strežnik.

Preusmeritev celotnega spletnega mesta na protokol HTTPS je treba izvesti na ravni strežnika, na primer z datoteko .htaccess v korenskem imeniku naše aplikacije, s kodo HTTP 301. Nastavitve se lahko razlikujejo glede na gostovanje in so videti nekako takole:

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

Usmerjevalnik ustvari naslov URL z enakim protokolom, kot je bila naložena stran, zato ni treba nastavljati ničesar drugega.

Če pa izjemoma potrebujemo, da se različne poti izvajajo pod različnimi protokoli, bomo to določili v maski poti:

```php
// Ustvari naslov HTTP
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);

// Ustvari naslov HTTPS
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);
```


Razhroščevanje usmerjevalnika .[#toc-debugging-router]
======================================================

Vrstica za usmerjanje, prikazana v [Tracy Bar |tracy:], je uporabno orodje, ki prikazuje seznam poti in tudi parametre, ki jih je usmerjevalnik pridobil iz URL-ja.

Zelena vrstica s simbolom ✓ predstavlja pot, ki je ustrezala trenutnemu naslovu URL, modre vrstice s simboli ≈ pa označujejo poti, ki bi prav tako ustrezale naslovu URL, če jih zelena ne bi prehitela. V nadaljevanju vidimo trenutni predstavnik in dejanje.

[* routing-debugger.webp *]

Hkrati je v primeru nepričakovane preusmeritve zaradi [kanonizacije |#SEO and Canonization] koristno pogledati v vrstico *preusmeritev*, da vidimo, kako je usmerjevalnik prvotno razumel naslov URL in zakaj ga je preusmeril.

.[note]
Pri odpravljanju napak usmerjevalnika je priporočljivo, da v brskalniku odprete programerska orodja (Ctrl+Shift+I ali Cmd+Option+I) in onemogočite predpomnilnik na plošči Omrežje, da se vanj ne shranjujejo preusmeritve.


Uspešnost .[#toc-performance]
=============================

Število poti vpliva na hitrost usmerjevalnika. Njihovo število vsekakor ne sme presegati nekaj deset. Če ima vaše spletno mesto preveč zapleteno strukturo URL, lahko napišete [usmerjevalnik po meri |#custom router].

Če usmerjevalnik nima odvisnosti, na primer od podatkovne zbirke, in njegova tovarna nima argumentov, lahko njegovo sestavljeno obliko serializiramo neposredno v vsebnik DI in tako aplikacijo nekoliko pohitrimo.

```neon
routing:
	cache: true
```


Usmerjevalnik po meri .[#toc-custom-router]
===========================================

Naslednje vrstice so namenjene zelo naprednim uporabnikom. Ustvarite lahko svoj usmerjevalnik in ga seveda dodate v zbirko poti. Usmerjevalnik je implementacija vmesnika [api:Nette\Routing\Router] z dvema metodama:

```php
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` obdela trenutni [zahtevek $httpRequest |http:request], iz katerega je mogoče pridobiti ne le naslov URL, temveč tudi glave itd., v polje, ki vsebuje ime predstavnika in njegove parametre. Če zahteve ne more obdelati, vrne ničlo.
Pri obdelavi zahteve moramo vrniti vsaj predstavnika in akcijo. Ime predstavnika je popolno in vključuje vse module:

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

Metoda `constructUrl`, po drugi strani pa iz niza parametrov ustvari absolutni naslov URL. Uporabi lahko podatke iz parametra `$refUrl`, ki je trenutni naslov URL.

Če želite zbirki poti dodati usmerjevalnik po meri, uporabite `add()`:

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


Ločena uporaba .[#toc-separated-usage]
======================================

Z ločeno uporabo mislimo na uporabo zmožnosti usmerjevalnika v aplikaciji, ki ne uporablja aplikacije Nette in predstavnikov. Zanjo velja skoraj vse, kar smo prikazali v tem poglavju, z naslednjimi razlikami:

- za zbirke poti uporabljamo razred [api:Nette\Routing\RouteList]
- kot preprost razred usmerjevalnika [api:Nette\Routing\SimpleRouter]
- ker ni para `Presenter:action`, uporabljamo [zapis Advanced |#Advanced notation]

Tako bomo ponovno ustvarili metodo, ki bo zgradila usmerjevalnik, na primer:

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

Če uporabljate vsebnik DI, kar priporočamo, ponovno dodajte metodo v konfiguracijo in nato skupaj z zahtevo HTTP iz vsebnika pridobite usmerjevalnik:

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

Ali pa bomo predmete ustvarili neposredno:

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

Zdaj moramo omogočiti delovanje usmerjevalnika:

```php
$params = $router->match($httpRequest);
if ($params === null) {
	// ni bila najdena ustrezna pot, pošljemo napako 404.
	exit;
}

// obdelamo prejete parametre
$controller = $params['controller'];
// ...
```

In obratno, usmerjevalnik bomo uporabili za vzpostavitev povezave:

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


{{composer: nette/router}}

Usmerjanje

Usmerjevalnik je odgovoren za vse, kar zadeva naslove URL, tako da vam o njih ni treba več razmišljati. Prikazali bomo:

  • kako nastaviti usmerjevalnik, da bodo naslovi URL videti tako, kot želite
  • nekaj opomb o preusmeritvi SEO
  • in pokazali vam bomo, kako lahko napišete svoj usmerjevalnik

Bolj človeški URL-ji (ali kul ali lepi URL-ji) so bolj uporabni, bolj zapomnljivi in pozitivno prispevajo k SEO. Nette to upošteva in v celoti izpolnjuje želje razvijalcev. Strukturo URL za svojo aplikacijo lahko oblikujete točno tako, kot želite. Oblikujete jo lahko celo po tem, ko je aplikacija že pripravljena, saj to lahko storite brez kakršnih koli sprememb kode ali predloge. Opredeljena je na eleganten način na enem samem mestu, v usmerjevalniku, in ni razpršena v obliki opomb v vseh predstavitvah.

Usmerjevalnik v programu Nette je poseben, ker je dvosmeren, saj lahko tako dekodira URL-je zahtevkov HTTP kot tudi ustvarja povezave. Zato ima v aplikaciji Nette pomembno vlogo, saj odloča, kateri predstavnik in dejanje bosta izvedla trenutno zahtevo, uporablja pa se tudi za ustvarjanje URL-jev v predlogi itd.

Vendar usmerjevalnik ni omejen na to uporabo, uporabite ga lahko v aplikacijah, kjer se predstavniki sploh ne uporabljajo, za API REST itd. Več v razdelku ločena uporaba.

Zbiranje poti

Najprijetnejši način za določanje naslovov URL v aplikaciji je prek razreda Nette\Application\Routers\RouteList. Opredelitev je sestavljena iz seznama tako imenovanih poti, tj. mask naslovov URL in z njimi povezanih predstavnikov ter akcij z uporabo preprostega API. Poti nam ni treba poimenovati.

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

Primer pravi, da če v brskalniku odpremo https://any-domain.com/rss.xml z akcijo rss, če https://domain.com/article/12 z akcijo view itd. Če ne najdemo ustrezne poti, se aplikacija Nette Application odzove tako, da vrže izjemo BadRequestException, ki se uporabniku prikaže kot stran z napako 404 Not Found.

Vrstni red poti

Vrstni red, v katerem so poti navedene, je zelo pomemben, saj se ocenjujejo zaporedno od zgoraj navzdol. Velja pravilo, da poti prijavljamo od posebnih do splošnih:

// Napačno: 'rss.xml' ustreza prvi poti in to napačno razume kot <slug>
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');

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

Tudi pri ustvarjanju povezav se poti ocenjujejo od zgoraj navzdol:

// NAPAKA: ustvari povezavo do 'Feed:rss' kot 'admin/feed/rss'
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');

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

Ne bomo vam skrivali, da je za pravilno oblikovanje seznama potrebno nekaj spretnosti. Dokler se v to ne boste spoprijeli, bo plošča za usmerjanje uporabno orodje.

Maska in parametri

Maska opisuje relativno pot, ki temelji na korenu spletnega mesta. Najpreprostejša maska je statični URL:

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

Maske pogosto vsebujejo tako imenovane parametre. Ti so zaprti v oglatih oklepajih (npr. <year>) in se posredujejo ciljnemu predstavniku, na primer metodi renderShow(int $year) ali trajnemu parametru $year:

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

Primer pravi, da če v brskalniku odpremo https://any-domain.com/chronicle/2020 in dejanje show s parametrom year: 2020.

Neposredno v maski lahko določimo privzeto vrednost parametrov in tako postane neobvezna:

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

Pot bo zdaj sprejela naslov URL https://any-domain.com/chronicle/ s parametrom year: 2020.

Seveda sta lahko parametra tudi ime predstavnika in akcija. Na primer:

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

Ta pot sprejme na primer naslov URL v obliki /article/edit oz. /catalog/list in ga prevede v predstavnike in dejanja Article:edit oz. Catalog:list.

Parametroma presenter in action daje tudi privzete vrednostiHome in default, zato sta neobvezna. Tako pot sprejme tudi naslov URL /article in ga prevede kot Article:default. Ali obratno, povezava na Product:default ustvari pot /product, povezava na privzeto Home:default pa ustvari pot /.

Maska lahko opiše ne le relativno pot na podlagi korena spletnega mesta, temveč tudi absolutno pot, kadar se začne s poševnico, ali celo celoten absolutni naslov URL, kadar se začne z dvema poševnicama:

// relativna pot do korena dokumenta aplikacije
$router->addRoute('<presenter>/<action>', /* ... */);

// absolutna pot, relativna glede na gostiteljsko ime strežnika
$router->addRoute('/<presenter>/<action>', /* ... */);

// absolutni naslov URL, vključno z imenom gostitelja (vendar relativno glede na shemo)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);

// absolutni URL, vključno s shemo
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);

Izrazi za potrjevanje

Za vsak parameter lahko določite pogoj za preverjanje z uporabo regularnega izraza. Na primer, z uporabo regexp \d+ določimo, da je id samo številski parameter:

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

Privzet regularni izraz za vse parametre je [^/]+tj. vse razen poševnice. Če naj bi se parameter ujemal tudi s poševnico, nastavimo regularni izraz na .+.

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

Neobvezna zaporedja

V oglatih oklepajih so označeni neobvezni deli maske. Vsak del maske je lahko nastavljen kot neobvezen, vključno s tistimi, ki vsebujejo parametre:

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

// Sprejeti naslovi URL:      Parametri:
//  /en/download lang => en, name => download
//  /download lang => null, ime => download

Če je parameter del neobveznega zaporedja, seveda postane tudi neobvezen. Če nima privzete vrednosti, bo nič.

Neobvezni odseki so lahko tudi v domeni:

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

Sekvence se lahko poljubno gnezdijo in kombinirajo:

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

// Sprejeti naslovi URL:
//  /en/hello
//  /en-us/hello
//  /hello
//  /hello/stran-12

generator URL poskuša ohraniti čim krajši URL, zato je tisto, kar je mogoče izpustiti, izpuščeno. Zato je na primer pot index[.html] ustvari pot /index. To vedenje lahko obrnete tako, da za levim oglatim oklepajem napišete vzklikalnik:

// sprejme tako /hello kot /hello.html in ustvari /hello
$router->addRoute('<name>[.html]', /* ... */);

// sprejme tako /hello kot /hello.html in ustvari /hello.html
$router->addRoute('<name>[!.html]', /* ... */);

Izbirni parametri (tj. parametri s privzeto vrednostjo) brez oglatih oklepajev se obnašajo, kot da bi bili zaviti na ta način:

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

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

Če želite spremeniti način generiranja skrajne desne poševnice, tj. namesto /home/ dobite /home, prilagodite pot na ta način:

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

Zaščitne črke

V maski absolutne poti lahko uporabimo naslednje nadomestne črke, da se na primer izognemo potrebi po zapisu domene v masko, ki se lahko razlikuje v razvojnem in produkcijskem okolju:

  • %tld% = domena najvišje ravni, npr. com ali org
  • %sld% = domena druge ravni, npr. example
  • %domain% = domena brez poddomen, npr. example.com
  • %host% = celoten gostitelj, npr. www.example.com
  • %basePath% = pot do korenskega imenika
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action', /* ... */);

Napredni zapis

Cilj poti, ki je običajno zapisan v obliki Presenter:action, je mogoče izraziti tudi s poljem, ki določa posamezne parametre in njihove privzete vrednosti:

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

Za podrobnejšo specifikacijo je mogoče uporabiti še bolj razširjeno obliko, v kateri lahko poleg privzetih vrednosti nastavite tudi druge lastnosti parametrov, na primer regularni izraz za preverjanje (glejte parameter id ):

use Nette\Routing\Route;

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

Pomembno je opozoriti, da če parametri, opredeljeni v polju, niso vključeni v masko poti, njihovih vrednosti ni mogoče spremeniti, niti z uporabo parametrov poizvedbe, določenih za vprašalnim znakom v naslovu URL.

Filtri in prevodi

Dobra praksa je, da izvorno kodo pišete v angleščini, a kaj, če potrebujete, da je URL vašega spletnega mesta preveden v drug jezik? Preproste poti, kot so npr:

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

bodo ustvarile angleške naslove URL, kot sta /product/123 ali /cart. Če želimo, da so predstavniki in dejanja v naslovu URL prevedeni v nemščino (npr. /produkt/123 ali /einkaufswagen), lahko uporabimo prevajalski slovar. Za njegovo dodajanje že potrebujemo „bolj zgovorno“ različico drugega parametra:

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterTable => [
			// niz v naslovu URL => presenter
			'produkt' => 'Product',
			'einkaufswagen' => 'Cart',
			'katalog' => 'Catalog',
		],
	],
	'action' => [
		Route::Value => 'default',
		Route::FilterTable => [
			'liste' => 'list',
		],
	],
]);

Za isti predstavnik lahko uporabimo več ključev slovarja. Z njimi bodo zanj ustvarjeni različni vzdevki. Zadnji ključ velja za kanonično različico (tj. tisto, ki bo v ustvarjenem naslovu URL).

Na ta način je mogoče prevajalno tabelo uporabiti za kateri koli parameter. Če prevod ne obstaja, se vzame izvirna vrednost. To obnašanje lahko spremenimo tako, da dodamo Route::FilterStrict => true in pot bo nato zavrnila URL, če vrednosti ni v slovarju.

Poleg slovarja prevodov v obliki polja je mogoče nastaviti tudi lastne prevajalske funkcije:

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

Funkcija Route::FilterIn pretvori parameter v naslovu URL v niz, ki se nato posreduje predstavniku, funkcija FilterOut pa poskrbi za pretvorbo v nasprotni smeri.

Parametri presenter, action in module imajo že vnaprej določene filtre, ki pretvarjajo med slogom PascalCase oz. camelCase in kebab-case, uporabljenim v naslovu URL. Privzeta vrednost parametrov je že zapisana v pretvorjeni obliki, tako da na primer v primeru predvajalnika zapišemo <presenter=ProductEdit> namesto <presenter=product-edit>.

Splošni filtri

Poleg filtrov za določene parametre lahko določite tudi splošne filtre, ki prejmejo asociativno polje vseh parametrov, ki jih lahko poljubno spremenijo in nato vrnejo. Splošni filtri so opredeljeni pod ključem 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 { /* ... */ },
	],
]);

Splošni filtri vam dajejo možnost, da prilagodite obnašanje poti na popolnoma poljuben način. Uporabimo jih lahko na primer za spreminjanje parametrov na podlagi drugih parametrov. Na primer, prevod <presenter> in <action> na podlagi trenutne vrednosti parametra <lang>.

Če ima parameter opredeljen filter po meri in hkrati obstaja splošni filter, se filter po meri FilterIn izvede pred splošnim in obratno, splošni FilterOut se izvede pred filtrom po meri. Tako so znotraj splošnega filtra vrednosti parametrov presenter oz. action zapisane v slogu PascalCase oz. camelCase.

Enosmerna zastavica

Enosmerne poti se uporabljajo za ohranjanje funkcionalnosti starih URL-jev, ki jih aplikacija ne ustvarja več, vendar jih še vedno sprejema. Označimo jih z OneWay:

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

Pri dostopu do starega naslova URL predstavnik samodejno preusmeri na novi naslov URL, tako da iskalniki teh strani ne indeksirajo dvakrat (glejte SEO in kanonizacijo).

Dinamično usmerjanje s povratnimi klici

Dinamično usmerjanje s povratnimi klici omogoča neposredno dodeljevanje funkcij (povratnih klicev) na poti, ki se bodo izvedle, ko bo obiskana določena pot. Ta prilagodljiva funkcija vam omogoča hitro in učinkovito ustvarjanje različnih končnih točk za vašo aplikacijo:

$router->addRoute('test', function () {
	echo 'You are at the /test address';
});

V maski lahko določite tudi parametre, ki bodo samodejno posredovani povratnemu klicu:

$router->addRoute('<lang cs|en>', function (string $lang) {
	echo match ($lang) {
		'cs' => 'Welcome to the Czech version of our website!',
		'en' => 'Welcome to the English version of our website!',
	};
});

Moduli

Če imamo več poti, ki pripadajo enemu modulu, jih lahko z uporabo withModule() združimo v skupine:

$router = new RouteList;
$router->withModule('Forum') // naslednji usmerjevalniki so del modula Forum
	->addRoute('rss', 'Feed:rss') // predstavnik je Forum:Feed
	->addRoute('<presenter>/<action>')

	->withModule('Admin') // Naslednji usmerjevalniki so del modula Forum:Admin
		->addRoute('sign:in', 'Sign:in');

Druga možnost je uporaba parametra module:

// URL upravljam/dashboard/default se prikaže v predstavniku Admin:Dashboard
$router->addRoute('manage/<presenter>/<action>', [
	'module' => 'Admin',
]);

Poddomene

Zbirke poti lahko združite po poddomenah:

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

V imenu domene lahko uporabite tudi nadomestne znake:

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

Predpona poti

Zbirke poti lahko združite po poti v URL:

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

Kombinacije

Zgornje načine uporabe je mogoče kombinirati:

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

Parametri poizvedbe

Maske lahko vsebujejo tudi parametre poizvedbe (parametri za vprašalnim znakom v naslovu URL). Ne morejo opredeliti izraza za preverjanje, lahko pa spremenijo ime, pod katerim so posredovani predstavniku:

// uporabite parameter poizvedbe 'cat' kot 'categoryId' v aplikaciji
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);

Foo Parametri

Zdaj se bomo poglobili. Parametri Foo so pravzaprav neimenovani parametri, ki omogočajo ujemanje z regularnim izrazom. Naslednja pot ustreza /index, /index.html, /index.htm in /index.php:

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

Prav tako je mogoče izrecno določiti niz, ki bo uporabljen za generiranje URL-jev. Niz mora biti nameščen neposredno za vprašalnim znakom. Naslednja pot je podobna prejšnji, vendar generira /index.html namesto /index, ker je niz .html nastavljen kot „generirana vrednost“.

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

Integracija

Da bi naš usmerjevalnik povezali z aplikacijo, moramo o tem obvestiti vsebnik DI. Najlažje je pripraviti tovarno, ki bo zgradila objekt usmerjevalnika, in povedati konfiguraciji vsebnika, naj jo uporabi. Recimo, da v ta namen napišemo 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;
	}
}

Nato zapišemo v konfiguracijo:

services:
	- App\Core\RouterFactory::createRouter

Vse odvisnosti, kot je povezava s podatkovno bazo itd., se metodi tovarne posredujejo kot njeni parametri z uporabo samodejnega povezovanja:

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

SimpleRouter

Precej preprostejši usmerjevalnik od zbirke poti je SimpleRouter. Uporabimo ga lahko, kadar ni potrebe po posebni obliki URL, kadar mod_rewrite (ali alternative) ni na voljo ali kadar se preprosto še ne želimo ukvarjati z uporabniku prijaznimi URL-ji.

Generira naslove v približno takšni obliki:

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

Parameter konstruktorja SimpleRouter je privzeti predstavnik in dejanje, tj. dejanje, ki se izvede, če odpremo npr. http://example.com/ brez dodatnih parametrov.

// privzeto za predstavitelja 'Home' in akcijo 'default'
$router = new Nette\Application\Routers\SimpleRouter('Home:default');

Priporočamo, da se SimpleRouter opredeli neposredno v konfiguraciji:

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

SEO in kanonizacija

Okvir izboljša SEO (optimizacijo za iskalnike), saj preprečuje podvajanje vsebine na različnih URL-jih. Če je več naslovov povezanih z istim ciljem, npr. /index in /index.html, ogrodje določi prvega kot primarnega (kanoničnega) in nanj preusmeri druge z uporabo kode HTTP 301. Zaradi tega iskalniki strani ne indeksirajo dvakrat in ne porušijo njihovega ranga strani. .

Ta postopek se imenuje kanonizacija. Kanonični URL je tisti, ki ga ustvari usmerjevalnik, tj. prva ustrezna pot v zbirki brez oznake OneWay. Zato v zbirki najprej navedemo primarne poti.

Kanonizacijo izvede predstavnik, več v poglavju Kanonizacija.

HTTPS

Za uporabo protokola HTTPS ga je treba aktivirati na gostovanju in konfigurirati strežnik.

Preusmeritev celotnega spletnega mesta na protokol HTTPS je treba izvesti na ravni strežnika, na primer z datoteko .htaccess v korenskem imeniku naše aplikacije, s kodo HTTP 301. Nastavitve se lahko razlikujejo glede na gostovanje in so videti nekako takole:

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

Usmerjevalnik ustvari naslov URL z enakim protokolom, kot je bila naložena stran, zato ni treba nastavljati ničesar drugega.

Če pa izjemoma potrebujemo, da se različne poti izvajajo pod različnimi protokoli, bomo to določili v maski poti:

// Ustvari naslov HTTP
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);

// Ustvari naslov HTTPS
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);

Razhroščevanje usmerjevalnika

Vrstica za usmerjanje, prikazana v Tracy Bar, je uporabno orodje, ki prikazuje seznam poti in tudi parametre, ki jih je usmerjevalnik pridobil iz URL-ja.

Zelena vrstica s simbolom ✓ predstavlja pot, ki je ustrezala trenutnemu naslovu URL, modre vrstice s simboli ≈ pa označujejo poti, ki bi prav tako ustrezale naslovu URL, če jih zelena ne bi prehitela. V nadaljevanju vidimo trenutni predstavnik in dejanje.

Hkrati je v primeru nepričakovane preusmeritve zaradi kanonizacije koristno pogledati v vrstico preusmeritev, da vidimo, kako je usmerjevalnik prvotno razumel naslov URL in zakaj ga je preusmeril.

Pri odpravljanju napak usmerjevalnika je priporočljivo, da v brskalniku odprete programerska orodja (Ctrl+Shift+I ali Cmd+Option+I) in onemogočite predpomnilnik na plošči Omrežje, da se vanj ne shranjujejo preusmeritve.

Uspešnost

Število poti vpliva na hitrost usmerjevalnika. Njihovo število vsekakor ne sme presegati nekaj deset. Če ima vaše spletno mesto preveč zapleteno strukturo URL, lahko napišete usmerjevalnik po meri.

Če usmerjevalnik nima odvisnosti, na primer od podatkovne zbirke, in njegova tovarna nima argumentov, lahko njegovo sestavljeno obliko serializiramo neposredno v vsebnik DI in tako aplikacijo nekoliko pohitrimo.

routing:
	cache: true

Usmerjevalnik po meri

Naslednje vrstice so namenjene zelo naprednim uporabnikom. Ustvarite lahko svoj usmerjevalnik in ga seveda dodate v zbirko poti. Usmerjevalnik je implementacija vmesnika Nette\Routing\Router z dvema metodama:

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 obdela trenutni zahtevek $httpRequest, iz katerega je mogoče pridobiti ne le naslov URL, temveč tudi glave itd., v polje, ki vsebuje ime predstavnika in njegove parametre. Če zahteve ne more obdelati, vrne ničlo. Pri obdelavi zahteve moramo vrniti vsaj predstavnika in akcijo. Ime predstavnika je popolno in vključuje vse module:

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

Metoda constructUrl, po drugi strani pa iz niza parametrov ustvari absolutni naslov URL. Uporabi lahko podatke iz parametra $refUrl, ki je trenutni naslov URL.

Če želite zbirki poti dodati usmerjevalnik po meri, uporabite add():

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

Ločena uporaba

Z ločeno uporabo mislimo na uporabo zmožnosti usmerjevalnika v aplikaciji, ki ne uporablja aplikacije Nette in predstavnikov. Zanjo velja skoraj vse, kar smo prikazali v tem poglavju, z naslednjimi razlikami:

Tako bomo ponovno ustvarili metodo, ki bo zgradila usmerjevalnik, na primer:

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

Če uporabljate vsebnik DI, kar priporočamo, ponovno dodajte metodo v konfiguracijo in nato skupaj z zahtevo HTTP iz vsebnika pridobite usmerjevalnik:

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

Ali pa bomo predmete ustvarili neposredno:

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

Zdaj moramo omogočiti delovanje usmerjevalnika:

$params = $router->match($httpRequest);
if ($params === null) {
	// ni bila najdena ustrezna pot, pošljemo napako 404.
	exit;
}

// obdelamo prejete parametre
$controller = $params['controller'];
// ...

In obratno, usmerjevalnik bomo uporabili za vzpostavitev povezave:

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