はじめに

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

コントローラーの作成

基本的なコントローラー

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

  1. php artisan make:controller UserController

基本的なコントローラーの例を見てみましょう。コントローラーには、受信する HTTP リクエストに応答する任意の数のパブリックメソッドを持つことができます:

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

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

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

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

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

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

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

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

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

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

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

  1. php artisan make:controller ProvisionServer --invokable

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

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

ミドルウェアは、ルートファイル内のコントローラーのルートに割り当てることができます:

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

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

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

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

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

リソースコントローラー

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

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

  1. php artisan make:controller PhotoController --resource

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

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

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

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

  1. Route::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 メソッドは、暗黙的にバインドされたモデルがリソースのルートのいずれかに対して見つからない場合に呼び出されるクロージャを受け入れます:

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

ソフト削除されたモデル

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

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

引数なしで withTrashed を呼び出すと、showedit、および update リソースルートに対してソフト削除されたモデルが許可されます。これらのルートのサブセットを指定するには、withTrashed メソッドに配列を渡します:

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

リソースモデルの指定

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

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

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

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

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

部分的なリソースルート

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

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

API リソースルート

API によって消費されるリソースルートを宣言する際には、createedit のような HTML テンプレートを表示するルートを除外することが一般的です。便利なことに、apiResource メソッドを使用して、これらの 2 つのルートを自動的に除外できます:

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

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

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

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

  1. php artisan make:controller PhotoController --api

ネストされたリソース

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

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

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

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

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

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

浅いネスト

しばしば、URI 内に親と子の両方の ID を持つ必要はありません。なぜなら、子の ID はすでに一意の識別子だからです。URI セグメント内でモデルを識別するために自動インクリメントプライマリキーのような一意の識別子を使用する場合、「浅いネスト」を使用することを選択できます:

  1. use App\Http\Controllers\CommentController;
  2. Route::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 配列を渡すことで、これらの名前をオーバーライドできます:

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

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

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

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

上記の例は、リソースの show ルートに対して次の URI を生成します:

  1. /users/{admin_user}

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

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

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

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

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

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

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

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

  1. /**
  2. * Bootstrap any application services.
  3. */
  4. public 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. /publicacion/{publicaciones}/editar

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

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

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

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

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

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

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

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

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

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


php<br>Route::singleton('photos.thumbnail', ThumbnailController::class);<br>

この例では、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 メソッドを呼び出すことができます:

  1. Route::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 メソッドを利用できます:

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

API シングルトンリソース

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

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

もちろん、API シングルトンリソースも creatable であり、リソースの store および destroy ルートを登録します:

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

依存性注入とコントローラー

コンストラクタ注入

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

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

メソッド注入

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

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

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

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

Illuminate\Http\Request を型ヒントし、id パラメータにアクセスするには、コントローラーメソッドを次のように定義します:

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