基本的なルーティング
Laravelの全ルートは、フレームワークが自動的に読み込むapp/Http/routes.php
ファイル中で定義されます。一番基本のLaravelルートはシンプルにURIと「クロージャ」により定義され、単純で記述しやすいルートの定義方法を提供しています。
Route::get('foo', function () {
return 'Hello World';
});
デフォルトルート定義ファイル
デフォルトのroutes.php
ファイルはRouteServiceProvider
により読み込まれ、セッションステータスへのアクセスとCSRF保護を提供するweb
ミドルウェアが自動的に適用されます。アプリケーションの殆どのルートは、このファイルで定義されるでしょう。
使用可能なルート定義メソッド
ルータはHTTP動詞に対応してルートを定義できるようにしています。
Route::get($uri, $callback);
Route::post($uri, $callback);
Route::put($uri, $callback);
Route::patch($uri, $callback);
Route::delete($uri, $callback);
Route::options($uri, $callback);
複数のHTTP動詞に対応したルートを登録する必要が起きることもあります。match
メソッドが利用できます。もしくは全HTTP動詞に対応するany
メソッドを使い、ルート登録することもできます。
Route::match(['get', 'post'], '/', function () {
//
});
Route::any('foo', function () {
//
});
ルートパラメーター
必須パラメータ
もちろん、ルートの中のURIセグメントを取り出す必要が起きることもあります。たとえば、URLからユーザIDを取り出したい場合です。ルートパラメーターを定義してください。
Route::get('user/{id}', function ($id) {
return 'User '.$id;
});
ルートで必要なだけのルートパラメーターを定義することができます。
Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) {
//
});
ルートパラメーターは常に波括弧で囲います。パラメーターはそのルートが実行される時に「クロージャ」に渡されます。
注意: ルートパラメーターは
-
文字を含むことができません。代わりに下線(_
)を使ってください。
任意パラメータ
ルートパラメータを指定してもらう必要があるが、指定は任意にしたいこともよく起こります。パラメータ名の後に?
を付けると、任意指定のパラメータになります。対応するルートの引数に、デフォルト値を必ず付けてください。
Route::get('user/{name?}', function ($name = null) {
return $name;
});
Route::get('user/{name?}', function ($name = 'John') {
return $name;
});
正規表現による限定
ルート定義でwhere
を使用し、一致するルートパラメーターのフォーマットを限定することができます。where
メソッドはパラメーターの名前と、どのように限定するかを表す正規表現を引数に取ります。
Route::get('user/{name}', function ($name) {
//
})
->where('name', '[A-Za-z]+');
Route::get('user/{id}', function ($id) {
//
})
->where('id', '[0-9]+');
Route::get('user/{id}/{name}', function ($id, $name) {
//
})
->where(['id' => '[0-9]+', 'name' => '[a-z]+']);
グローバルな限定
ある名前のルートパラメーターをいつも正規表現で限定したい場合は、pattern
メソッドを使用してください。RouteServiceProvider
のboot
メソッドでこうしたパターンを定義してください。
/**
* ルートモデルの結合、パターンフィルタなどの定義
*
* @param \Illuminate\Routing\Router $router
* @return void
*/
public function boot(Router $router)
{
$router->pattern('id', '[0-9]+');
parent::boot($router);
}
パターンを一度定義すれば、そのパラメーター名を使用している全ルートで自動的に適用されます。
Route::get('user/{id}', function ($id) {
// Only called if {id} is numeric.
});
名前付きルート
名前付きルートは特定のルートへのURLを生成したり、リダイレクトしたりする場合に便利です。ルートを定義するときに、as
配列キーを使用して名前を指定してください。
Route::get('user/profile', ['as' => 'profile', function () {
//
}]);
コントローラーアクションに対しても名前を付けることができます。
Route::get('user/profile', [
'as' => 'profile', 'uses' => 'UserController@showProfile'
]);
ルート定義の配列の中でルート名を指定する代わりに、ルート定義の最後にname
メソッドをつなげることもできます。
Route::get('user/profile', 'UserController@showProfile')->name('profile');
ルートグループと名前付きルート
ルートグループを使用している場合、ルートグループの属性配列でas
キーワードを指定し、グループ内の全ルートに共通な名前のプリフィックスを指定することができます。
Route::group(['as' => 'admin::'], function () {
Route::get('dashboard', ['as' => 'dashboard', function () {
// Route named "admin::dashboard"
}]);
});
名前付きルートへのURLを生成する
ルートに一度名前を付ければ、その名前をグローバルなroute
関数で使用することで、URLを生成したり、リダイレクトしたりできます。
// URLの生成
$url = route('profile');
// リダイレクトの生成
return redirect()->route('profile');
そのルートでパラメーターを定義してある場合は、route
関数の第2引数としてパラメーターを渡してください。指定されたパラメーターは自動的にURLの正しい場所へ埋め込まれます。
Route::get('user/{id}/profile', ['as' => 'profile', function ($id) {
//
}]);
$url = route('profile', ['id' => 1]);
ルートグループ
ルートグループは多くのルートで共通なミドルウェアや名前空間のようなルート属性をルートごとに定義するのではなく、一括して適用するための手法です。Route::group
メソッドの最初の引数には、共通の属性を配列で指定します。
ルートグループについてより理解を深めるために、この機能の一般的なユースケースを学んでください。
ミドルウェア
グループの中の全ルートにミドルウェアを指定するには、middleware
キーをグループ属性配列に使用します。この配列で指定した順番にミドルウェアは実行されます。
Route::group(['middleware' => 'auth'], function () {
Route::get('/', function () {
// Authミドルウェアを使用
});
Route::get('user/profile', function () {
// Authミドルウェアを使用
});
});
名前空間
ルートグループのもう一つのよくあるユースケースは、グループ内のコントローラーに同じPHP名前空間を指定する場合です。グループ中の全コントローラーに対して適用する名前空間をグループ属性配列のnamespace
キーを使用し指定します。
Route::group(['namespace' => 'Admin'], function()
{
// "App\Http\Controllers\Admin"名前空間下のコントローラ
Route::group(['namespace' => 'User'], function() {
// "App\Http\Controllers\Admin\User"下のコントローラ
});
});
App\Http\Controllers
名前空間をコントローラールート登録時に毎回指定しなくても済むように、デフォルトでRouteServiceProvider
が名前空間グループの中でroutes.php
ファイルを読み込み、指定していることを覚えておいてください。これにより、先頭のApp\Http\Controllers
名前空間を省略でき、続きの部分を指定するだけで済みます。
サブドメインルーティング
ルートグループはワイルドカードサブドメインをルート定義するためにも使えます。サブドメインの部分を取り出しルートやコントローラーで使用するために、ルートURIにおけるルートパラメーターのように指定できます。サブドメインはグループ属性配列でdomain
キーにより指定します。
Route::group(['domain' => '{account}.myapp.com'], function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
ルートプレフィックス
prefix
グループ配列属性はグループ内の各ルートに対して、指定されたURIのプレフィックスを指定するために使用します。たとえばグループ内の全ルートのURIにadmin
を付けたければ、次のように指定します。
Route::group(['prefix' => 'admin'], function () {
Route::get('users', function () {
// "/admin/users"のURIと一致
});
});
prefix
パラメーターは、グループ内のルートに対して、共通のパラメーターを指定するためにも使用できます。
Route::group(['prefix' => 'accounts/{account_id}'], function () {
Route::get('detail', function ($accountId) {
// "/accounts/{account_id}/detail"のURLと一致
});
});
CSRF保護
イントロダクション
Laravelでは、クロス・サイト・リクエスト・フォージェリ(CSRF)からアプリケーションを簡単に守れます。クロス・サイト・リクエスト・フォージェリは悪意のあるエクスプロイトの一種であり、信頼できるユーザーになり代わり、認められていないコマンドを実行します。
Laravelは、アプリケーションにより管理されているアクティブなユーザーの各セッションごとに、CSRF「トークン」を自動的に生成しています。このトークンを認証済みのユーザーが、実装にアプリケーションに対してリクエストを送信しているのかを確認するために利用します。
アプリケーションでHTMLフォームを定義する場合はいつでも、隠しCSRFトークンフィールドをフォームに埋め込み、CSRF保護ミドルウェアがリクエストの有効性をチェックできるようにしなければなりません。CSRFトークンを含んだ、_token
隠し入力フィールドを生成するには、csrf_field
ヘルパ関数を使ってください。
// 通常のPHPコード
<?php echo csrf_field(); ?>
// Bladeテンプレート記法
{{ csrf_field() }}
csrf_field
ヘルパは、以下のHTMLを生成します。
<input type="hidden" name="_token" value="<?php echo csrf_token(); ?>">
POST、PUT、DELETEリクエストのCSRFトークンを自分で確認する必要はありません。web
ミドルウェアグループに含まれている、VerifyCsrfToken
ミドルウェアが、リクエスト中のトークンとセッションに保存されているトークンが一致するか、確認しています。
CSRF保護から特定URIを除外
一連のURIをCSRF保護より除外したい場合もあります。たとえば、Stripeを料金の受け取りに採用しており、そのWebフックシステムを利用している時は、LaravelのCSRF保護よりWebフック処理ルートを除外する必要があるでしょう。
デフォルトのroutes.php
ファイルで適用されるweb
ミドルウェアグループ外で除外URIを定義するか、もしくはVerifyCsrfToken
ミドルウェアの$except
プロパティにそのURIを追加してください。
<?php
namespace App\Http\Middleware;
use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
class VerifyCsrfToken extends BaseVerifier
{
/**
* CSRFバリデーションから除外するURI
*
* @var array
*/
protected $except = [
'stripe/*',
];
}
X-CSRF-TOKEN
更に追加でPOSTパラメーターとしてCSRFトークンを確認したい場合は、LaravelのVerifyCsrfToken
ミドルウェアがX-CSRF-TOKEN
リクエストヘッダもチェックします。たとえば、"meta"タグにトークンを保存します。
<meta name="csrf-token" content="{{ csrf_token() }}">
meta
タグを作成したら、jQueryのようなライブラリーで、全リクエストヘッダにトークンを追加できます。この手法によりAJAXベースのアプリケーションにシンプルで便利なCSRF保護を提供できます。
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
X-XSRF-TOKEN
Laravelは更にCSRFトークンをXSRF-TOKEN
クッキーの中に保存します。このクッキーの値をX-XSRF-TOKEN
リクエストヘッダにセットすることが可能です。AngularのようなJavaScriptフレームワークでは、自動的に行われます。自動で行われない場合は、手動で値を設定する必要があります。
モデル結合ルート
Laravelのモデル結合ルートはルートへモデルインスタンスを依存注入する便利な手法です。たとえば、ユーザのIDを受け取る代わりに、指定されたIDと一致するUser
モデルインスタンスそのものを依存注入で受け取れます。
暗黙の結合
Laravelは変数名とルートセグメント名が一致する場合、LaravelはルートかコントローラアクションでEloquentモデルが定義されていると、自動的に依存解決します。
Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});
この例では、Eloquentをタイプヒントしているルート上の$user
変数が、ルートURIの{user}
セグメントと名前が一致しているので、LaravelはリクエストURI上の対応するIDを持つ、モデルインスタンスを自動的に依存注入します。
一致するモデルインスタンスがデータベース上に見つからない場合、404 HTTPレスポンスが自動的に生成されます。
キー名のカスタマイズ
モデル取得時にid
以外のデータベースカラムを暗黙のモデル結合で使用したい場合、EloquentモデルのgetRouteKeyName
メソッドをオーバーライドしてください。
/**
* モデルのルートキーの取得
*
* @return string
*/
public function getRouteKeyName()
{
return 'slug';
}
明白な結合
明白な結合を登録するときは、指定したパラメータに対するクラスをルータのmodel
メソッドにより登録します。モデルの結合は、RouteServiceProvider::boot
メソッドで定義します。
引数をモデルに結合する
public function boot(Router $router)
{
parent::boot($router);
$router->model('user', 'App\User');
}
次に{user}
パラメーターを含むルートを定義します。
$router->get('profile/{user}', function(App\User $user) {
//
});
{user}
パラメーターをApp\User
モデルへ結合しているため、User
インスタンスはルートへ注入されます。ですからたとえば、profile/1
のリクエストでは、IDが1のインスタンスが注入されます。
一致するモデルインスタンスがデータベース上に見つからない場合、404 HTTPレスポンスが自動的に生成されます。
依存解決ロジックのカスタマイズ
独自の依存解決ロジックを使いたい場合は、Route::bind
メソッドを使います。bind
メソッドに渡す「クロージャ」は、URIセグメントの値を受け取るので、ルートへ注入したいクラスのインスタンスを返してください。
$router->bind('user', function ($value) {
return App\User::where('name', $value)->first();
});
"Not Found"時の振る舞いのカスタマイズ
独自の"Not
Found"時の動作を指定したいときは、model
メソッドの第3引数に「クロージャ」を渡してください。
$router->model('user', 'App\User', function () {
throw new NotFoundHttpException;
});
擬似フォームメソッド
HTLMフォームはPUT
、PATCH
、DELETE
アクションをサポートしていません。ですから、HTMLフォームから呼ばれるPUT
、PATCH
、DELETE
ルートを定義する時、フォームに_method
隠しフィールドを追加する必要があります。_method
フィールドとして送られた値は、HTTPリクエストメソッドとして使用されます。
<form action="/foo/bar" method="POST">
<input type="hidden" name="_method" value="PUT">
<input type="hidden" name="_token" value="{{ csrf_token() }}">
</form>
_method
隠し入力フィールドを生成するために、method_field
ヘルパ関数を使用することもできます。
<?php echo method_field('PUT'); ?>
もちろん、Bladeテンプレートエンジンを使用できます。
{{ method_field('PUT') }}
現在のルートへのアクセス
Route::current()
メソッドは、現在のHTTPリクエストを処理しているルートを返します。これはIlluminate\Routing\Route
インスタンスで、メソッドによりルートの情報を調べることができます。
$route = Route::current();
$name = $route->getName();
$actionName = $route->getActionName();
Route
ファサードのcurrentRouteName
とcurrentRouteAction
ヘルパメソッドも使用でき、現在のルートの名前とアクションへアクセスできます。
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
組み込まれている全メソッドを確認するには、Routeファサードの裏で動作しているクラスと、Routeインスタンスの2つについてのAPIドキュメントを参照してください。