Skip to content

コントローラ

イントロダクション

ルートファイル内ですべてのリクエスト処理ロジックをクロージャとして定義する代わりに、この動作を整理するために「コントローラ」クラスを使用することができます。コントローラは、関連するリクエスト処理ロジックを1つのクラスにグループ化することができます。例えば、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
{
    /**
     * 指定されたユーザーのプロフィールを表示します。
     */
    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メソッドが呼び出され、ルートパラメータがメソッドに渡されます。

Note

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

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

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

<?php

namespace App\Http\Controllers;

class ProvisionServer extends Controller
{
    /**
     * 新しいウェブサーバーをプロビジョニングします。
     */
    public function __invoke()
    {
        // ...
    }
}

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

use App\Http\Controllers\ProvisionServer;

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

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

php artisan make:controller ProvisionServer --invokable

Note

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

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

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

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
{
    /**
     * コントローラに割り当てるべきミドルウェアを取得します。
     */
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('log', only: ['index']),
            new Middleware('subscribed', except: ['store']),
        ];
    }

    // ...
}

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

use Closure;
use Illuminate\Http\Request;

/**
 * コントローラに割り当てるべきミドルウェアを取得します。
 */
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 /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メソッドは、暗黙的にバインドされたモデルがリソースのいずれのルートでも見つからない場合に呼び出されるクロージャを受け取ります。

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を呼び出すと、ソフトデリートされたモデルがshowedit、およびupdateリソースルートで許可されます。withTrashedメソッドに配列を渡すことで、これらのルートのサブセットを指定できます。

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

リソースモデルの指定

route model bindingを使用していて、リソースコントローラのメソッドにモデルインスタンスをタイプヒントする場合、コントローラを生成する際に--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テンプレートを表示するルートを除外したいでしょう。便宜上、apiResourceメソッドを使用してこれらの2つのルートを自動的に除外できます。

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に子リソースを取得するフィールドを指示できます。これを実現する方法の詳細については、リソースルートのスコーピングに関するドキュメントを参照してください。

浅いネスト

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

use App\Http\Controllers\CommentController;

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配列を渡すことで、これらの名前を上書きできます。

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'
]);

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

/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を英語の動詞と複数形規則を使用して作成します。createeditアクション動詞をローカライズする必要がある場合は、Route::resourceVerbsメソッドを使用できます。これは、アプリケーションのApp\Providers\AppServiceProviderbootメソッドの先頭で行うことができます。

/**
 * 任意のアプリケーションサービスのブートストラップ。
 */
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);

Note

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

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

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

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

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

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

動詞 URI アクション ルート名
GET /profile show profile.show
GET /profile/edit edit profile.edit
PUT/PATCH /profile update profile.update
動詞 URI アクション ルート名
GET /profile 表示 profile.show
GET /profile/edit 編集 profile.edit
PUT/PATCH /profile 更新 profile.update

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

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

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

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

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

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

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

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

動詞 URI アクション ルート名
GET /photos/{photo}/thumbnail/create 作成 photos.thumbnail.create
POST /photos/{photo}/thumbnail 保存 photos.thumbnail.store
GET /photos/{photo}/thumbnail 表示 photos.thumbnail.show
GET /photos/{photo}/thumbnail/edit 編集 photos.thumbnail.edit
PUT/PATCH /photos/{photo}/thumbnail 更新 photos.thumbnail.update
DELETE /photos/{photo}/thumbnail 削除 photos.thumbnail.destroy

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

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

APIシングルトンリソース

apiSingletonメソッドは、APIを介して操作されるシングルトンリソースを登録するために使用できます。そのため、createおよびeditルートは不要です。

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
{
    /**
     * 新しいコントローラインスタンスの作成
     */
    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
{
    /**
     * 新しいユーザーを保存
     */
    public function store(Request $request): RedirectResponse
    {
        $name = $request->name;

        // ユーザーを保存...

        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
{
    /**
     * 指定されたユーザーを更新
     */
    public function update(Request $request, string $id): RedirectResponse
    {
        // ユーザーを更新...

        return redirect('/users');
    }
}

ユーザーノート