レスポンスの生成
文字列と配列
当然ながらすべてのルートやコントローラは、ユーザーのブラウザに対し、何らかのレスポンスを返す必要があります。Laravelはレスポンスを返すためにさまざまな手段を用意しています。一番基本的なレスポンスは、ルートかコントローラから文字列を返します。フレームワークが自動的に、文字列を完全なHTTPレスポンスへ変換します。
Route::get('/', function () {
return 'Hello World';
});
ルートやコントローラから文字列を返す他に、配列も返せます。フレームワークは自動的に、配列をJSONレスポンスへ変換します。
Route::get('/', function () {
return [1, 2, 3];
});
Note: Eloquentコレクションも返せることを知っていますか? 自動的にJSONへ変換されます。試してください!
レスポンスオブジェクト
通常、皆さんは単純な文字列や配列をルートアクションから返すだけじゃありませんよね。代わりに、Illuminate\Http\Response
インスタンスかビューを返したいですよね。
完全なResponse
インスタンスを返せば、レスポンスのHTTPステータスコードやヘッダをカスタマイズできます。Response
インスタンスは、Symfony\Component\HttpFoundation\Response
クラスを継承しており、HTTPレスポンスを構築するためにさまざまなメソッドを提供しています。
Route::get('/home', function () {
return response('Hello World', 200)
->header('Content-Type', 'text/plain');
});
Eloquentモデルとコレクション
Eloquent ORMモデルとコレクションをルートとコントローラから直接返すこともできます。これを行うと、Laravelはモデルの非表示属性を尊重しながら、モデルやコレクションをJSONレスポンスへ自動的に変換します。
use App\Models\User;
Route::get('/user/{user}', function (User $user) {
return $user;
});
レスポンスへのヘッダ付加
レスポンスインスタンスをスラスラと構築できるように、ほとんどのレスポンスメソッドはチェーンとしてつなげられることを覚えておきましょう。たとえば、ユーザーにレスポンスを送り返す前に、header
メソッドでいくつかのヘッダを追加できます。
return response($content)
->header('Content-Type', $type)
->header('X-Header-One', 'Header Value')
->header('X-Header-Two', 'Header Value');
もしくは、withHeaders
メソッドで、レスポンスへ追加したいヘッダの配列を指定します。
return response($content)
->withHeaders([
'Content-Type' => $type,
'X-Header-One' => 'Header Value',
'X-Header-Two' => 'Header Value',
]);
キャッシュコントロール・ミドルウェア
ルートグループへCache-Control
ヘッダを簡単に指定できるよう、Laravelはcache.headers
を用意しています。ディレクティブは、対応するcache-controlディレクティブの「スネークケース」を使用し、セミコロンで区切って指定してください。ディレクティブのリストの中でetag
を指定すると、レスポンスコンテンツのMD5ハッシュをETag識別子へ自動的にセットします。
Route::middleware('cache.headers:public;max_age=2628000;etag')->group(function () {
Route::get('/privacy', function () {
// ...
});
Route::get('/terms', function () {
// ...
});
});
レスポンスへのクッキー付加
cookie
メソッドを使用して、発信Illuminate\Http\Response
インスタンスへクッキーを添付できます。Cookieが有効であると見なされる名前、値、および分数をメソッドへ渡す必要があります。
return response('Hello World')->cookie(
'name', 'value', $minutes
);
cookie
メソッドはさらに、使用機会が少ない引数をいくつか受け付けます。これらの引数は、全般的にPHPネイティブのsetcookieメソッドに指定する引数と、同じ目的、同じ意味合いを持っています。
return response('Hello World')->cookie(
'name', 'value', $minutes, $path, $domain, $secure, $httpOnly
);
クッキーが送信レスポンスとともに確実に送信したいが、そのレスポンスのインスタンスがまだない場合は、Cookie
ファサードを使用して、送信時にレスポンスへ添付するためにそのクッキーを「キュー」へ投入できます。queue
メソッドは、クッキーインスタンスの作成に必要な引数をとります。こうしたクッキーは、ブラウザへ送信される前に送信レスポンスへ添付します。
use Illuminate\Support\Facades\Cookie;
Cookie::queue('name', 'value', $minutes);
クッキーインスタンスの生成
後ほどレスポンスインスタンスへアタッチできるSymfony\Component\HttpFoundation\Cookie
インスタンスを生成したい場合は、グローバルなcookie
ヘルパを使用します。このCookieは、レスポンスインスタンスへ添付しない限り、クライアントに返送されません。
$cookie = cookie('name', 'value', $minutes);
return response('Hello World')->cookie($cookie);
クッキーの早期期限切れ
送信レスポンスのwithoutCookie
メソッドを介してクッキーを期限切れにすることにより、そのクッキーを削除できます。
return response('Hello World')->withoutCookie('name');
送信レスポンスのインスタンスがまだない場合は、Cookie
ファサードのexpire
メソッドを使用してCookieを期限切れにすることができます。
Cookie::expire('name');
クッキーと暗号化
Laravelにより生成されるクッキーは、クライアントにより変更されたり、読まれたりされないようにデフォルトで暗号化され、署名されます。アプリケーションで生成する特定のクッキーで暗号化を無効にしたい場合は、app/Http/Middleware
ディレクトリ中に存在する、App\Http\Middleware\EncryptCookies
ミドルウェアの$except
プロパティで指定してください。
/**
* 暗号化しないクッキー名
*
* @var array
*/
protected $except = [
'cookie_name',
];
リダイレクト
リダイレクトのレスポンスはIlluminate\Http\RedirectResponse
クラスのインスタンスであり、ユーザーを他のURLへリダイレクトさせるために必要なしっかりとしたヘッダを含んでいます。RedirectResponse
インスタンスを生成するにはさまざまな方法があります。一番簡単な方法は、グローバルなredirect
ヘルパを使う方法です。
Route::get('/dashboard', function () {
return redirect('home/dashboard');
});
送信したフォームが無効な場合など、ユーザーを以前の場所にリダイレクトしたい場合があります。これは、グローバルなback
ヘルパ関数を使用して行うことができます。この機能はセッションを利用するため、back
関数を呼び出すルートがweb
ミドルウェアグループを使用していることを確認してください。
Route::post('/user/profile', function () {
// レスポンスのバリデーション処理…
return back()->withInput();
});
名前付きルートへのリダイレクト
redirect
ヘルパを引数無しで呼ぶと、Illuminate\Routing\Redirector
インスタンスが返され、Redirector
インスタンスのメソッドが呼び出せるようになります。たとえば、名前付きルートに対するRedirectResponse
を生成したい場合は、route
メソッドが使えます。
return redirect()->route('login');
ルートにパラメーターがある場合は、route
メソッドの第2引数として渡してください。
// /profile/{id}のURIを持つルートの場合
return redirect()->route('profile', ['id' => 1]);
Eloquentモデルによる、パラメータの埋め込み
Eloquentモデルの"ID"をルートパラメーターとしてリダイレクトする場合は、モデルをそのまま渡してください。IDは自動的に取り出されます。
// /profile/{id}のURIを持つルートの場合
return redirect()->route('profile', [$user]);
ルートパラメータへ配置する値をカスタマイズする場合は、ルートパラメータ定義(/profile/{id:slug}
)でカラムを指定するか、EloquentモデルのgetRouteKey
メソッドをオーバーライドします。
/**
* モデルのルートキー値の取得
*
* @return mixed
*/
public function getRouteKey()
{
return $this->slug;
}
コントローラアクションへのリダイレクト
コントローラアクションに対するリダイレクトを生成することもできます。そのためには、コントローラとアクションの名前をaction
メソッドに渡してください。
use App\Http\Controllers\UserController;
return redirect()->action([UserController::class, 'index']);
コントローラルートにパラメーターが必要ならば、action
メソッドの第2引数として渡してください。
return redirect()->action(
[UserController::class, 'profile'], ['id' => 1]
);
外部ドメインへのリダイレクト
アプリケーション外のドメインへリダイレクトする必要がときどき起きます。このためにはaway
メソッドを呼び出してください。これはRedirectResponse
を生成しますが、URLエンコードを追加せず、バリデーションも検証も行いません。
return redirect()->away('https://www.google.com');
フラッシュデータを保存するリダイレクト
新しいURLへリダイレクトし、セッションへフラッシュデータを保存するのは、一度にまとめて行われる典型的な作業です。典型的な使い方は、あるアクションが実行成功した後に、実効成功メッセージをフラッシュデータとしてセッションに保存する場合でしょう。これに便利なように、RedirectResponse
インスタンスを生成し、メソッドチェーンを一つだけさっと書けば、データをセッションへ保存できるようになっています。
Route::post('/user/profile', function () {
// …
return redirect('dashboard')->with('status', 'Profile updated!');
});
ユーザーを新しいページヘリダイレクトした後、セッションへ保存したフラッシュデータのメッセージを取り出して、表示します。たとえば、Blade記法を使ってみましょう。
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
入力と共にリダイレクト
ユーザーを新しい場所にリダイレクトする前に、RedirectResponse
インスタンスが提供するwithInput
メソッドを使用して、現在のリクエストの入力データをセッションへ一時保存できます。これは通常、ユーザーがバリデーションエラーに遭遇した場合に行います。入力をセッションに一時保存したら、次のリクエスト中で簡単に取得してフォームを再入力できます。
return back()->withInput();
他のレスポンスタイプ
response
ヘルパは、他のタイプのレスポンスインスタンスを生成するために便利です。response
ヘルパが引数なしで呼び出されると、Illuminate\Contracts\Routing\ResponseFactory
契約が返されます。この契約はレスポンスを生成するための、さまざまなメソッドを提供しています。
Viewレスポンス
レスポンスのステータスやヘッダをコントロールしながらも、レスポンス内容としてビューを返す必要がある場合は、view
メソッドを使用してください。
return response()
->view('hello', $data, 200)
->header('Content-Type', $type);
もちろん、カスタムHTTPステータスコードやカスタムヘッダを渡す必要がない場合は、グローバルなview
ヘルパ関数が使用できます。
JSONレスポンス
json
メソッドは自動的にContent-Type
ヘッダをapplication/json
にセットし、同時に指定された配列をjson_encode
PHP関数によりJSONへ変換します。
return response()->json([
'name' => 'Abigail',
'state' => 'CA',
]);
JSONPレスポンスを生成したい場合は、json
メソッドとwithCallback
メソッドを組み合わせてください。
return response()
->json(['name' => 'Abigail', 'state' => 'CA'])
->withCallback($request->input('callback'));
Fileダウンロード
download
メソッドを使用して、ユーザーのブラウザに対し、指定パスのファイルをダウンロードするように強制するレスポンスを生成できます。download
メソッドは、メソッドの引数の2番目にファイル名を取ります。これにより、ユーザーがファイルをダウンロードするときに表示するファイル名が決まります。最後に、HTTPヘッダの配列をメソッドの3番目の引数として渡すこともできます。
return response()->download($pathToFile);
return response()->download($pathToFile, $name, $headers);
Warning!! ファイルダウンロードを管理しているSymfony HttpFoundationクラスは、ASCIIのダウンロードファイル名を指定するよう要求しています。
ストリームダウンロード
特定の操作の文字列レスポンスを、操作の内容をディスクに書き込まずにダウンロード可能なレスポンスへ変換したい場合もあるでしょう。このシナリオでは、streamDownload
メソッドを使用します。このメソッドは、コールバック、ファイル名、およびオプションのヘッダ配列を引数に取ります。
use App\Services\GitHub;
return response()->streamDownload(function () {
echo GitHub::api('repo')
->contents()
->readme('laravel', 'laravel')['contents'];
}, 'laravel-readme.md');
Fileレスポンス
file
メソッドは、ダウンロードする代わりに、ブラウザへ画像やPDFのようなファイルを表示するために使用します。このメソッドは第1引数にファイルパス、第2引数にヘッダの配列を指定します。
return response()->file($pathToFile);
return response()->file($pathToFile, $headers);
レスポンスマクロ
さまざまなルートやコントローラで再利用できるカスタムレスポンスを定義する場合は、Response
ファサードでmacro
メソッドを使用してください。通常、このメソッドは、App\Providers\AppServiceProvider
サービスプロバイダなど、アプリケーションのサービスプロバイダの1つのboot
メソッドから呼び出す必要があります。
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Response;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* 全アプリケーションサービスの初期起動処理
*
* @return void
*/
public function boot()
{
Response::macro('caps', function ($value) {
return Response::make(strtoupper($value));
});
}
}
macro
関数は、最初の引数に名前を受け入れ、2番目の引数にクロージャを取ります。マクロのクロージャは、ResponseFactory
実装またはresponse
ヘルパからマクロ名を呼び出すときに実行されます。
return response()->caps('foo');