ルーティング

ルーターは URL アドレスにまつわるすべてを引き受けるので、あなたが URL のことを考える必要はありません。ここでは次のことを扱います。

  • URL を思いどおりの見た目にするためのルーターの設定
  • SEO とリダイレクト
  • そして独自のルーターの書き方

人にやさしい URL(かっこいい URL、きれいな URL とも呼ばれます)は使いやすく、覚えやすく、SEO にもよい影響を与えます。Nette はそれを心得ていて、開発者の求めるものにしっかり応えます。アプリケーションの URL の構造を、思いどおりに設計できます。しかもアプリケーションが完成したあとでも設計できます。コードやテンプレートの変更が要らないからです。それはすべてのプレゼンターにアノテーションとして散らばるのではなく、ただ一か所、つまりルーターで優雅に定義されます。

Nette のルーターが並外れているのは、双方向だからです。HTTP のリクエストから URL を読み解くことも、リンクを作ることもできます。ですから Nette Applicationで欠かせない役割を果たします。現在のリクエストをどのプレゼンターとアクションが処理するかを決めるだけでなく、テンプレートなどで URL を生成するのにも使われるからです。

とはいえルーターの用途はそれだけではありません。プレゼンターをまったく使わないアプリケーションや REST API などでも使えます。詳しくは 単独での利用の節をご覧ください。

ルートのコレクション

アプリケーションの URL アドレスの構造を定義するもっとも心地よい方法は、Nette\Application\Routers\RouteListクラスが提供します。その定義は、いわゆるルートの一覧、つまり URL アドレスのマスクと、それに結びつくプレゼンターやアクションから成り、単純な API で書けます。ルートに名前を付ける必要はまったくありません。

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

この例からわかるように、ブラウザで https://domain.com/rss.xml を開くと Feed プレゼンターの rss アクションが表示されます。https://domain.com/article/12 なら Article プレゼンターの view アクションが表示される、といった具合です。ふさわしいルートが見つからなければ、Nette Application は BadRequestExceptionを投げて応え、ユーザーには 404 Not Found のエラーページとして表示されます。

ルートの順序

個々のルートを並べる順序はきわめて重要です。上から下へ順に評価されるからです。原則は、ルートを具体的なものから一般的なものへと宣言することです。

// 誤り: 'rss.xml' は最初のルートに捕まえられ、その文字列が <slug> と解釈されます
$router->addRoute('<slug>', 'Article:view');
$router->addRoute('rss.xml', 'Feed:rss');

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

リンクを生成するときも、ルートは上から下へ評価されます。

// 誤り: 'Feed:rss' へのリンクが 'admin/feed/rss' として生成されます
$router->addRoute('admin/<presenter>/<action>', 'Admin:default');
$router->addRoute('rss.xml', 'Feed:rss');

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

ルートを正しく組み立てるにはいくらか慣れが要ることは、隠さずに申し上げます。身につくまでは ルーティングのパネルが役に立つ道具になるでしょう。

マスクとパラメータ

マスクはウェブサイトのルートディレクトリからの相対パスを表します。もっとも単純なマスクは静的な URL です。

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

マスクにはパラメータが入ることがよくあります。これは山かっこで囲まれ(たとえば <year>)、対象のプレゼンターに、たとえば renderShow(int $year) メソッドや永続パラメータ $year に渡されます。

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

この例からわかるように、ブラウザで https://example.com/chronicle/2020 を開くと、History プレゼンターの show アクションがパラメータ year: 2020 とともに表示されます。

パラメータの既定値はマスクの中で直接指定でき、そうするとそのパラメータは省略できるようになります。

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

これでこのルートは https://example.com/chronicle/ という URL も受け付け、やはり History:show をパラメータ year: 2020 とともに表示します。

もちろんプレゼンターやアクションの名前もパラメータにできます。たとえば次のようにです。

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

このルートはたとえば /article/edit/catalog/list の形の URL を受け付け、それぞれプレゼンターとアクション Article:editCatalog:list と解釈します。

同時に presenteraction のパラメータに既定値 Homedefault を与えるので、これらも省略できるようになります。ですからこのルートは /article という URL も受け付け、Article:default と解釈します。逆に Product:default へのリンクはパス /product を生成し、既定の Home:default へのリンクはパス / を生成します。

マスクはウェブサイトのルートディレクトリからの相対パスだけでなく、スラッシュで始めれば絶対パスを、スラッシュ 2 つで始めれば絶対 URL 全体を表せます。

// ドキュメントルートからの相対
$router->addRoute('<presenter>/<action>', /* ... */);

// 絶対パス(ドメインからの相対)
$router->addRoute('/<presenter>/<action>', /* ... */);

// ドメインを含む絶対 URL(スキームからの相対)
$router->addRoute('//<lang>.example.com/<presenter>/<action>', /* ... */);

// スキームを含む絶対 URL
$router->addRoute('https://<lang>.example.com/<presenter>/<action>', /* ... */);

検証の正規表現

パラメータごとに 正規表現で検証の条件を指定できます。たとえば id パラメータには、正規表現 \d+ で数字しか入れられないと指定します。

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

すべてのパラメータの既定の正規表現は [^/]+、つまりスラッシュ以外のすべてです。パラメータにスラッシュも受け付けさせたいなら、正規表現を .+ にします。

// https://example.com/a/b/c を受け付け、path は 'a/b/c' になります
$router->addRoute('<path .+>', /* ... */);

省略できる部分

マスクの中では、角かっこで省略できる部分に印を付けられます。マスクのどの部分も省略できるようにでき、その中にパラメータを入れられます。

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

// 次のパスを受け付けます:
//    /en/download  => lang => en, name => download
//    /download     => lang => null, name => download

パラメータが省略できる部分の中にあると、当然そのパラメータも省略できるようになります。既定値が指定されていなければ null になります。

省略できる部分はドメインにも置けます。

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

省略できる部分は自由に入れ子にしたり組み合わせたりできます。

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

// 次のパスを受け付けます:
// 	/en/hello
// 	/en-us/hello
// 	/hello
// 	/hello/page-12

URL を生成するときは、もっとも短い形が優先されるので、省ける部分はすべて省かれます。ですからたとえばルート index[.html] はパス /index を生成します。この振る舞いは、開き角かっこのうしろに感嘆符を置くと逆にできます。

// /hello と /hello.html を受け付け、/hello を生成します
$router->addRoute('<name>[.html]', /* ... */);

// /hello と /hello.html を受け付け、/hello.html を生成します
$router->addRoute('<name>[!.html]', /* ... */);

角かっこのない、省略できるパラメータ(つまり既定値を持つパラメータ)は、実質的に次のように囲まれているかのように振る舞います。

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

// これは次と同じです:
$router->addRoute('[<presenter=Home>/[<action=default>/[<id>]]]', /* ... */);

末尾のスラッシュの振る舞いに手を入れて、たとえば /home/ の代わりに /home を生成させたいなら、次のようにできます。

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

ワイルドカード

絶対 URL のマスクでは次のワイルドカードを使えます。たとえば開発環境と本番環境で違うかもしれないドメインを、マスクに書かずに済ませられます。

  • %tld% = トップレベルドメイン、たとえば com や org
  • %sld% = セカンドレベルドメイン、たとえば example
  • %domain% = サブドメインを除いたドメイン、たとえば example.com
  • %host% = ホスト全体、たとえば www.example.com
  • %basePath% = ルートディレクトリへのパス
$router->addRoute('//www.%domain%/%basePath%/<presenter>/<action>', /* ... */);
$router->addRoute('//www.%sld%.%tld%/%basePath%/<presenter>/<action>', /* ... */);

詳しい書き方

ふつう Presenter:action の形で書くルートの行き先は、個々のパラメータとその既定値を定義する配列でも書けます。

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

より細かく指定するには、さらに広げた形も使えます。そこでは既定値のほかに、検証の正規表現などパラメータのほかの性質も設定できます(id パラメータをご覧ください)。

use Nette\Routing\Route;

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

大事なのは、配列で定義したパラメータがパスのマスクに現れていない場合、その値は変えられないという点です。URL の疑問符のうしろに書くクエリパラメータでも変えられません。

これは固定のパラメータ、つまりあるページに短く覚えやすい URL を与えるのに役立ちます。たとえば /tos がいつも Article:viewid: 123 で開くようにするには次のようにします。

$router->addRoute('tos', [
	'presenter' => 'Article',
	'action' => 'view',
	'id' => 123,
]);

フィルタと変換

アプリケーションのソースコードは英語で書きますが、ウェブサイトの URL をチェコ語にしたい場合、次のような単純なルーティングでは、

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

/product/123/cart のような英語の URL が生成されます。URL の中のプレゼンターとアクションをチェコ語(たとえば /produkt/123/kosik)で表したいなら、変換の辞書を使えます。それを書くには、第 2 パラメータの「詳しい」書き方がもう必要です。

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterTable => [
			// URL の中の文字列 => プレゼンター
			'produkt' => 'Product',
			'kosik' => 'Cart',
			'katalog' => 'Catalog',
		],
	],
	'action' => [
		Route::Value => 'default',
		Route::FilterTable => [
			'seznam' => 'list',
		],
	],
]);

変換の辞書では、複数のキーが同じプレゼンターを指しても構いません。そうするとそのプレゼンターにいろいろな別名ができます。最後のキーが正式な形(つまり生成される URL に入る形)と見なされます。

変換の表はこのやり方でどのパラメータにも使えます。変換が存在しなければ、もとの値がそのまま使われます。この振る舞いは Route::FilterStrict => true を足すと変えられ、値が辞書にない場合、そのルートは URL を受け付けなくなります。

配列の形の変換の辞書のほかに、独自の変換の関数も使えます。

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>/<id>', [
	'presenter' => [
		Route::Value => 'Home',
		Route::FilterIn => function (string $s): string { /* ... */ },
		Route::FilterOut => function (string $s): string { /* ... */ },
	],
	'action' => 'default',
	'id' => null,
]);

Route::FilterIn の関数は、URL の中のパラメータと、そのあとプレゼンターに渡される文字列とのあいだの変換を行い、FilterOut の関数は逆向きの変換を受け持ちます。

presenteractionmodule のパラメータには、PascalCase や camelCase の書き方と、URL で使われる kebab-case とのあいだを変換するフィルタがあらかじめ用意されています。パラメータの既定値は、アプリケーションに渡される形(プレゼンターとモジュールは PascalCase、アクションは camelCase)で書くので、たとえばプレゼンターなら <presenter=ProductEdit> と書き、<presenter=product-edit> とは書きません。

一般のフィルタ

特定のパラメータ向けのフィルタのほかに、一般のフィルタも定義できます。これはすべてのパラメータの連想配列を受け取り、好きなように変えて返せます。一般のフィルタは空のキーの下に定義します。

use Nette\Routing\Route;

$router->addRoute('<presenter>/<action>', [
	'presenter' => 'Home',
	'action' => 'default',
	'' => [
		Route::FilterIn => function (array $params): array { /* ... */ },
		Route::FilterOut => function (array $params): array { /* ... */ },
	],
]);

一般のフィルタを使えば、ルートの振る舞いを本当に好きなように変えられます。たとえばほかのパラメータをもとにパラメータを変えるのに使えます。たとえば <lang> パラメータの今の値をもとに <presenter><action> を変換する、といった具合です。

パラメータに独自のフィルタが定義されていて、一般のフィルタもある場合、独自の FilterIn が一般のものより先に実行され、逆に一般の FilterOut が独自のものより先に実行されます。ですから一般のフィルタの中では、presenteraction のパラメータの値はそれぞれ PascalCase と camelCase の書き方になっています。

これらのフィルタの実用的な使い方は スラッグ付きのきれいな URLをご覧ください。テンプレートを一切変えずに /article/123-how-to-bake-bread のような SEO にやさしい URL を生成します。

OneWay フラグ

一方通行のルートは、アプリケーションがもう生成しないけれど受け付けはする古い URL を生かしておくのに使います。OneWay フラグで印を付けます。

// 古い URL /product-info?id=123
$router->addRoute('product-info', 'Product:detail', oneWay: true);
// 新しい URL /product/123
$router->addRoute('product/<id>', 'Product:detail');

古い URL にアクセスすると、プレゼンターが自動的に新しい URL へリダイレクトするので、検索エンジンがこれらのページを二重に登録することはありません(SEO と正規化をご覧ください)。

コールバックによる動的なルーティング

コールバックによる動的なルーティングを使うと、ルートに関数(コールバック)を直接割り当てられ、そのパスが訪れられたときに実行されます。この柔軟な機能のおかげで、アプリケーションのさまざまなエンドポイントを手早く効率よく作れます。

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

マスクの中にパラメータを定義することもでき、それは自動的にコールバックに渡されます。

$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!',
	};
});

マスクからのパラメータのほかに、コールバックは DI コンテナのサービスも受け取れます。それはパラメータの型をもとに渡されます。さらに $presenter パラメータには、そのルートを処理する MicroPresenterのインスタンスが渡されます。

$router->addRoute('<lang cs|en>', function (string $lang, Nette\Http\Request $httpRequest, NetteModule\MicroPresenter $presenter) {
	// ...
});

モジュール

共通のモジュールに属するルートが複数あるなら、withModule() を使います。指定したモジュールは、そのグループのすべてのルートのプレゼンターに自動的に前置され、URL からはすっかり消えます。

$router = new RouteList;
$router->withModule('Forum') // 以下のルートは Forum モジュールの一部です
	->addRoute('rss', 'Feed:rss') // プレゼンターは Forum:Feed になります
	->addRoute('<presenter>/<action>')

	->withModule('Admin') // 以下のルートは Forum:Admin モジュールの一部です
		->addRoute('sign:in', 'Sign:in');

代わりに module パラメータも使えます。これも同じように固定のモジュールを設定し、URL には現れないようにします。

// URL manage/dashboard/default はプレゼンター Admin:Dashboard に対応します
$router->addRoute('manage/<presenter>/<action>', [
	'module' => 'Admin',
]);

プレゼンターの名前は、そのモジュールと合わせてはじめて完全になります。たとえば Front:Admin:ProductList です。こうした完全な名前が URL のパラメータに入るとき、ルーターは 2 つの単純な規則でそれを符号化します。コロン :(モジュールの区切り)はすべてドットになり、PascalCase の名前の語の切れ目はすべてハイフンになります。ですから Front:Admin:ProductList は URL の中で front.admin.product-list として現れ、同じやり方で読み戻されます。モジュールに分かれたアプリケーションが、上のような道具を使わないとドットだらけの URL を作るのは、これが理由です。

withModule()module パラメータも、まさにこれを避けます。プレゼンターの名前が URL に届く前に、分かっているモジュールの接頭辞を取り除くからです。モジュールが決まりきったものである以上、そもそも符号化する必要はありません。

ときにはモジュール自体を変えられるようにして、URL に現れてほしいこともあります。そこでマスクの中で <module> を直接使います。ただし大事な点にご注意ください。<module> はモジュールのパス全体、つまりプレゼンターの名前の最後のコロンまでを取り込みます。プレゼンター Shop:Admin:Product ならモジュールは Shop:Admin、プレゼンターは Product ということになり、コロンはドットになるので、次のようになります。

サブドメイン

ルートのコレクションはサブドメインごとに分けられます。

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

ドメイン名には ワイルドカードも使えます。

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

パスの接頭辞

ルートのコレクションは URL のパスごとに分けられます。

$router = new RouteList;
$router->withPath('eshop')
	->addRoute('rss', 'Feed:rss') // URL /eshop/rss に一致します
	->addRoute('<presenter>/<action>'); // URL /eshop/<presenter>/<action> に一致します

組み合わせ

上のグループ分けは互いに組み合わせられます。

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

クエリパラメータ

マスクにはクエリパラメータ(URL の疑問符のうしろのパラメータ)も入れられます。これには検証の正規表現を定義できませんが、プレゼンターに渡される名前は変えられます。

// クエリパラメータ 'cat' をアプリケーションでは 'categoryId' という名前で使いたい
$router->addRoute('product ? id=<productId> & cat=<categoryId>', /* ... */);

Foo パラメータ

さらに深いところへ進みます。Foo パラメータは要するに名前のないパラメータで、正規表現に一致させられます。例として /index/index.html/index.htm/index.php を受け付けるルートを挙げます。

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

URL を生成するときに使われる文字列を、はっきり定義することもできます。その文字列は疑問符のすぐうしろに置かなければなりません。次のルートは前のものと似ていますが、/index の代わりに /index.html を生成します。生成に使う値として文字列 .html が設定されているからです。

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

組み込み

作ったルーターをアプリケーションに組み込むには、DI コンテナにそれを教える必要があります。もっとも簡単なのは、ルーターのオブジェクトを作るファクトリを用意して、設定でそれを使うようにコンテナに伝えることです。そのために App\Core\RouterFactory::createRouter() メソッドを書くとしましょう。

namespace App\Core;

use Nette\Application\Routers\RouteList;

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

そして設定に次のように書きます。

services:
	- App\Core\RouterFactory::createRouter

データベースなどへの依存関係があれば、オートワイヤリングによってファクトリメソッドのパラメータとして渡されます。

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

SimpleRouter

ルートのコレクションよりずっと単純なルーターが SimpleRouterです。URL の形に特別な要求がないとき、mod_rewrite(やその代わりになるもの)が使えないとき、あるいはまだきれいな URL に手を出したくないときに使います。

だいたい次のような形のアドレスを生成します。

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

SimpleRouter のコンストラクタのパラメータは既定のプレゼンターとアクション、つまり http://example.com/ をほかのパラメータなしで開いたときに実行されるアクションです。

// 既定のプレゼンターは 'Home'、アクションは 'default' になります
$router = new Nette\Application\Routers\SimpleRouter('Home:default');

SimpleRouter は設定で直接定義することをおすすめします。

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

SEO と正規化

フレームワークは、異なる URL に同じ内容が現れるのを防ぐことで SEO(検索エンジン最適化)に貢献します。ある行き先に複数のアドレス、たとえば /index/index.html が通じている場合、フレームワークは最初のものを主要なもの(正式なもの)と定め、ほかはそこへ HTTP コード 301 でリダイレクトします。おかげで検索エンジンがページを二重に登録して、そのページランクを薄めることがありません。

この処理を正規化と呼びます。正式な URL は、ルーターが生成するもの、つまりコレクションの中で最初に一致した OneWay フラグのないルートが生成するものです。ですからコレクションでは主要なルートを先に並べます。

正規化はプレゼンターが行います。詳しくは 正規化の章をご覧ください。

HTTPS

HTTPS プロトコルを使うには、ホスティングでそれを有効にし、サーバーを正しく設定する必要があります。

ウェブサイト全体の HTTPS へのリダイレクトは、サーバーの水準で、たとえばアプリケーションのルートディレクトリの .htaccess ファイルで HTTP コード 301 を使って設定しなければなりません。設定はホスティングによって違うことがあり、だいたい次のようになります。

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

ルーターはページが読み込まれたのと同じプロトコルで URL を生成するので、これ以上の設定は要りません。

とはいえ、例外的にルートごとに違うプロトコルで動かす必要があるなら、ルートのマスクで指定します。

// HTTP のアドレスを生成します
$router->addRoute('http://%host%/<presenter>/<action>', /* ... */);

// HTTPS のアドレスを生成します
$router->addRoute('https://%host%/<presenter>/<action>', /* ... */);

ルーターのデバッグ

Tracy Barに表示されるルーティングのパネルは役に立つ助っ人で、ルートの一覧と、ルーターが URL から取り出したパラメータを見せてくれます。

✓ の印が付いた緑の帯は、現在の URL を処理したルートを表します。青色と ≈ の印は、緑のルートに先を越されなければやはりその URL を処理したであろうルートを示します。さらに現在のプレゼンターとアクションも見られます。

同時に、正規化によって思いがけないリダイレクトが起きたときは、パネルの redirect の帯を見るとよいでしょう。そこでルーターがもともとその URL をどう解釈し、なぜリダイレクトしたのかがわかります。

ルーターをデバッグするときは、ブラウザで開発者ツールを開き(Ctrl+Shift+I または Cmd+Option+I)、Network のパネルでキャッシュを無効にして、リダイレクトが保存されないようにすることをおすすめします。

性能

ルートの数はルーターの速さに影響します。その数は数十を超えないようにすべきです。ウェブサイトの URL の構造が複雑すぎるなら、独自のルーターを書けます。

ルーターがデータベースなどへの依存関係を持たず、そのファクトリが引数を取らないなら、その組み立て済みの形を DI コンテナに直接シリアライズして、アプリケーションをわずかに速くできます。

routing:
	cache: true

独自のルーター

以下の記述はとても進んだ利用者向けです。独自のルーターを作って、ルートのコレクションに自然に組み込めます。ルーターは 2 つのメソッドを持つ Nette\Routing\Routerインターフェースの実装です。

use Nette\Http\IRequest as HttpRequest;
use Nette\Http\UrlScript;

class MyRouter implements Nette\Routing\Router
{
	public function match(HttpRequest $httpRequest): ?array
	{
		// ...
	}

	public function constructUrl(array $params, UrlScript $refUrl): ?string
	{
		// ...
	}
}

match メソッドは現在のリクエスト $httpRequest(そこからは URL だけでなくヘッダーなども取り出せます)を、プレゼンターの名前とそのパラメータを含む配列に変えます。リクエストを処理できなければ null を返します。リクエストを処理するときは、少なくともプレゼンターを返さなければなりません。アクションは省略でき、指定がなければ default になります。プレゼンターの名前は完全で、モジュールも含みます。

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

一方 constructUrl メソッドは、パラメータの配列から結果となる絶対 URL を組み立てます。そのとき現在の URL である $refUrlパラメータの情報を使えます。

add() でルートのコレクションに足します。

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

単独での利用

単独での利用とは、Nette Application とプレゼンターを使わないアプリケーションでルーターの機能を活かすことです。この章で見てきたことのほとんどはそこでも当てはまり、違いは次の点だけです。

ですからここでもルーターを組み立てるメソッドを作ります。たとえば次のようにです。

namespace App\Core;

use Nette\Routing\RouteList;

class RouterFactory
{
	public static function createRouter(): RouteList
	{
		$router = new RouteList;
		$router->addRoute('rss.xml', [
			'controller' => 'RssFeedController',
		]);
		$router->addRoute('article/<id \d+>', [
			'controller' => 'ArticleController',
		]);
		// ...
		return $router;
	}
}

おすすめの DI コンテナを使っているなら、このメソッドをやはり設定に足して、コンテナからルーターを HTTP のリクエストとともに受け取ります。

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

あるいはオブジェクトを直接作ります。

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

あとはルーターに仕事をさせるだけです。

$params = $router->match($httpRequest);
if ($params === null) {
	// 一致するルートが見つからなかったので 404 のエラーを送ります
	exit;
}

// 得られたパラメータを処理します
$controller = $params['controller'];
// ...

逆にルーターを使ってリンクを組み立てます。

$params = ['controller' => 'ArticleController', 'id' => 123];
$url = $router->constructUrl($params, $httpRequest->getUrl());
バージョン: 4.x