URI ルーティング

通常、URL 文字列と対応するコントローラクラス・メソッドは一対一の関係にあります。URI のセグメントは通常つぎのパターンに従います:

example.com/class/function/id/

しかしいくつかの場合ではこの関係を変更したいことでしょう。そのため、URLに対応するものとは異なるクラス・メソッドを呼び出せるようにもなっています。

例として、つぎの形式を持つ URL があるとします:

example.com/product/1/
example.com/product/2/
example.com/product/3/
example.com/product/4/

通常、URLの第2セグメントはメソッド名として予約されていますが、上のこの例では代わりに製品IDとなっています。これを実現するため、CodeIgniter は URL ハンドラを変更することができます。

独自のルーティングルールの設定

Routing rules are defined in the app/config/Routes.php file. これの中で、RouteCollection クラスのインスタンスが作られ、独自のルーティング基準を設定を可能としていることがわかるでしょう。 ルーティングはプレースホルダまたは正規表現で設定できます。

ルーティングは単に左側に URL、右側に対応するコントローラとメソッドを取ります。合わせて、あらゆるパラメータはコントローラに渡される必要があります。コントローラとメソッドは静的メソッドを使うのと同じ方法で列挙する必要があります。Users::list のように、完全な名前空間のクラス名とメソッド名をダブルコロンを使います。もしそのメソッドがパラメータを要求するなら、スラッシュ区切りでメソッド名の後に続けます:

// Calls the $Users->list()
Users::list
// Calls $Users->list(1, 23)
Users::list/1/23

プレースホルダ

典型的なルーティングはつぎのような形を取るでしょう:

$routes->add('product/(:num)', 'App\Catalog::productLookup');

ルーティングでは、第1引数に一致する URL を、第2引数に再ルーティング先を取ります。上の例では、URL の第1セグメントにリテラル文字列 "product" が、第2セグメントに数値が見つかれば、"AppCatalog" クラスの "productLookup" メソッドが代わりに使用されます。

プレースホルダは正規表現パターンを単純に文字列で替えたものです。ルーティングプロセス中、プレースホルダは正規表現の値に置換されます。これは主に読みやすさのためのものです。

以下のプレースホルダがルーティングで使用できます:

  • (:any) は URL のその位置から最後までのすべての文字に一致します。これは複数の URI セグメントを持ちえます。
  • (:segment) はスラッシュ (/) を除くすべての文字に一致し、結果としてひとつのセグメントに限定します。
  • (:num) はすべての数字に一致します。
  • (:alpha) はすべての英字に一致します。
  • (:alphanum) はすべての英数字に一致します。
  • (:hash) is the same as :segment, but can be used to easily see which routes use hashed ids (see the Model docs).

注釈

{locale} cannot be used as a placeholder or other part of the route, as it is reserved for use in localization.

すこしだけ基本的なルーティングの例をここに示します:

$routes->add('journals', 'App\Blogs');

文字列 "journals" を第1セグメントに持つ URL は "AppBlogs" クラスに再マッピングされます。メソッドはデフォルトのままで、たいていは index() です:

$routes->add('blog/joe', 'Blogs::users/34');

セグメント "blog/joe" を持つ URL は“Blogs”クラスの“users”メソッドに再マッピングされます。 ID には“34”が設定されます:

$routes->add('product/(:any)', 'Catalog::productLookup');

URL の第1セグメントが“product”で第2セグメントが何かしら指定されていれば、“Catalog”クラスの“productLookup”メソッドに再マッピングされます:

$routes->add('product/(:num)', 'Catalog::productLookupByID/$1';

URL の第1セグメントが“product”で第2セグメントが数字なら、“Catalog”クラスの“productLookupByID”メソッドに再マッピングされ、一致した変数がメソッドに渡されます。

重要

add() メソッドはお手軽ですけども、このあと解説する HTTP 動詞をベースとしたルーティングを利用することが常に推奨されます。そのほうがよりセキュアです。It will also provide a slight performance increase, since only routes that match the current request method are stored, resulting in fewer routes to scan through when trying to find a match.

カスタムプレースホルダ

独自のプレースホルダを作成することができます。ルーティングファイル内で利用可能で、読みやすさと使用感を完全にカスタマイズできます。

新しいプレースホルダは addPlaceholder メソッドで追加します。第1引数はプレースホルダとして使う文字列です。第2引数は置換先の正規表現パターンです。 これはルーティングを追加する前に呼び出さなければなりません:

$routes->addPlaceholder('uuid', '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}');
$routes->add('users/(:uuid)', 'Users::show/$1');

正規表現

もしお好みなら、正規表現をルーティングルールに使用することができます。あらゆる正しい正規表現を利用でき、後方参照することができます。

重要

Note: If you use back-references you must use the dollar syntax rather than the double backslash syntax. 典型的な正規表現ルーティングはつぎのような形を取ります:

$routes->add('products/([a-z]+)/(\d+)', '$1::id_$2');

上の例では、products/shirts/123 のような URL は“Shirts”コントローラクラスの“id_123”メソッドを呼び出します。

正規表現を使うとセグメントは、たいてい区切り文字として使われるスラッシュ (‘/’) も取り込んでしまうことができます。

例えば、webアプリケーションでユーザがパスワードで保護されたエリアにアクセスしたとして、ログイン操作後に元のページに戻すリダイレクトを実現したいなら、つぎの例が役に立つでしょう:

$routes->add('login/(.+)', 'Auth::login/$1');

正規表現をよく知らず、これから学びたいのであれば、 regular-expressions.info が良い手始めになるでしょう。

重要

Note: 正規表現にはワイルドカードを混ぜることもできます。

クロージャ

無名関数、つまりクロージャをルーティングのマッピング先に使用することができます。この関数はユーザがその URL にアクセスすると実行されます。これは単純なビューを見せるだけのような小さいタスクの実行に便利です:

$routes->add('feed', function()
{
    $rss = new RSSFeeder();
    return $rss->feed('general');
});

ルーティングをまとめてマッピング

add() メソッドは簡単ですが、一度に複数ルーティングを登録するなら map() メソッドを使うとより便利なことが多いです。ひとつひとつ add() メソッドを呼び出す代わりに、ルーティングの配列を定義し、 map() メソッドの第1引数に渡します:

$routes = [];
$routes['product/(:num)']      = 'Catalog::productLookupById';
$routes['product/(:alphanum)'] = 'Catalog::productLookupByName';

$collection->map($routes);

リダイレクトするルーティング

長生きなサイトはどれでも、ページを移動させてしまっているものです。addRedirect() メソッドを使えば、他のルーティングにリダイレクトする必要のあるルーティングを設定することができます。第1引数は古いルーティングの URL パターンです。第2引数はリダイレクト先の新しい URI、または名前付きルーティングの名前です。第3引数は HTTP ステータスコードで、リダイレクトに合わせて送信する必要のあるものです。デフォルト値は 302 で、一時的なリダイレクトを示します。多くの場合に推奨されます:

$routes->add('users/profile', 'Users::profile', ['as' => 'profile']);

// 名前付きルーティングへのリダイレクト
$routes->addRedirect('users/about', 'profile');
// URI へのリダイレクト
$routes->addRedirect('users/about', 'users/profile');

ページの読込中にリダイレクトルーティングにマッチしたなら、ユーザはすぐにリダイレクトされます。コントローラが読み込まれる前です。

ルーティングのグルーピング

group() メソッドを使うと、ルーティングを共通の名前でグルーピングすることができます。グループ名は、グループ内で定義しているルーティングのセグメントの前に現れます。これは、開始文字列がまったく共通のルーティングでそれが多いとき、タイピングの手間を減らしてくれます。例えば管理画面を作るときなどです:

$routes->group('admin', function($routes)
{
        $routes->add('users', 'Admin\Users::index');
        $routes->add('blog', 'Admin\Blog::index');
});

これは 'users' と 'blog' の URI に "admin" のプレフィックスがつきます。操作する URL は /admin/users/admin/blog のようなものです。 必要であれば、より細かい整理のためにグループをネストすることができます:

$routes->group('admin', function($routes)
{
        $routes->group('users', function($routes)
        {
                $routes->add('list', 'Admin\Users::list');
        });

});

これは URL admin/users/list を取ります。

If you need to assign options to a group, like a namespace, do it before the callback:

$routes->group('api', ['namespace' => 'App\API\v1'], function($routes)
{
        $routes->resource('users');
});

This would handle a resource route to the App\API\v1\Users controller with the /api/users URI.

You can also use ensure that a specific filter runs for a group of routes. This will always run the filter before or after the controller. This is especially handy during authentication or api logging:

$routes->group('api', ['filter' => 'api-auth'], function($routes)
{
    $routes->resource('users');
});

The value for the filter must match one of the aliases defined within app/Config/Filters.php.

環境による制限

You can create a set of routes that will only be viewable in a certain environment. これによって、開発者のローカルマシンでしか使えず、テスト用または本番環境では使えないツールを作ることができるようになります。 これには environment() メソッドを使います。第1引数は環境名です。クロージャ内で定義されたあらゆるルーティングはその環境でしかアクセスできません:

$routes->environment('development', function($routes)
{
        $routes->add('builder', 'Tools\Builder::index');
});

ルーティングの逆引き

ルーティングの逆引きは、コントローラとメソッドの定義とパラメータからリンクを作ることができます。現在のルーティングから引いてきます。これはアプリケーションの修正なしにルーティング定義を変更することを可能にします。これは典型的にはビューの中でリンクを作るのに使用されます。

例えば、フォトギャラリーにリンクしたいとすると、 route_to() ヘルパ関数で貼るべきリンク先を取得できます。第1引数は要件を満たしたコントローラ・メソッド名です。ダブルコロン (::) 区切りで、ちょうどルーティング初期化で書いたようにします。ルーティングに渡すほかの引数は次のように渡します:

// ルーティングはこのように定義されています:
$routes->add('users/(:id)/gallery(:any)', 'App\Controllers\Galleries::showUserGallery/$1/$2');

// ユーザ ID が 15、ギャラリー 12 の相対 URL を生成します
// 生成結果: /users/15/gallery/12
<a href="<?= route_to('App\Controllers\Galleries::showUserGallery', 15, 12) ?>">ギャラリーを見る</a>

名前付きルーティングの利用

ルーティングには名前をつけることができ、アプリケーションの崩れやすさを抑えられます。ルーティングに名前をつけることで後からその名前で呼び出せるようにします。それにより例えルーティング定義が変わったとしても、アプリケーションの route_to で作ったすべてのリンクは修正なしに動作し続けられます。ルーティングは as オプションで名前をつけられます:

// ルーティングは次のように定義されています:
$routes->add('users/(:id)/gallery(:any)', 'Galleries::showUserGallery/$1/$2', ['as' => 'user_gallery');

// Generate the relative URL to link to user ID 15, gallery 12
// Generates: /users/15/gallery/12
<a href="<?= route_to('user_gallery', 15, 12) ?>">View Gallery</a>

また、これで読みやすくもなります。

HTTP 動詞のルーティングでの利用

HTTP 動詞(リクエストメソッド)をルーティングルール定義に使用することができます。これは特に RESTful アプリケーションを作る際に有用です。標準の HTTP 動詞(GET、POST、PUT、DELETEなど)はどれでも使えます。 それぞれの動詞にはそれぞれにメソッドがあります:

$routes->get('products', 'Product::feature');
$routes->post('products', 'Product::feature');
$routes->put('products/(:num)', 'Product::feature');
$routes->delete('products/(:num)', 'Product::feature');

ルーティングが一致する必要のある複数の動詞を配列にして match メソッドに渡すことができます:

$routes->match(['get', 'put'], 'products', 'Product::feature');

コマンドラインだけのルーティング

webブラウザからはアクセスできず、コマンドラインからのみ動作するルーティングを作ることができます。cli() メソッドを使います。これは cron ジョブまたは CLI だけのツールを作るのにすごく良いです。HTTP 動詞ベースのあらゆるルーティングは CLI からのアクセスも制限しますが、any() メソッドで作られたルーティングはコマンドラインからのアクセスも可能です:

$routes->cli('migrate', 'App\Database::migrate');

リソースのルーティング

ひとつのリソースに対する最低限の RESTful ルーティング は resource() メソッドで手早く生成できます。これは、リソースの完全な CRUD に必要な、とても一般的な5つのルーティングを作ります: 新しいリソースの作成、存在するリソースの更新、リソースすべての一覧、単一のリソースの表示、単一のリソースの削除、です。第1引数はリソース名です:

$routes->resource('photos');

// Equivalent to the following:
$routes->get('photos',                 'Photos::index');
$routes->get('photos/new',             'Photos::new');
$routes->get('photos/(:segment)/edit', 'Photos::edit/$1');
$routes->get('photos/(:segment)',      'Photos::show/$1');
$routes->post('photos',                'Photos::create');
$routes->patch('photos/(:segment)',    'Photos::update/$1');
$routes->put('photos/(:segment)',      'Photos::update/$1');
$routes->delete('photos/(:segment)',   'Photos::delete/$1');

重要

The routes are matched in the order they are specified, so if you have resource photos above a get 'photos/poll' the show action's route for the resource line will be matched before the get line. To fix this, move the get line above the resource line so that it is matched first.

第2引数には生成ルーティングを編集するオプション配列を受け取ります。これらのルーティングは API の用途には機能しますが、多くのメソッドを許可しているところでの話です。'websafe' オプションを使うと、update および delete メソッドを HTML フォームでも動くようにルーティングを生成します:

$routes->resource('photos', ['websafe' => 1]);

// つぎのものと同等のルーティングを作ります:
$routes->post('photos/(:segment)',        'Photos::update/$1');
$routes->post('photos/(:segment)/delete', 'Photos::delete/$1');

使用するコントローラの変更

controller オプションで使用されるコントローラを指定することができます:

$routes->resource('photos', ['controller' =>'App\Gallery']);

// Would create routes like:
$routes->get('photos', 'App\Gallery::index');

使用するプレースホルダの変更

デフォルトでは segment プレースホルダがリソース ID に使われます。placeholder オプションでこれを変更できます:

$routes->resource('photos', ['placeholder' => '(:id)']);

// 次のようなルーティングを生成します:
$routes->get('photos/(:id)', 'Photos::show/$1');

生成するルーティングの限定

only オプションで生成されるルーティングを制限できます。This should be an array or comma separated list of method names that should be created. それらのどれかに一致するルーティングのみが生成されます。残りは無視されます:

$routes->resource('photos', ['only' => ['index', 'show']]);

Otherwise you can remove unused routes with the except option. This option run after only:

$routes->resource('photos', ['except' => 'new,edit']);

Valid methods are: index, show, create, update, new, edit and delete.

広範囲のオプション

All of the methods for creating a route (add, get, post, resource, etc) can take an array of options that can modify the generated routes, or further restrict them. $options 配列は常に引数の最後です:

$routes->add('from', 'to', $options);
$routes->get('from', 'to', $options);
$routes->post('from', 'to', $options);
$routes->put('from', 'to', $options);
$routes->head('from', 'to', $options);
$routes->options('from', 'to', $options);
$routes->delete('from', 'to', $options);
$routes->patch('from', 'to', $options);
$routes->match(['get', 'put'], 'from', 'to', $options);
$routes->resource('photos', $options);
$routes->map($array, $options);
$routes->group('name', $options, function());

Applying Filters

You can alter the behavior of specific routes by supplying a filter to run before or after the controller. This is especially handy during authentication or api logging:

$routes->add('admin',' AdminController::index', ['filter' => 'admin-auth']);

The value for the filter must match one of the aliases defined within app/Config/Filters.php. You may also supply parameters to be passed to the filter's before() and after() methods:

$routes->add('users/delete/(:segment)', 'AdminController::index', ['filter' => 'admin-auth:dual,noreturn']);

See Controller filters for more information on setting up filters.

名前空間の割り当て

デフォルトの名前空間がコントローラの前につけられますが(後述参照)、異なる名前空間を namespace オプションで指定することもできます。変更したい名前空間を値とします:

// \Admin\Users::index() へのルーティング
$routes->add('admin/users', 'Users::index', ['namespace' => 'Admin']);

get、postなどのような単一のルーティングを作るメソッドすべてについて、新しい名前空間は呼び出したものにだけ適用されます。 複数のルーティングを作るメソッドについて、新しい名前空間はそのメソッドで作るすべての生成ルーティングに対して適用されます。group() についてはクロージャで作成する全てに適用されます。

ホスト名の限定

ルーティングのグループを特定のドメインまたはサブドメインでのみ機能するように制限することができます。"hostname" オプションに許可が必要なドメインを渡し、オプション配列の一部としてください:

$collection->get('from', 'to', ['hostname' => 'accounts.example.com']);

この例では "accounts.example.com" に正確に一致するホストでのみ動作します。 "example.com" では動きません。

サブドメインの限定

subdomain オプションが渡されたら、そのサブドメインでのみルーティングが有効になります。ルーティングはそのサブドメイン経由で見ている場合だけマッチするようになります:

// media.example.com に限定する
$routes->add('from', 'to', ['subdomain' => 'media']);

値にアスタリスク (*) を使うと、あらゆるサブドメインに制限することができます。サブドメインのついていない URL で見ようとしても、これはマッチしません:

// サブドメインに限定する
$routes->add('from', 'to', ['subdomain' => '*']);

重要

この仕組みは不完全であり、本番環境で使う前にそのドメインでのテストをする必要があります。 ほとんどのドメインでは動作しますが、いくつかの極端なケースでは動きません。とりわけ、ドメインそれ自体にピリオドを含む場合(属性型ドメインやwwwを使っていない場合)は誤った判定をする可能性があります。

一致パラメータの位置ずらし

ルーティング内で一致したパラメータのオフセットを offset オプションに数値を渡すことで変更できます。値にはオフセットするセグメント数を使います。

これは API の URL 第1セグメントにバージョン番号を使いたいときに効力を発揮します。第1パラメータに言語の文字列を指定する場合にも使えます:

$routes->get('users/(:num)', 'users/show/$1', ['offset' => 1]);

// Creates:
$routes['users/(:num)'] = 'users/show/$2';

ルーティングの設定オプション

RoutesCollection クラスにはルーティング全体に影響するいくつかのオプションがあり、アプリケーションの必要に合わせて変更することができます。These options are available at the top of /app/Config/Routes.php.

デフォルト名前空間

ルーティングにコントローラをマッチさせるとき、ルータはデフォルトの名前空間を指定のコントローラの前にくっつけます。デフォルトではこの値は空であり、それぞれのルーティングを完全な名前空間で修飾されたコントローラ名にします:

$routes->setDefaultNamespace('');

// Controller is \Users
$routes->add('users', 'Users::index');

// Controller is \Admin\Users
$routes->add('users', 'Admin\Users::index');

コントローラに明示的な名前空間をつけていないなら、変更する必要はありません。コントローラに名前空間をつけているなら、この値を変えればタイピングの手間が省けるでしょう:

$routes->setDefaultNamespace('App');

// コントローラは \App\Users
$routes->add('users', 'Users::index');

// コントローラは \App\Admin\Users
$routes->add('users', 'Admin\Users::index');

デフォルトコントローラ

サイトのルートを表示した場合(例: example.com)、明示的なルーティングが存在しない限り、setDefaultController() メソッドの値で使用するコントローラが決まります。The default value for this is Home which matches the controller at /app/Controllers/Home.php:

// example.com routes to app/Controllers/Welcome.php
$routes->setDefaultController('Welcome');

また、デフォルトコントローラはルーティングにマッチしなかった場合にも使用されます。URI はコントローラディレクトリ内のディレクトリを指し示します。For example, if the user visits example.com/admin, if a controller was found at /app/Controllers/admin/Home.php it would be used.

デフォルトメソッド

これはデフォルトコントローラの設定と同じように動きますが、デフォルトメソッドを決定するのに使用します。URI に一致したコントローラが見つかり、しかしメソッドを決めるセグメントがない場合に使用されます。デフォルト値は index です:

$routes->setDefaultMethod('listAll');

この例では、ユーザが example.com/products を表示して、Products コントローラがあった場合、Products::listAll() メソッドが実行されます。

URI ダッシュの変換

このオプションは URI セグメントのうちコントローラとメソッドのダッシュ (‘-‘) を自動的にアンダースコアに変換します。そのためそれが必要な場合、ルーティングの追加を省くことができます。This is required because the dash isn’t a valid class or method name character and would cause a fatal error if you try to use it:

$routes->setTranslateURIDashes(true);

定義したルーティングのみの使用

URI が定義済みのルーティングにマッチしなかった場合、上述したようにシステムは URI に一致するコントローラとメソッドがないかを試します。この自動マッチングは無効化できます。setAutoRoute() オプションを false にすることで、定義されたルーティングのみに制限できます:

$routes->setAutoRoute(false);

404のオーバーライド

現在の URI に一致するページが見つからなかった場合、システムは共通の 404 ページを表示します。set404Override() オプションにアクションを指定することで、その挙動を変更することができます。この値は、他のルーティングで指定しているような有効なクラス・メソッドの組み合わせ、またはクロージャのどちらかです:

// App\Errors クラスの show404 メソッドが実行されます
$routes->set404Override('App\Errors::show404');

// Will display a custom view
$routes->set404Override(function()
{
    echo view('my_errors/not_found.html');
});