メインコンテンツまでスキップ

コントローラー

はじめに

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

コントローラーの記述

基本的なコントローラー

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

php artisan make:controller UserController

基本的なコントローラーの例を見てみましょう。コントローラーには、受信するHTTPリクエストに応答する任意の数のパブリックメソッドが含まれる可能性があります:

    <?php

namespace App\Http\Controllers;

use App\Models\User;
use Illuminate\View\View;

class UserController extends Controller
{
/**
* Show the profile for a given user.
*/
public function show(string $id): View
{
return view('user.profile', [
'user' => User::findOrFail($id)
]);
}
}

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

    use App\Http\Controllers\UserController;

Route::get('/user/{id}', [UserController::class, 'show']);

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

注記

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

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

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

    <?php

namespace App\Http\Controllers;

class ProvisionServer extends Controller
{
/**
* Provision a new web server.
*/
public function __invoke()
{
// ...
}
}

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

    use App\Http\Controllers\ProvisionServer;

Route::post('/server', ProvisionServer::class);

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

php artisan make:controller ProvisionServer --invokable
注記

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

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

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

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

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

    <?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

class UserController extends Controller implements HasMiddleware
{
/**
* Get the middleware that should be assigned to the controller.
*/
public static function middleware(): array
{
return [
'auth',
new Middleware('log', only: ['index']),
new Middleware('subscribed', except: ['store']),
];
}

// ...
}

また、コントローラミドルウェアをクロージャとして定義することもできます。これは、ミドルウェアクラス全体を書かずにインラインミドルウェアを定義する便利な方法を提供します:

    use Closure;
use Illuminate\Http\Request;

/**
* Get the middleware that should be assigned to the controller.
*/
public static function middleware(): array
{
return [
function (Request $request, Closure $next) {
return $next($request);
},
];
}

リソースコントローラ

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

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

php artisan make:controller PhotoController --resource

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

    use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class);

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

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

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

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

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

モデルが見つからない場合のカスタマイズ

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

    use App\Http\Controllers\PhotoController;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;

Route::resource('photos', PhotoController::class)
->missing(function (Request $request) {
return Redirect::route('photos.index');
});

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

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

    use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class)->withTrashed();

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

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

リソースモデルの指定

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

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

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

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

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

部分的なリソースルート

リソースルートを宣言する際に、コントローラが処理すべきアクションのサブセットを指定できます。デフォルトアクションのフルセットではなく、特定のアクションのみを指定することができます:

    use App\Http\Controllers\PhotoController;

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

Route::resource('photos', PhotoController::class)->except([
'create', 'store', 'update', 'destroy'
]);

APIリソースルート

APIを利用するリソースルートを宣言する際には、通常、createeditなどのHTMLテンプレートを表示するルートを除外したいと考えることがよくあります。便宜上、これらの2つのルートを自動的に除外するためにapiResourceメソッドを使用することができます:

    use App\Http\Controllers\PhotoController;

Route::apiResource('photos', PhotoController::class);

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

    use App\Http\Controllers\PhotoController;
use App\Http\Controllers\PostController;

Route::apiResources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);

createeditメソッドを含まないAPIリソースコントローラを素早く生成するには、make:controllerコマンドを実行する際に--apiスイッチを使用してください:

php artisan make:controller PhotoController --api

ネストされたリソース

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

    use App\Http\Controllers\PhotoCommentController;

Route::resource('photos.comments', PhotoCommentController::class);

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

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

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

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

シャローネスト

しばしば、子IDがすでに一意の識別子であるため、URI内に親と子の両方のIDを持つ必要がないことがあります。URIセグメントでモデルを識別するために自動増分プライマリキーなどの一意の識別子を使用する場合、"シャローネスト"を使用することができます:

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

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

リソースルートの名前付け

デフォルトでは、すべてのリソースコントローラーアクションにはルート名がありますが、names 配列を渡すことでこれらの名前をオーバーライドすることができます:

    use App\Http\Controllers\PhotoController;

Route::resource('photos', PhotoController::class)->names([
'create' => 'photos.build'
]);

リソースルートパラメータの名前付け

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

    use App\Http\Controllers\AdminUserController;

Route::resource('users', AdminUserController::class)->parameters([
'users' => 'admin_user'
]);

The example above generates the following URI for the resource's `show` route:

/users/{admin_user}

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

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

    use App\Http\Controllers\PhotoCommentController;

Route::resource('photos.comments', PhotoCommentController::class)->scoped([
'comment' => 'slug',
]);

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

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

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

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

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

    /**
* Bootstrap any application services.
*/
public function boot(): void
{
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]);
}

Laravelの複数形変換機能は、必要に応じて構成できる複数の異なる言語をサポートしています。動詞と複数形変換言語をカスタマイズした後、Route::resource('publicacion', PublicacionController::class)などのリソースルート登録は、次のURIを生成します:

    /publicacion/crear

/publicacion/{publicaciones}/editar

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

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

    use App\Http\Controller\PhotoController;

Route::get('/photos/popular', [PhotoController::class, 'popular']);
Route::resource('photos', PhotoController::class);

注記

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

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

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

use App\Http\Controllers\ProfileController;
use Illuminate\Support\Facades\Route;

Route::singleton('profile', ProfileController::class);

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

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

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

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

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

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

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

時折、シングルトンリソースに対して作成および保存ルートを定義したい場合があります。これを実現するために、シングルトンリソースルートを登録する際にcreatableメソッドを呼び出すことができます:

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

この例では、次のルートが登録されます。作成可能なシングルトンリソースにはDELETEルートも登録されていることがわかります:

動詞URIアクションルート名
GET/photos/{photo}/thumbnail/createcreatephotos.thumbnail.create
POST/photos/{photo}/thumbnailstorephotos.thumbnail.store
GET/photos/{photo}/thumbnailshowphotos.thumbnail.show
GET/photos/{photo}/thumbnail/editeditphotos.thumbnail.edit
PUT/PATCH/photos/{photo}/thumbnailupdatephotos.thumbnail.update
DELETE/photos/{photo}/thumbnaildestroyphotos.thumbnail.destroy
Route::singleton(...)->destroyable();

API Singleton Resources

destroyableメソッドを利用すると、LaravelにDELETEルートをシングルトンリソース用に登録させることができますが、作成や保存のルートは登録されません。

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

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

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

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

コンストラクタ注入

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

    <?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
/**
* Create a new controller instance.
*/
public function __construct(
protected UserRepository $users,
) {}
}

メソッド注入

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

    <?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class UserController extends Controller
{
/**
* Store a new user.
*/
public function store(Request $request): RedirectResponse
{
$name = $request->name;

// Store the user...

return redirect('/users');
}
}

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

    use App\Http\Controllers\UserController;

Route::put('/user/{id}', [UserController::class, 'update']);

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

    <?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class UserController extends Controller
{
/**
* Update the given user.
*/
public function update(Request $request, string $id): RedirectResponse
{
// ユーザを更新...

return redirect('/users');
}
}