コントローラ (Controllers)
導入 (Introduction)
すべてのリクエスト処理ロジックをルート ファイル内のクロージャとして定義する代わりに、「コントローラ」クラスを使用してこの動作を整理したい場合があります。コントローラは、関連するリクエスト処理ロジックを 1 つのクラスにグループ化できます。たとえば、UserController クラスは、ユーザーの表示、作成、更新、削除など、ユーザーに関連するすべての受信リクエストを処理する場合があります。デフォルトでは、コントローラは app/Http/Controllers ディレクトリに保存されます。
コントローラの作成 (Writing Controllers)
基本的なコントローラ
基本的なコントローラの例を見てみましょう。コントローラは、Laravel に含まれる基本コントローラ クラス App\Http\Controllers\Controller を拡張していることに注意してください。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\User;
class UserController extends Controller
{
/**
* Show the profile for a given user.
*
* @param int $id
* @return \Illuminate\View\View
*/
public function show($id)
{
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 メソッドが呼び出され、ルート パラメーターがメソッドに渡されます。
{tip} コントローラは、基本クラスを拡張するために必須ではありません。ただし、
middlewareメソッドやauthorizeメソッドなどの便利な機能にはアクセスできません。
シングルアクションコントローラ
コントローラのアクションが特に複雑な場合は、コントローラ クラス全体をその 1 つのアクション専用にすると便利な場合があります。これを実現するには、コントローラ内で単一の __invoke メソッドを定義します。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\User;
class ProvisionServer extends Controller
{
/**
* Provision a new web server.
*
* @return \Illuminate\Http\Response
*/
public function __invoke()
{
// ...
}
}
シングルアクションコントローラのルートを登録する場合、コントローラメソッドを指定する必要はありません。代わりに、単にコントローラの名前をルーターに渡すこともできます。
use App\Http\Controllers\ProvisionServer;
Route::post('/server', ProvisionServer::class);
make:controller Artisan コマンドの --invokable オプションを使用して、呼び出し可能なコントローラを生成できます。
php artisan make:controller ProvisionServer --invokable
{tip} コントローラ スタブは、スタブ発行 を使用してカスタマイズできます。
コントローラミドルウェア (Controller Middleware)
Middleware は、ルート ファイル内のコントローラのルートに割り当てることができます。
Route::get('profile', [UserController::class, 'show'])->middleware('auth');
または、コントローラのコンストラクター内でミドルウェアを指定すると便利な場合があります。コントローラのコンストラクター内で middleware メソッドを使用すると、コントローラのアクションにミドルウェアを割り当てることができます。
class UserController extends Controller
{
/**
* Instantiate a new controller instance.
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log')->only('index');
$this->middleware('subscribed')->except('store');
}
}
コントローラでは、クロージャーを使用してミドルウェアを登録することもできます。これにより、ミドルウェア クラス全体を定義せずに、単一のコントローラのインライン ミドルウェアを定義する便利な方法が提供されます。
$this->middleware(function ($request, $next) {
return $next($request);
});
リソースコントローラ (Resource Controllers)
アプリケーション内の各 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);
この 1 つのルート宣言により、リソースに対するさまざまなアクションを処理するための複数のルートが作成されます。生成されたコントローラには、これらのアクションごとにスタブ化されたメソッドがすでに含まれています。 route:list Artisan コマンドを実行すると、アプリケーションのルートの概要をいつでも簡単に取得できることに注意してください。
配列を resources メソッドに渡すことで、多くのリソース コントローラを一度に登録することもできます。
Route::resources([
'photos' => PhotoController::class,
'posts' => PostController::class,
]);
リソースコントローラによって処理されるアクション
| 動詞 | URI | アクション | 路線名 |
|---|---|---|---|
| 得る | /photos | 索引 | 写真.インデックス |
| 得る | /photos/create | 作成する | 写真.作成 |
| 役職 | /photos | 店 | 写真.ストア |
| 得る | /photos/{photo} | 見せる | 写真.ショー |
| 得る | /photos/{photo}/edit | 編集 | 写真.編集 |
| パット/パッチ | /photos/{photo} | アップデート | 写真.更新 |
| 消去 | /photos/{photo} | 破壊する | 写真.破壊 |
欠落モデルの動作のカスタマイズ
通常、暗黙的にバインドされたリソース モデルが見つからない場合は、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');
});
リソースモデルの指定
ルートモデルバインディング を使用していて、リソース コントローラのメソッドでモデル インスタンスのタイプヒントを取得したい場合は、コントローラの生成時に --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 によって使用されるリソース ルートを宣言する場合、一般的に、create や edit などの 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,
]);
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 | アクション | 路線名 |
|---|---|---|---|
| 得る | /photos/{photo}/comments | 索引 | 写真.コメント.インデックス |
| 得る | /photos/{photo}/comments/create | 作成する | 写真.コメント.作成 |
| 役職 | /photos/{photo}/comments | 店 | 写真.コメント.ストア |
| 得る | /comments/{comment} | 見せる | コメント.ショー |
| 得る | /comments/{comment}/edit | 編集 | コメント.編集 |
| パット/パッチ | /comments/{comment} | アップデート | コメント.更新 |
| 消去 | /comments/{comment} | 破壊する | コメント.破壊 |
リソースルートの命名
デフォルトでは、すべてのリソース コントローラ アクションにはルート名が付いています。ただし、希望のルート名を含む 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 モデルには、Comment モデルを取得するために使用できる comments (ルート パラメーター名の複数形) という名前のリレーションシップがあると想定されます。
リソース URI のローカライズ
デフォルトでは、Route::resource は英語の動詞を使用してリソース URI を作成します。 create および edit アクション動詞をローカライズする必要がある場合は、Route::resourceVerbs メソッドを使用できます。これは、アプリケーションの App\Providers\RouteServiceProvider 内の boot メソッドの先頭で行うことができます。
/**
* Define your route model bindings, pattern filters, etc.
*
* @return void
*/
public function boot()
{
Route::resourceVerbs([
'create' => 'crear',
'edit' => 'editar',
]);
// ...
}
動詞がカスタマイズされると、Route::resource('fotos', PhotoController::class) などのリソース ルート登録によって次の URI が生成されます。
/fotos/crear
/fotos/{foto}/editar
リソースコントローラの補足
リソース ルートのデフォルト セットを超えて追加のルートをリソース コントローラに追加する必要がある場合は、Route::resource メソッドを呼び出す前にそれらのルートを定義する必要があります。そうしないと、resource メソッドで定義されたルートが、補助ルートよりも意図せず優先される可能性があります。
use App\Http\Controller\PhotoController;
Route::get('/photos/popular', [PhotoController::class, 'popular']);
Route::resource('photos', PhotoController::class);
{tip} コントローラに集中することを忘れないでください。一般的なリソース アクションのセット以外のメソッドが日常的に必要な場合は、コントローラを 2 つの小さなコントローラに分割することを検討してください。
依存関係の注入とコントローラ (Dependency Injection & Controllers)
コンストラクターのインジェクション
Laravel サービスコンテナ は、すべての Laravel コントローラを解決するために使用されます。その結果、コントローラがコンストラクターで必要とする依存関係をタイプヒントで指定できるようになります。宣言された依存関係は自動的に解決され、コントローラ インスタンスに挿入されます。
<?php
namespace App\Http\Controllers;
use App\Repositories\UserRepository;
class UserController extends Controller
{
/**
* The user repository instance.
*/
protected $users;
/**
* Create a new controller instance.
*
* @param \App\Repositories\UserRepository $users
* @return void
*/
public function __construct(UserRepository $users)
{
$this->users = $users;
}
}
メソッドインジェクション
コンストラクターのインジェクションに加えて、コントローラのメソッドに対するタイプヒントの依存関係を指定することもできます。メソッド インジェクションの一般的な使用例は、コントローラ メソッドに Illuminate\Http\Request インスタンスを挿入することです。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Store a new user.
*
* @param \Illuminate\Http\Request $request
* @return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$name = $request->name;
//
}
}
コントローラ メソッドがルート パラメーターからの入力も期待している場合は、他の依存関係の後にルート引数をリストします。たとえば、ルートが次のように定義されているとします。
use App\Http\Controllers\UserController;
Route::put('/user/{id}', [UserController::class, 'update']);
次のようにコントローラ メソッドを定義することで、Illuminate\Http\Request をタイプヒントし、id パラメーターにアクセスすることができます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class UserController extends Controller
{
/**
* Update the given user.
*
* @param \Illuminate\Http\Request $request
* @param string $id
* @return \Illuminate\Http\Response
*/
public function update(Request $request, $id)
{
//
}
}