Laravel 8.x コントローラ

イントロダクション

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

コントローラを書く

基本のコントローラ

基本的なコントローラの一例を見てみましょう。コントローラは、Laravelに含まれている基本コントローラクラス、App\Http\Controllers\Controllerを拡張することに注意してください::

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;

class UserController extends Controller
{
    /**
     * 指定ユーザーのプロファイルを表示
     *
     * @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!! コントローラは基本クラスを拡張する必要はありません。ただし、middlewareauthorizeメソッドなどの便利な機能にはアクセスできません。

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

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

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Models\User;

class ProvisionServer extends Controller
{
    /**
     * 新しいWebサーバをプロビジョニング
     *
     * @return \Illuminate\Http\Response
     */
    public function __invoke()
    {
        // ...
    }
}

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

use App\Http\Controllers\ProvisionServer;

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

make:controller Artisanコマンドで--invokableオプションを指定すると、__invokeメソッドを含んだコントローラを生成できます。

php artisan make:controller ProvisionServer --invokable

Tip!! stubのリソース公開を使用し、コントローラのスタブをカスタマイズできます。

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

ミドルウェアはルートファイルの中で、コントローラのルートに対して指定します。

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

または、コントローラのコンストラクター内でミドルウェアを指定できると便利な場合があります。コントローラのコンストラクタ内でmiddlewareメソッドを使用して、コントローラのアクションにミドルウェアを割り当てられます。

class UserController extends Controller
{
    /**
     * 新しいUserControllerインスタンスの生成
     *
     * @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);
});

リソースコントローラ

アプリケーション内の各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 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');
        });

リソースモデルの指定

ルートモデル結合を使用していて、リソースコントローラのメソッドでモデルインスタンスをタイプヒントしたい場合は、コントローラを生成するときのオプションに--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);

このルートにより次のようなURLでアクセスする、ネストしたリソースが定義できます。

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

ネストしたリソースのスコープ

Laravelの暗黙的なモデル結合機能は、リソース解決する子モデルが親モデルに属することを確認するように、ネストした結合を自動的にスコープできます。ネストしたリソースを定義するときにscopedメソッドを使用することにより、自動スコープを有効にしたり、子リソースを取得するフィールドをLaravelに指示したりできます。この実現方法の詳細は、リソースルートのスコープに関するドキュメントを参照してください。

Shallowネスト

子のIDがすでに一意な識別子になってる場合、親子両方のIDをURIに含める必要はまったくありません。主キーの自動増分のように、一意の識別子をURIセグメント中でモデルを識別するために使用しているのなら、「shallow(浅い)ネスト」を使用できます。

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モデルには、Commentモデルを取得するために使用できるcomments(ルートパラメータ名の複数形)という名前のリレーションがあると想定します。

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

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

/**
 * ルートモデルの結合、パターンフィルターなどを定義
 *
 * @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つに分け、小さなコントローラにすることを考えましょう。

依存注入とコントローラ

コンストラクターインジェクション

全コントローラの依存を解決するために、Laravelのサービスコンテナが使用されます。これにより、コントローラが必要な依存をコンストラクターにタイプヒントで指定できるのです。依存クラスは自動的に解決され、コントローラへインスタンスが注入されます。

<?php

namespace App\Http\Controllers;

use App\Repositories\UserRepository;

class UserController extends Controller
{
    /**
     * ユーザーリポジトリインスタンス
     */
    protected $users;

    /**
     * 新しいコントローラインスタンスの生成
     *
     * @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
{
    /**
     * 新ユーザーの保存
     *
     * @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
{
    /**
     * 指定ユーザーの更新
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  string  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる