基本的なルーティング
一番基本のLaravelルートはURIと「クロージャ」により定義され、単純で記述しやすいルートの定義方法を提供しています。
Route::get('foo', function () {
return 'Hello World';
});
デフォルトルート定義ファイル
Laravelの全ルートは、routes
ディレクトリ下に設置されている、ルートファイルで定義されます。これらのファイルはフレームワークにより、自動的に読み込まれます。routes/web.php
ファイルで、Webインターフェイスのルートを定義します。定義されたルートはweb
ミドルウェアグループにアサインされ、セッション状態やCSRF保護などの機能が提供されます。routes/api.php
中のルートはステートレスで、api
ミドルウェアグループにアサインされます。
ほとんどのアプリケーションでは、routes/web.php
ファイルからルート定義を始めます。routes/web.php
中で定義されたルートは、ブラウザで定義したルートのURLを入力することでアクセスします。たとえば、次のルートはブラウザからhttp://your-app.test/user
でアクセスします。
Route::get('/user', 'UserController@index');
routes/api.php
ファイル中で定義したルートはRouteServiceProvider
により、ルートグループの中にネストされます。このグループには、/api
のURIが自動的にプレフィックスされ、それによりこのファイル中の全ルートにわざわざ指定する必要はありません。プレフィックスや他のルートグループオプションに変更する場合は、RouteServiceProvider
を変更してください。
使用可能なルート定義メソッド
ルータは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('/', function () {
//
});
CSRF保護
web
ルートファイル中で定義され、POST
、PUT
、PATCH
、DELETE
ルートへ送信されるHTMLフォームはすべて、CSRFトークンフィールドを含んでいる必要があります。含めていないと、そのリクエストは拒否されます。CSRF保護についての詳細は、CSRFのドキュメントをご覧ください。
<form method="POST" action="/profile">
@csrf
...
</form>
リダイレクトルート
他のURIへリダイレクトするルートを定義する場合は、Route::redirect
メソッドを使用します。このメソッドは便利な短縮形を提供しているので、単純なリダイレクトを実行するために、完全なルートやコントローラを定義する必要はありません。
Route::redirect('/here', '/there');
Route::redirect
はデフォルトで、302
ステータスコードを返します。オプションの第3引数を利用し、ステータスコードをカスタマイズできます。
Route::redirect('/here', '/there', 301);
Route::permanentRedirect
メソッドを使えば、301
ステータスコードが返されます。
Route::permanentRedirect('/here', '/there');
ビュールート
ルートからビューを返すだけの場合は、Route::view
メソッドを使用します。redirect
メソッドと同様に、このメソッドはシンプルな短縮形を提供しており、完全なルートやコントローラを定義する必要はありません。view
メソッドは、最初の引数にURIを取り、ビュー名は第2引数です。さらに、オプションの第3引数として、ビューへ渡すデータの配列を指定することもできます。
Route::view('/welcome', 'welcome');
Route::view('/welcome', 'welcome', ['name' => 'Taylor']);
ルートパラメーター
必須パラメータ
ルートの中の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
メソッドの中で、このようなパターンを定義します。
/**
* ルートモデル結合、パターンフィルタなどの定義
*
* @return void
*/
public function boot()
{
Route::pattern('id', '[0-9]+');
parent::boot();
}
パターンを定義すると、パラメータ名を使用している全ルートで、自動的に提供されます。
Route::get('user/{id}', function ($id) {
// {id}が数値の場合のみ実行される
});
スラッシュのエンコード
Laravelのルーティングコンポーネントは、/
を除くすべての文字を許可しています。プレースホルダの一部として、明確に/
を許可する場合は、where
で正規表現の条件を指定します。
Route::get('search/{search}', function ($search) {
return $search;
})->where('search', '.*');
Note: スラッシュのエンコードは、最後のルートセグメントでのみサポートしています。
名前付きルート
名前付きルートは特定のルートへのURLを生成したり、リダイレクトしたりする場合に便利です。ルート定義にname
メソッドをチェーンすることで、そのルートに名前がつけられます。
Route::get('user/profile', function () {
//
})->name('profile');
コントローラアクションに対しても名前を付けることができます。
Route::get('user/profile', 'UserProfileController@show')->name('profile');
Note: ルート名は常に一意にしてください。
名前付きルートへのURLを生成する
ルートに一度名前を付ければ、その名前をグローバルなroute
関数で使用すれば、URLを生成したり、リダイレクトしたりできます。
// URLの生成
$url = route('profile');
// リダイレクトの生成
return redirect()->route('profile');
そのルートでパラメーターを定義してある場合は、route
関数の第2引数としてパラメーターを渡してください。指定されたパラメーターは自動的にURLの正しい場所へ埋め込まれます。
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1]);
配列に追加のパラメーターを渡した場合、そうしたキー/値ペアは自動的にクエリ文字列として生成されるURLへ追加されます。
Route::get('user/{id}/profile', function ($id) {
//
})->name('profile');
$url = route('profile', ['id' => 1, 'photos' => 'yes']);
// /user/1/profile?photos=yes
Tip!! たとえば現在のローケルのように、URLパラメータへ複数回のリクエスト間に渡るデフォルト値を指定したい場合も時々あります。このためには、
URL::defaults
メソッドを使用して下さい。
現在ルートの検査
現在のリクエストが指定した名前付きルートのものであるかを判定したい場合は、Routeインスタンスのnamed
メソッドを使います。たとえば、ルートミドルウェアから、現在のルート名を判定できます。
/**
* 送信されたリクエストの処理
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if ($request->route()->named('profile')) {
//
}
return $next($request);
}
ルートグループ
ルートグループは多くのルートで共通なミドルウェアや名前空間のようなルート属性をルートごとに定義するのではなく、一括して適用するための手法です。Route::group
メソッドの最初の引数には、共通の属性を配列で指定します。
グループをネストさせると、親のグループに対して属性をできるだけ賢く「マージ」します。ミドルウェアとwhere
条件はマージし、名前、名前空間、プレフィックスは追加します。名前空間のデリミタと、URIプレフィックス中のスラッシュは、自動的で適切に追加されます。
ミドルウェア
グループ中の全ルートにミドルウェアを指定するには、そのグループを定義する前にmiddleware
メソッドを使用します。ミドルウェアは、配列に定義された順番で実行されます。
Route::middleware(['first', 'second'])->group(function () {
Route::get('/', function () {
// firstとsecondミドルウェアを使用
});
Route::get('user/profile', function () {
// firstとsecondミドルウェアを使用
});
});
名前空間
ルートグループのもう一つのよくあるユースケースで、グループ内のコントローラに同じPHP名前空間を指定する場合は、namespace
メソッドを使用します。
Route::namespace('Admin')->group(function () {
// "App\Http\Controllers\Admin"名前空間下のコントローラ
});
App\Http\Controllers
名前空間をコントローラルート登録時に毎回指定しなくても済むように、デフォルトでRouteServiceProvider
が名前空間グループの中でroutes.php
ファイルを読み込み、指定していることを覚えておいてください。これにより、先頭のApp\Http\Controllers
名前空間を省略でき、続きの部分を指定するだけで済みます。
サブドメインルーティング
ルートグループはワイルドカードサブドメインをルート定義するためにも使えます。サブドメインの部分を取り出しルートやコントローラで使用するために、ルートURIにおけるルートパラメーターのように指定できます。サブドメインはグループを定義する前に、domain
メソッドを呼び出し指定します。
Route::domain('{account}.myapp.com')->group(function () {
Route::get('user/{id}', function ($account, $id) {
//
});
});
Note: サブドメインルートまで処理を確実に届けるには、ルートドメインルートより前にサブドメインルートを登録する必要があります。これにより、同じURIパスに対するサブドメインルートがルートドメインルートによりオーバーライドされるのを防げます。
ルートプレフィックス
prefix
メソッドはグループ内の各ルートに対して、指定されたURIのプレフィックスを指定するために使用します。たとえばグループ内の全ルートのURIにadmin
を付けたければ、次のように指定します。
Route::prefix('admin')->group(function () {
Route::get('users', function () {
// Matches The "/admin/users" URL
});
});
ルート名プリフィックス
name
メソッドはグループ内の各ルート名へ、指定した文字列をプレフィックスするために使用します。たとえば、グループ内の全ルート名へadmin
というプレフィックスを付けたいとしましょう。指定した指定した文字列はそのままルート名の前に付きます。そのため、プレフィックスへ最後の.
文字を確実に指定してください。
Route::name('admin.')->group(function () {
Route::get('users', function () {
// "admin.users"という名前へ結合したルート…
})->name('users');
});
モデル結合ルート
ルートかコントローラアクションへモデルIDが指定される場合、IDに対応するそのモデルを取得するため、大抵の場合クエリします。Laravelのモデル結合はルートへ直接、そのモデルインスタンスを自動的に注入する便利な手法を提供しています。つまり、ユーザーのIDが渡される代わりに、指定されたIDに一致するUser
モデルインスタンスが渡されます。
暗黙の結合
Laravelはタイプヒントされた変数名とルートセグメント名が一致する場合、Laravelはルートかコントローラアクション中にEloquentモデルが定義されていると、自動的に依存解決します。
Route::get('api/users/{user}', function (App\User $user) {
return $user->email;
});
$user
変数がApp\User
Eloquentモデルとしてタイプヒントされており、変数名が{user}
URIセグメントと一致しているため、Laravelは、リクエストされたURIの対応する値に一致するIDを持つ、モデルインスタンスを自動的に注入します。一致するモデルインスタンスがデータベースへ存在しない場合、404
HTTPレスポンスが自動的に生成されます。
キーのカスタマイズ
id
以外のカラムを使用するEloquentモデルでも暗黙の結合を使いたい場合があるでしょう。それには、ルートパラメータ定義でカラムを指定してください。
Route::get('api/posts/{post:slug}', function (App\Post $post) {
return $post;
});
カスタムキーと取得
一つの定義中に複数のEloquentモデルを暗黙的に結合し、2つ目のEloquentモデルが最初のEloquentモデルの子である必要がある場合などでは、その2つ目のモデルを取得したいと思うでしょう。例として、特定のユーザーのブログポストをスラグで取得する場合を想像してください。
use App\Post;
use App\User;
Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
return $post;
});
カスタムなキーを付けた暗黙の結合をネストしたルートパラメータで使用するとき、親で定義されるリレーションは慣習にしたがい名付けられているだろうとLaravelは推測し、ネストしたモデルへのクエリを自動的に制約します。この場合、User
モデルにはPost
モデルを取得するためにposts
(ルートパラメータ名の複数形)という名前のリレーションがあると想定します。
デフォルトキー名のカスタマイズ
特定のモデルの取得時に、id
以外のデフォルトデータベースカラム名を使用しモデル結合したい場合は、そのEloquentモデルのgetRouteKeyName
メソッドをオーバーライドしてください。
/**
* モデルのルートキーの取得
*
* @return string
*/
public function getRouteKeyName()
{
return 'slug';
}
明示的な結合
明示的に結合を登録するには、ルータのmodel
メソッドで、渡されるパラメータに対するクラスを指定します。RouteServiceProvider
クラスのboot
メソッドの中で明示的なモデル結合を定義してください。
public function boot()
{
parent::boot();
Route::model('user', App\User::class);
}
次に{user}
パラメーターを含むルートを定義します。
Route::get('profile/{user}', function (App\User $user) {
//
});
{user}
パラメーターをApp\User
モデルへ結合しているため、User
インスタンスはルートへ注入されます。ですからたとえば、profile/1
のリクエストでは、IDが1
のUser
インスタンスが注入されます。
一致するモデルインスタンスがデータベース上に見つからない場合、404 HTTPレスポンスが自動的に生成されます。
依存解決ロジックのカスタマイズ
独自の依存解決ロジックを使いたい場合は、Route::bind
メソッドを使います。bind
メソッドに渡す「クロージャ」は、URIセグメントの値を受け取るので、ルートへ注入したいクラスのインスタンスを返してください。
/**
* アプリケーションサービスの初期処理
*
* @return void
*/
public function boot()
{
parent::boot();
Route::bind('user', function ($value) {
return App\User::where('name', $value)->firstOrFail();
});
}
別の方法として、EloquentモデルのresolveRouteBinding
メソッドをオーバーライドすることもできます。このメソッドはURIセグメントの値を受け取り、ルートへ注入すべきクラスのインスタンスを返す必要があります。
/**
* 結合値のモデル取得
*
* @param mixed $value
* @param string|null $field
* @return \Illuminate\Database\Eloquent\Model|null
*/
public function resolveRouteBinding($value, $field = null)
{
return $this->where('name', $value)->firstOrFail();
}
フォールバックルート
Route::fallback
メソッドを使用すれば、受け取ったリクエストが他のルートと一致しない場合に、実行するルートを定義できます。通常、アプリケーションの例外ハンドラにより、処理できないリクエストに対し自動的に"404"ページがレンダーされます。しかしながら、routes/web.php
ファイルにfallback
ルートが定義されていれば、web
ミドルウェアグループの中のすべてのミドルウェアで、このルートが適用されます。必要に応じ、このルートを他のミドルウェアに追加するかどうかは、皆さんの自由です。
Route::fallback(function () {
//
});
Note: フォールバックルートは、アプリケーションのルート登録で常に一番最後に行わなければなりません。
レート制限
Laravelには、アプリケーションのルートに対してレート制限をかけるミドルウェア
が用意されています。使用開始するには、ルートやルートグループに対し、throttle
ミドルウェアを指定してください。throttle
ミドルウェアは分数と、その時間内に許す最大リクエスト数の、2引数を取ります。例として、認証済みのユーザーが1分間に60回のアクセスを許すルートグループを指定してみましょう。
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
Route::get('/user', function () {
//
});
});
動的レート制限
認証済みUser
モデルの属性に基づいて、最大リクエストを動的に指定することもできます。たとえば、User
モデルがrate_limit
属性を含んでいる場合、最大リクエストの算出で使用するために、throttle
ミドルウェアにその属性の名前を渡します。
Route::middleware('auth:api', 'throttle:rate_limit,1')->group(function () {
Route::get('/user', function () {
//
});
});
ゲストと認証ユーザー別のレート制限
ゲストと認証済みユーザーで別のレート制限を適用できます。たとえば、ゲストには1分間に最大10
回、認証済みユーザーでは最大60
回を指定するとしましょう。
Route::middleware('throttle:10|60,1')->group(function () {
//
});
この機能を動的レート制限と組み合わせることもできます。たとえばUser
モデルにrate_limit
属性があるとして、この属性名をthrottle
ミドルウェアへ渡し、その認証ユーザーの最大リクエスト回数を指定するために使うことができます。
Route::middleware('auth:api', 'throttle:10|rate_limit,1')->group(function () {
Route::get('/user', function () {
//
});
});
レート制限区分
通常、アプリケーション全体のAPIに対し1つのレート制限を指定します。しかしながら、アプリケーションの別々の区分に別個の制限が必要になる場合もあります。このようなケースでは、throttle
ミドルウェアの第3引数にセグメント名を渡してください。
Route::middleware('auth:api')->group(function () {
Route::middleware('throttle:60,1,default')->group(function () {
Route::get('/servers', function () {
//
});
});
Route::middleware('throttle:60,1,deletes')->group(function () {
Route::delete('/servers/{id}', function () {
//
});
});
});
擬似フォームメソッド
HTMLフォームは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
Bladeディレクティブを使用することもできます。
<form action="/foo/bar" method="POST">
@method('PUT')
@csrf
</form>
現在のルートへのアクセス
送信されたリクエストを処理しているルートに関する情報へアクセスするには、Route
ファサードへcurrent
、currentRouteName
、currentRouteAction
メソッドを使用します。
$route = Route::current();
$name = Route::currentRouteName();
$action = Route::currentRouteAction();
組み込まれている全メソッドを確認するには、Routeファサードの裏で動作しているクラスと、Routeインスタンスの2つについてのAPIドキュメントを参照してください。
Cross-Origin Resource Sharing (CORS)
Laravelは指定値に従い自動的にCORSオプションリクエストへ対応します。CORSの設定はすべてcors
設定ファイルで行われ、オプションリクエストはグローバルミドルウェアスタックにデフォルトで含まれるHandleCors
ミドルウェアにより自動的に処理されます。
Tip!! CORSとそのヘッダの詳細は、CROSに関するMDN Webドキュメンテーションで調べてください。