コンテンツへスキップ

コントローラ

イントロダクション

ルートファイル内のクロージャとしてすべてのリクエスト処理ロジックを定義する代わりに、「コントローラ」クラスを使用してこの動作を整理したいと思うかもしれません。コントローラは、関連するリクエスト処理ロジックを単一のクラスにグループ化できます。たとえば、UserControllerクラスは、ユーザーの表示、作成、更新、削除など、ユーザーに関連するすべての受信リクエストを処理します。デフォルトでは、コントローラはapp/Http/Controllersディレクトリに保存されます。

コントローラの記述

基本のコントローラ

新しいコントローラをすばやく生成するには、make:controller Artisanコマンドを実行します。デフォルトでは、アプリケーションのすべてのコントローラはapp/Http/Controllersディレクトリに保存されます。

1php artisan make:controller UserController

基本的なコントローラの例を見てみましょう。コントローラには、受信HTTPリクエストに応答するpublicメソッドをいくつでも含められます。

1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Models\User;
6use Illuminate\View\View;
7 
8class UserController extends Controller
9{
10 /**
11 * Show the profile for a given user.
12 */
13 public function show(string $id): View
14 {
15 return view('user.profile', [
16 'user' => User::findOrFail($id)
17 ]);
18 }
19}

コントローラクラスとメソッドを記述したら、次のようにコントローラメソッドへのルートを定義できます。

1use App\Http\Controllers\UserController;
2 
3Route::get('/user/{id}', [UserController::class, 'show']);

受信リクエストが指定されたルートURIと一致すると、App\Http\Controllers\UserControllerクラスのshowメソッドが呼び出され、ルートパラメータがメソッドに渡されます。

コントローラは、基本クラスを拡張する必要はありません。ただし、すべてのコントローラで共有する必要があるメソッドを含む基本コントローラクラスを拡張すると便利な場合があります。

シングルアクションコントローラ

コントローラのアクションが特に複雑な場合は、その単一のアクションにコントローラクラス全体を割り当てると便利な場合があります。これを実現するには、コントローラ内に単一の__invokeメソッドを定義します。

1<?php
2 
3namespace App\Http\Controllers;
4 
5class ProvisionServer extends Controller
6{
7 /**
8 * Provision a new web server.
9 */
10 public function __invoke()
11 {
12 // ...
13 }
14}

シングルアクションコントローラのルートを登録するときは、コントローラメソッドを指定する必要はありません。代わりに、コントローラの名前をルータに渡すだけです。

1use App\Http\Controllers\ProvisionServer;
2 
3Route::post('/server', ProvisionServer::class);

make:controller Artisanコマンドの--invokableオプションを使用して、呼び出し可能なコントローラを生成できます。

1php artisan make:controller ProvisionServer --invokable

コントローラのスタブは、スタブの公開を使用してカスタマイズできます。

コントローラミドルウェア

ミドルウェアは、ルートファイルでコントローラのルートに割り当てられます。

1Route::get('/profile', [UserController::class, 'show'])->middleware('auth');

または、コントローラクラス内でミドルウェアを指定すると便利な場合があります。これを行うには、コントローラはHasMiddlewareインターフェイスを実装する必要があります。これは、コントローラが静的なmiddlewareメソッドを持つべきであることを示します。このメソッドから、コントローラのアクションに適用するミドルウェアの配列を返します。

1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Http\Controllers\Controller;
6use Illuminate\Routing\Controllers\HasMiddleware;
7use Illuminate\Routing\Controllers\Middleware;
8 
9class UserController extends Controller implements HasMiddleware
10{
11 /**
12 * Get the middleware that should be assigned to the controller.
13 */
14 public static function middleware(): array
15 {
16 return [
17 'auth',
18 new Middleware('log', only: ['index']),
19 new Middleware('subscribed', except: ['store']),
20 ];
21 }
22 
23 // ...
24}

コントローラのミドルウェアをクロージャとして定義することもできます。これにより、ミドルウェアクラス全体を記述せずにインラインミドルウェアを定義する便利な方法が提供されます。

1use Closure;
2use Illuminate\Http\Request;
3 
4/**
5 * Get the middleware that should be assigned to the controller.
6 */
7public static function middleware(): array
8{
9 return [
10 function (Request $request, Closure $next) {
11 return $next($request);
12 },
13 ];
14}

Illuminate\Routing\Controllers\HasMiddlewareを実装するコントローラは、Illuminate\Routing\Controllerを拡張してはいけません。

リソースコントローラ

アプリケーションの各Eloquentモデルを「リソース」と考えると、アプリケーションの各リソースに対して同じ一連のアクションを実行するのが一般的です。たとえば、アプリケーションにPhotoモデルとMovieモデルが含まれているとします。ユーザーはこれらのリソースを作成、読み取り、更新、または削除できる可能性が高いです。

この一般的なユースケースのため、Laravelのリソースルーティングは、一般的な作成、読み取り、更新、および削除(「CRUD」)ルートを1行のコードでコントローラに割り当てます。開始するには、make:controller Artisanコマンドの--resourceオプションを使用して、これらのアクションを処理するコントローラをすばやく作成します。

1php artisan make:controller PhotoController --resource

このコマンドは、app/Http/Controllers/PhotoController.phpにコントローラを生成します。コントローラには、利用可能な各リソース操作のメソッドが含まれます。次に、コントローラを指すリソースルートを登録できます。

1use App\Http\Controllers\PhotoController;
2 
3Route::resource('photos', PhotoController::class);

この単一のルート宣言は、リソース上のさまざまなアクションを処理するための複数のルートを作成します。生成されたコントローラには、これらの各アクションのメソッドがすでにスタブ化されています。route:list Artisanコマンドを実行することで、アプリケーションのルートの概要をいつでもすばやく確認できます。

resourcesメソッドに配列を渡すことで、一度に多くのリソースコントローラを登録することもできます。

1Route::resources([
2 'photos' => PhotoController::class,
3 'posts' => PostController::class,
4]);

リソースコントローラによって処理されるアクション

動詞 URI アクション ルート名
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/{photo} show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/{photo} update photos.update
DELETE /photos/{photo} destroy photos.destroy

見つからないモデルの動作のカスタマイズ

通常、暗黙的にバインドされたリソースモデルが見つからない場合、404 HTTPレスポンスが生成されます。ただし、リソースルートを定義するときにmissingメソッドを呼び出すことで、この動作をカスタマイズできます。missingメソッドは、リソースのルートのいずれかで暗黙的にバインドされたモデルが見つからない場合に呼び出されるクロージャを受け入れます。

1use App\Http\Controllers\PhotoController;
2use Illuminate\Http\Request;
3use Illuminate\Support\Facades\Redirect;
4 
5Route::resource('photos', PhotoController::class)
6 ->missing(function (Request $request) {
7 return Redirect::route('photos.index');
8 });

ソフトデリートされたモデル

通常、暗黙のモデルバインディングはソフトデリートされたモデルを取得せず、代わりに404 HTTPレスポンスを返します。ただし、リソースルートを定義するときにwithTrashedメソッドを呼び出すことで、フレームワークにソフトデリートされたモデルを許可するように指示できます。

1use App\Http\Controllers\PhotoController;
2 
3Route::resource('photos', PhotoController::class)->withTrashed();

引数なしでwithTrashedを呼び出すと、showeditupdateリソースルートでソフトデリートされたモデルが許可されます。withTrashedメソッドに配列を渡すことで、これらのルートのサブセットを指定できます。

1Route::resource('photos', PhotoController::class)->withTrashed(['show']);

リソースモデルの指定

ルートモデルバインディングを使用していて、リソースコントローラのメソッドがモデルインスタンスをタイプヒントするようにしたい場合は、コントローラを生成するときに--modelオプションを使用できます。

1php artisan make:controller PhotoController --model=Photo --resource

フォームリクエストの生成

リソースコントローラを生成するときに--requestsオプションを指定して、Artisanにコントローラの保存および更新メソッド用のフォームリクエストクラスを生成するように指示できます。

1php artisan make:controller PhotoController --model=Photo --resource --requests

部分的なリソースルート

リソースルートを宣言するときに、デフォルトのアクションの完全なセットの代わりに、コントローラが処理する必要があるアクションのサブセットを指定できます。

1use App\Http\Controllers\PhotoController;
2 
3Route::resource('photos', PhotoController::class)->only([
4 'index', 'show'
5]);
6 
7Route::resource('photos', PhotoController::class)->except([
8 'create', 'store', 'update', 'destroy'
9]);

APIリソースルート

APIによって消費されるリソースルートを宣言する場合、通常はcreateeditなどのHTMLテンプレートを提示するルートを除外したいでしょう。便宜上、apiResourceメソッドを使用して、これら2つのルートを自動的に除外できます。

1use App\Http\Controllers\PhotoController;
2 
3Route::apiResource('photos', PhotoController::class);

apiResourcesメソッドに配列を渡すことで、一度に多くのAPIリソースコントローラを登録できます。

1use App\Http\Controllers\PhotoController;
2use App\Http\Controllers\PostController;
3 
4Route::apiResources([
5 'photos' => PhotoController::class,
6 'posts' => PostController::class,
7]);

createまたはeditメソッドを含まないAPIリソースコントローラをすばやく生成するには、make:controllerコマンドを実行するときに--apiスイッチを使用します。

1php artisan make:controller PhotoController --api

ネストしたリソース

ネストされたリソースへのルートを定義する必要がある場合があります。たとえば、写真リソースには、写真に添付できる複数のコメントがある場合があります。リソースコントローラをネストするには、ルート宣言で「ドット」表記法を使用できます。

1use App\Http\Controllers\PhotoCommentController;
2 
3Route::resource('photos.comments', PhotoCommentController::class);

このルートは、次のようなURIでアクセスできるネストされたリソースを登録します。

1/photos/{photo}/comments/{comment}

ネストされたリソースのスコープ

Laravelの暗黙のモデルバインディング機能は、解決された子モデルが親モデルに属することを確認するようにネストされたバインディングを自動的にスコープできます。ネストされたリソースを定義するときにscopedメソッドを使用することで、自動スコープを有効にし、Laravelに子リソースを取得するフィールドを指示できます。これを実現する方法の詳細については、リソースルートのスコープに関するドキュメントを参照してください。

浅いネスト

多くの場合、子IDはすでに一意の識別子であるため、URI内に親IDと子IDの両方を含める必要は必ずしもありません。自動インクリメントする主キーなどの一意の識別子を使用してURIセグメント内のモデルを識別する場合、「浅いネスト」を使用することを選択できます。

1use App\Http\Controllers\CommentController;
2 
3Route::resource('photos.comments', CommentController::class)->shallow();

このルート定義は、次のルートを定義します。

動詞 URI アクション ルート名
GET /photos/{photo}/comments index photos.comments.index
GET /photos/{photo}/comments/create create photos.comments.create
POST /photos/{photo}/comments store photos.comments.store
GET /comments/{comment} show comments.show
GET /comments/{comment}/edit edit comments.edit
PUT/PATCH /comments/{comment} update comments.update
DELETE /comments/{comment} destroy comments.destroy

リソースルートの命名

デフォルトでは、すべてのリソースコントローラのアクションにはルート名がありますが、希望するルート名を含むnames配列を渡すことでこれらの名前を上書きできます。

1use App\Http\Controllers\PhotoController;
2 
3Route::resource('photos', PhotoController::class)->names([
4 'create' => 'photos.build'
5]);

リソースルートパラメータの命名

デフォルトでは、Route::resourceはリソース名の「単数形」バージョンに基づいてリソースルートのルートパラメータを作成します。parametersメソッドを使用して、リソースごとにこれを簡単にオーバーライドできます。parametersメソッドに渡される配列は、リソース名とパラメータ名の連想配列である必要があります。

1use App\Http\Controllers\AdminUserController;
2 
3Route::resource('users', AdminUserController::class)->parameters([
4 'users' => 'admin_user'
5]);

上記の例では、リソースのshowルートに対して次のURIが生成されます。

1/users/{admin_user}

リソースルートのスコープ

Laravelのスコープ付き暗黙のモデルバインディング機能は、解決された子モデルが親モデルに属することを確認するようにネストされたバインディングを自動的にスコープできます。ネストされたリソースを定義するときにscopedメソッドを使用することで、自動スコープを有効にし、Laravelに子リソースを取得するフィールドを指示できます。

1use App\Http\Controllers\PhotoCommentController;
2 
3Route::resource('photos.comments', PhotoCommentController::class)->scoped([
4 'comment' => 'slug',
5]);

このルートは、次のようなURIでアクセスできるスコープ付きネストリソースを登録します。

1/photos/{photo}/comments/{comment:slug}

ネストされたルートパラメータとしてカスタムキー付き暗黙的バインディングを使用する場合、Laravelは親の関係名を推測するための規則を使用して、その親によってネストされたモデルを取得するためにクエリを自動的にスコープします。この場合、Photoモデルには、Commentモデルを取得するために使用できるcomments(ルートパラメータ名の複数形)という名前の関係があると想定されます。

リソースURIのローカライズ

デフォルトでは、Route::resourceは英語の動詞と複数形ルールを使用してリソースURIを作成します。createeditのアクション動詞をローカライズする必要がある場合は、Route::resourceVerbsメソッドを使用できます。これは、アプリケーションのApp\Providers\AppServiceProvider内のbootメソッドの先頭で行うことができます。

1/**
2 * Bootstrap any application services.
3 */
4public function boot(): void
5{
6 Route::resourceVerbs([
7 'create' => 'crear',
8 'edit' => 'editar',
9 ]);
10}

Laravelの複数形化機能は、ニーズに応じて設定できるいくつかの異なる言語をサポートしています。動詞と複数形化言語がカスタマイズされると、Route::resource('publicacion', PublicacionController::class)のようなリソースルート登録は次のURIを生成します。

1/publicacion/crear
2
3/publicacion/{publicaciones}/editar

リソースコントローラの補足

デフォルトのリソースルートのセットに加えて、リソースコントローラにさらにルートを追加する必要がある場合は、Route::resourceメソッドの呼び出しの前にそれらのルートを定義する必要があります。そうしないと、resourceメソッドによって定義されたルートが意図せずに補足ルートより優先される可能性があります。

1use App\Http\Controller\PhotoController;
2 
3Route::get('/photos/popular', [PhotoController::class, 'popular']);
4Route::resource('photos', PhotoController::class);

コントローラを集中させておくことを忘れないでください。典型的なリソースアクションのセット以外のメソッドが定期的に必要になる場合は、コントローラを2つの小さなコントローラに分割することを検討してください。

シングルトンリソースコントローラ

アプリケーションには、単一のインスタンスしか持てないリソースが存在する場合があります。たとえば、ユーザーの「プロフィール」は編集または更新できますが、ユーザーは複数の「プロフィール」を持つことはできません。同様に、画像には単一の「サムネイル」しかありません。これらのリソースは「シングルトンリソース」と呼ばれ、リソースのインスタンスが1つだけ存在することを意味します。このようなシナリオでは、「シングルトン」リソースコントローラを登録できます。

1use App\Http\Controllers\ProfileController;
2use Illuminate\Support\Facades\Route;
3 
4Route::singleton('profile', ProfileController::class);

上記のシングルトンリソース定義は、次のルートを登録します。ご覧のとおり、シングルトンリソースには「作成」ルートは登録されず、登録されたルートはリソースのインスタンスが1つしか存在しないため識別子を受け入れません。

動詞 URI アクション ルート名
GET /profile show profile.show
GET /profile/edit edit profile.edit
PUT/PATCH /profile update profile.update

シングルトンリソースは、標準リソース内にネストすることもできます。

1Route::singleton('photos.thumbnail', ThumbnailController::class);

この例では、photosリソースは標準のリソースルートをすべて受け取ります。ただし、thumbnailリソースは次のルートを持つシングルトンリソースになります。

動詞 URI アクション ルート名
GET /photos/{photo}/thumbnail show photos.thumbnail.show
GET /photos/{photo}/thumbnail/edit edit photos.thumbnail.edit
PUT/PATCH /photos/{photo}/thumbnail update photos.thumbnail.update

作成可能なシングルトンリソース

シングルトンリソースの作成ルートと保存ルートを定義したい場合があります。これを実現するには、シングルトンリソースルートを登録するときにcreatableメソッドを呼び出します。

1Route::singleton('photos.thumbnail', ThumbnailController::class)->creatable();

この例では、次のルートが登録されます。ご覧のとおり、作成可能なシングルトンリソースにはDELETEルートも登録されます。

動詞 URI アクション ルート名
GET /photos/{photo}/thumbnail/create create photos.thumbnail.create
POST /photos/{photo}/thumbnail store photos.thumbnail.store
GET /photos/{photo}/thumbnail show photos.thumbnail.show
GET /photos/{photo}/thumbnail/edit edit photos.thumbnail.edit
PUT/PATCH /photos/{photo}/thumbnail update photos.thumbnail.update
DELETE /photos/{photo}/thumbnail destroy photos.thumbnail.destroy

LaravelにシングルトンリソースのDELETEルートを登録させたいが、作成ルートや保存ルートは登録したくない場合は、destroyableメソッドを利用できます。

1Route::singleton(...)->destroyable();

APIシングルトンリソース

apiSingletonメソッドを使用して、API経由で操作されるシングルトンリソースを登録できます。これにより、createルートとeditルートが不要になります。

1Route::apiSingleton('profile', ProfileController::class);

もちろん、APIシングルトンリソースもcreatableにすることができ、これによりリソースのstoreルートとdestroyルートが登録されます。

1Route::apiSingleton('photos.thumbnail', ProfileController::class)->creatable();

依存注入とコントローラ

コンストラクタインジェクション

Laravelのサービスコンテナは、すべてのLaravelコントローラを解決するために使用されます。その結果、コントローラが必要とする依存関係をコンストラクタでタイプヒントできます。宣言された依存関係は自動的に解決され、コントローラインスタンスに注入されます。

1<?php
2 
3namespace App\Http\Controllers;
4 
5use App\Repositories\UserRepository;
6 
7class UserController extends Controller
8{
9 /**
10 * Create a new controller instance.
11 */
12 public function __construct(
13 protected UserRepository $users,
14 ) {}
15}

メソッドインジェクション

コンストラクタインジェクションに加えて、コントローラのメソッドで依存関係をタイプヒントすることもできます。メソッドインジェクションの一般的なユースケースは、Illuminate\Http\Requestインスタンスをコントローラメソッドに注入することです。

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7 
8class UserController extends Controller
9{
10 /**
11 * Store a new user.
12 */
13 public function store(Request $request): RedirectResponse
14 {
15 $name = $request->name;
16 
17 // Store the user...
18 
19 return redirect('/users');
20 }
21}

コントローラメソッドがルートパラメータからの入力も期待している場合は、他の依存関係の後にルート引数をリストします。たとえば、ルートが次のように定義されている場合:

1use App\Http\Controllers\UserController;
2 
3Route::put('/user/{id}', [UserController::class, 'update']);

次のようにコントローラメソッドを定義することで、Illuminate\Http\Requestをタイプヒントし、idパラメータにアクセスできます。

1<?php
2 
3namespace App\Http\Controllers;
4 
5use Illuminate\Http\RedirectResponse;
6use Illuminate\Http\Request;
7 
8class UserController extends Controller
9{
10 /**
11 * Update the given user.
12 */
13 public function update(Request $request, string $id): RedirectResponse
14 {
15 // Update the user...
16 
17 return redirect('/users');
18 }
19}

Laravelは最も生産的な方法です
ソフトウェアを構築、デプロイ、監視します。