ルーティング
ルーターは 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:edit、Catalog:list
と解釈します。
同時に presenter と action のパラメータに既定値 Home と
default を与えるので、これらも省略できるようになります。ですからこのルートは
/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:view を id: 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
の関数は逆向きの変換を受け持ちます。
presenter、action、module のパラメータには、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
が独自のものより先に実行されます。ですから一般のフィルタの中では、presenter と
action のパラメータの値はそれぞれ 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 とプレゼンターを使わないアプリケーションでルーターの機能を活かすことです。この章で見てきたことのほとんどはそこでも当てはまり、違いは次の点だけです。
- ルートのコレクションには Nette\Routing\RouteListクラスを使います
- 単純なルーターには Nette\Routing\SimpleRouterクラスを使います
Presenter:actionの組が存在しないので、詳しい書き方を使います
ですからここでもルーターを組み立てるメソッドを作ります。たとえば次のようにです。
namespace App\Core;
use Nette\Routing\RouteList;
class RouterFactory
{
public static function createRouter(): RouteList
{
$router = new RouteList;
$router->addRoute('rss.xml', [
'controller' => 'RssFeedController',
]);
$router->addRoute('article/<id \d+>', [
'controller' => 'ArticleController',
]);
// ...
return $router;
}
}
おすすめの DI コンテナを使っているなら、このメソッドをやはり設定に足して、コンテナからルーターを HTTP のリクエストとともに受け取ります。
$router = $container->getByType(Nette\Routing\Router::class);
$httpRequest = $container->getByType(Nette\Http\IRequest::class);
あるいはオブジェクトを直接作ります。
$router = App\Core\RouterFactory::createRouter();
$httpRequest = (new Nette\Http\RequestFactory)->fromGlobals();
あとはルーターに仕事をさせるだけです。
$params = $router->match($httpRequest);
if ($params === null) {
// 一致するルートが見つからなかったので 404 のエラーを送ります
exit;
}
// 得られたパラメータを処理します
$controller = $params['controller'];
// ...
逆にルーターを使ってリンクを組み立てます。
$params = ['controller' => 'ArticleController', 'id' => 123];
$url = $router->constructUrl($params, $httpRequest->getUrl());