コントローラー
はじめに
すべてのリクエスト処理ロジックをルートファイルのクロージャとして定義する代わりに、「コントローラー」クラスを使用してこの動作を整理することができます。コントローラーは、関連するリクエスト処理ロジックを単一のクラスにグループ化できます。たとえば、`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リソースルーティングは、一般的な作成、読み取り、更新、削除(「CRUD」)ルートを1行のコードでコントローラーに割り当てます。最初に、`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 |
/photos | store |
GET | photos.store |
GET | /photos/{photo} |
GET | show |
photos.show | GET |
/photos/{photo}/edit | photos.store |
edit | photos.edit |
PUT/PATCH | photos.store |
/photos/{photo} | update |
photos.update
DELETE
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'); });
/photos/{photo}
destroy
use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class)->withTrashed();
photos.destroy
Route::resource('photos', PhotoController::class)->withTrashed(['show']);
欠落モデル動作のカスタマイズ
通常、暗黙的にバインドされたリソースモデルが見つからない場合、404 HTTPレスポンスが生成されます。ただし、リソースルートを定義するときに`missing`メソッドを呼び出すことで、この動作をカスタマイズできます。`missing`メソッドは、暗黙的にバインドされたモデルがリソースのルートのいずれにも見つからない場合に呼び出されるクロージャを受け入れます。
php artisan make:controller PhotoController --model=Photo --resource
論理削除されたモデル
通常、暗黙的なモデルバインディングは、論理削除されたモデルを取得せず、代わりに404 HTTPレスポンスを返します。ただし、リソースルートを定義するときに`withTrashed`メソッドを呼び出すことで、論理削除されたモデルを許可するようにフレームワークに指示できます。
php artisan make:controller PhotoController --model=Photo --resource --requests
部分リソースルート
引数なしで`withTrashed`を呼び出すと、`show`、`edit`、および`update`リソースルートで論理削除されたモデルが許可されます。`withTrashed`メソッドに配列を渡すことで、これらのルートのサブセットを指定できます。
use App\Http\Controllers\PhotoController; Route::resource('photos', PhotoController::class)->only([ 'index', 'show']); Route::resource('photos', PhotoController::class)->except([ 'create', 'store', 'update', 'destroy']);
リソースモデルの指定
ルートモデルバインディングを使用していて、リソースコントローラーのメソッドでモデルインスタンスの型ヒントを指定したい場合は、コントローラーを生成するときに`--model`オプションを使用できます。
use App\Http\Controllers\PhotoController; Route::apiResource('photos', PhotoController::class);
フォームリクエストの生成
use App\Http\Controllers\PhotoController;use App\Http\Controllers\PostController; Route::apiResources([ 'photos' => PhotoController::class, 'posts' => PostController::class,]);
create
メソッドと edit
メソッドを含まない 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 と子 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 |
/photos | photos.comments.store |
GET | /comments/{comment} |
GET | comments.show |
GET | /comments/{comment}/edit |
photos.show | comments.edit |
/photos/{photo}/edit | /comments/{comment} |
edit | comments.update |
PUT/PATCH | /comments/{comment} |
/photos/{photo} | 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 は、親の関連名
リソース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 つだけ存在することを意味します。これらのシナリオでは、「シングルトン」リソースコントローラーを登録できます。
use App\Http\Controllers\ProfileController;use Illuminate\Support\Facades\Route; Route::singleton('profile', ProfileController::class);
上記のシングルトンリソース定義は、次のルートを登録します。ご覧のとおり、「作成」ルートはシングルトンリソースに対して登録されておらず、登録されたルートは、リソースのインスタンスが 1 つだけ存在するため、識別子を受け入れません。
動詞 | URI | アクション | ルート名 |
---|---|---|---|
GET | /profile |
GET | profile.show |
GET | /profile/edit |
photos.show | profile.edit |
/photos/{photo}/edit | /profile |
edit | profile.update |
シングルトンリソースは、標準リソース内にネストすることもできます。
Route::singleton('photos.thumbnail', ThumbnailController::class);
この例では、photos
リソースはすべての標準リソースルートを受け取ります。ただし、thumbnail
リソースは、次のルートを持つシングルトンリソースになります。
動詞 | URI | アクション | ルート名 |
---|---|---|---|
GET | /photos/{photo}/thumbnail |
GET | photos.thumbnail.show |
GET | /photos/{photo}/thumbnail/edit |
photos.show | photos.thumbnail.edit |
/photos/{photo}/edit | /photos/{photo}/thumbnail |
edit | photos.thumbnail.update |
作成可能なシングルトンリソース
場合によっては、シングルトンリソースの作成ルートとストレージルートを定義する必要があります。これを達成するには、シングルトンリソースルートを登録するときに creatable
メソッドを呼び出すことができます。
Route::singleton('photos.thumbnail', ThumbnailController::class)->creatable();
この例では、次のルートが登録されます。ご覧のとおり、DELETE
ルートも作成可能なシングルトンリソースに登録されます。
動詞 | URI | アクション | ルート名 |
---|---|---|---|
GET | /photos/{photo}/thumbnail/create |
create | photos.thumbnail.create |
POST | /photos/{photo}/thumbnail |
/photos | photos.thumbnail.store |
GET | /photos/{photo}/thumbnail |
GET | photos.thumbnail.show |
GET | /photos/{photo}/thumbnail/edit |
photos.show | photos.thumbnail.edit |
/photos/{photo}/edit | /photos/{photo}/thumbnail |
edit | photos.thumbnail.update |
PUT/PATCH | /photos/{photo}/thumbnail |
/photos/{photo} | photos.thumbnail.destroy |
Laravel にシングルトンリソースの `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{ /** * Create a new controller instance. */ public function __construct( protected UserRepository $users, ) {}}
メソッドインジェクション
コンストラクターインジェクションに加えて、コントローラーのメソッドの依存関係をタイプヒントすることもできます。メソッドインジェクションの一般的なユースケースは、`Illuminate\Http\Request` インスタンスをコントローラーメソッドに挿入することです。 p>
<?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 { // Update the user... return redirect('/users'); }}