はじめに
すべてのリクエスト処理ロジックをルートファイル内のクロージャとして定義する代わりに、これらの動作を「コントローラー」クラスを使用して整理することを検討するかもしれません。コントローラーは、関連するリクエスト処理ロジックを単一のクラスにグループ化できます。たとえば、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 に一致すると、show
メソッドが App\Http\Controllers\UserController
クラスで呼び出され、ルートパラメータがメソッドに渡されます。
コントローラーは、必須ではありませんが、すべてのコントローラーで共有すべきメソッドを含む基本コントローラークラスを拡張することが便利な場合があります。
シングルアクションコントローラー
コントローラーアクションが特に複雑な場合、その単一のアクションに専念するために、コントローラークラス全体を割り当てることが便利かもしれません。これを実現するには、コントローラー内に単一の 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」)ルートを単一の行のコードでコントローラーに割り当てます。始めるには、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
を呼び出すと、show
、edit
、および update
リソースルートに対してソフト削除されたモデルが許可されます。これらのルートのサブセットを指定するには、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 によって消費されるリソースルートを宣言する際には、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 リソースコントローラーを迅速に生成するには、--api
スイッチを使用して make:controller
コマンドを実行します:
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 を作成します。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 | /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
メソッドを呼び出すことができます:
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
メソッドを利用できます:
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
インスタンスをコントローラーメソッドに注入することです:
<?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');
}
}