イントロダクション

全リクエストの処理をたった一つのroutes.phpファイルで定義するより、コントローラークラスを使い構造化して利用したいと思われるでしょう。コントローラーは関連したHTTPリクエストのロジックをクラスにまとめます。基本的にコントローラーはapp/Http/Controllersディレクトリーに設置されます。

基本的なコントローラー

コントローラークラスの一例です。

<?php namespace App\Http\Controllers;

use App\Http\Controllers\Controller;

class UserController extends Controller {

    /**
     * 指定されたユーザーのプロファイルを表示する
     *
     * @param  int  $id
     * @return Response
     */
    public function showProfile($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }

}

コントローラーアクションへのルートは、次のように書くことができます。

Route::get('user/{id}', 'UserController@showProfile');

注目: 全てのコントローラーはベースコントローラークラスを拡張する必要があります。

コントローラーと名前空間

とても重要な注目ポイントは、コントローラーの完全な名前空間を指定する必要がないことです。「ルート」のApp\Http\Controllers名前空間に続くクラス名の部分だけを指定しています。デフォルトでは、RouteServiceProviderがルートコントローラーの名前空間を指定したルートグループの中で、routes.phpファイルをロードします。

App\Http\Controllersディレクトリーより深く、コントローラのPHP名前空間をネストしたり、組織立てたりする場合でも単に、App\Http\Controllersルート名前空間からの相対クラス名を指定するだけです。ですから、コントローラーの完全なクラス名がApp\Http\Controllers\Photos\AdminControllerならば、次のようにルートを登録します。

Route::get('foo', 'Photos\AdminController@method');

コントローラールートへの名前付け

クロージャールートと同様に、コントローラールートにも名前が指定できます。

Route::get('foo', ['uses' => 'FooController@method', 'as' => 'name']);

コントローラーアクションへのURL

コントローラーアクションへのURLを生成するときは、actionヘルパーメソッドを使用します。

$url = action('App\Http\Controllers\FooController@method');

コントローラーの名前空間からの相対クラス名の一部だけを使用し、コントローラーアクションへのURLを生成したい場合は、URLジェネレーターへルート名前空間を登録してください。

URL::setRootControllerNamespace('App\Http\Controllers');

$url = action('FooController@method');

実行中のコントローラーアクション名を取得するには、currentRouteActionメソッドが使えます。

$action = Route::currentRouteAction();

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

ミドルウェアは、コントローラーアクションに対して、次のように指定します。

Route::get('profile', [
    'middleware' => 'auth',
    'uses' => 'UserController@showProfile'
]);

また、コントローラーのコンストラクターでも、ミドルウェアを指定できます。

class UserController extends Controller {

    /**
     * 新しいUserControllerのインスタンスの生成
     */
    public function __construct()
    {
        $this->middleware('auth');

        $this->middleware('log', ['only' => ['fooAction', 'barAction']]);

        $this->middleware('subscribed', ['except' => ['fooAction', 'barAction']]);
    }

}

暗黙のコントローラー

Laravelでは、一つのルートだけで、簡単にコントローラーの全アクションを定義できます。最初に、Route::controllerメソッドで、そのルートを定義します。

Route::controller('users', 'UserController');

controllerメソッドは2つの引数を取ります。最初はコントローラーが処理するURIで、2つ目はコントローラーのクラス名です。次に、対応するHTTP動詞をプリフィックスにし、メソッドをコントローラーに追加してください。

class UserController extends BaseController {

    public function getIndex()
    {
        //
    }

    public function postProfile()
    {
        //
    }

    public function anyLogin()
    {
        //
    }

}

indexメソッドは、コントローラーのルートURIに対応します。この場合、usersです。

コントローラーアクションに複数の単語を含める場合は、URIに「ダッシュ」記法を使用し、そのアクションへアクセスできます。例えば、コントローラーアクションがUserControllerであれば、users/admin-profileのURIにレスポンスします。

public function getAdminProfile() {}

RESTフルリソースコントローラー

リソースフルコントローラーはリソースに関するRESTフルコントローラーを苦労をせずに構築してくれます。例えば、アプリケーションで保存されている「写真(phots)」関係のHTTPリクエストを処理するコントローラーを作成するとしましょう。Artisanコマンドラインでmake:controller Artisanコマンドを使えば、そのようなコントローラを素早く生成できます。

php artisan make:controller PhotoController

次に、コントローラーへのリソースフルルートを登録します。

Route::resource('photo', 'PhotoController');

写真リソースの様々なRESTフルアクションを処理する多くのルートが、この1行のルート定義で作り出されます。同時に、生成されたコントローラーには、どのURI/動詞を処理するのかという情報を含んだスタブメソッドが、それぞれのアクションに対して用意されています。

リソースフルコントローラーにより処理されるアクション

変数 パス アクション ルート名
GET /リソース名 index resource.index
GET /リソース名/create create resource.create
POST /リソース名 store resource.store
GET /リソース名/{resource} show resource.show
GET /リソース名/{resource}/edit edit resource.edit
PUT/PATCH /リソース名/{resource} update resource.update
DELETE /リソース名/{resource} destroy resource.destroy

リソースルートのカスタマイズ

さらに、リソースアクションの一部のみを取り扱うことも可能です。

Route::resource('photo', 'PhotoController',
                ['only' => ['index', 'show']]);

Route::resource('photo', 'PhotoController',
                ['except' => ['create', 'store', 'update', 'destroy']]);

デフォルトで、すべてのリソースコントローラーアクションはルート名を持ちます。しかしオプションにnames配列を渡すことで、こうした名前をオーバーライドすることもできます。

Route::resource('photo', 'PhotoController',
                ['names' => ['create' => 'photo.build']]);

ネストしたリソースコントローラーの処理

「ネスト」したリソースコントローラーには、ルート宣言で「ドット」記法を使用してください。

Route::resource('photos.comments', 'PhotoCommentController');

これにより、「ネスト」したリソースが登録され、photos/{photos}/comments/{comments}のURLにアクセスできるようになります。

class PhotoCommentController extends Controller {

    /**
     * 特定の写真のコメントを表示する
     *
     * @param  int  $photoId
     * @param  int  $commentId
     * @return Response
     */
    public function show($photoId, $commentId)
    {
        //
    }

}

リソースコントローラーへのルート追加

デフォルトのリソースルート以外のルートをリソースコントローラーへ追加する必要がある場合は、Route::resourceの呼び出しより前に定義する必要があります。

Route::get('photos/popular');

Route::resource('photos', 'PhotoController');

依存注入とコントローラー

コンストラクターによる注入

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

<?php namespace App\Http\Controllers;

use Illuminate\Routing\Controller;
use App\Repositories\UserRepository;

class UserController extends Controller {

    /**
     * ユーザーリポジトリーインスタンス
     */
    protected $users;

    /**
     * 新しいコントローラーインスタンスの生成
     *
     * @param  UserRepository  $users
     * @return void
     */
    public function __construct(UserRepository $users)
    {
        $this->users = $users;
    }

}

もちろん、Laravelの契約もタイプヒントに指定できます。コンテナが依存解決できるものは、タイプヒントで指定できます。

メソッドによる注入

コンストラクターによる注入に加え、コントローラーのメソッドにタイプヒントで依存を指定することもできます。例えば、あるメソッドでRequestインスタンスをタイプヒントで指定してみましょう。

<?php namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class UserController extends Controller {

    /**
     * 新しいユーザーの保存
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->input('name');

        //
    }

}

もしコントローラーメソッドで、ルートパラメーターの入力が求められているのでしたら、依存定義の後に続けて、ルート引数を指定するだけです。

<?php namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class UserController extends Controller {

    /**
     * 新しいユーザーの保存
     *
     * @param  Request  $request
     * @param  int  $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        //
    }

}

注目: メソッドによる注入はモデルの結合でも同様に動作します。コンテナは結合されたモデルの引数と、注入すべきモデルを聡明に判断します。

ルートキャッシュ

アプリケーションがコントローラールートだけを使用していれば、Laravelのルートキャッシュを利用できる利点があります。ルートキャッシュを使用すれば、アプリケーションの全ルートを登録するのに必要な時間を劇的に減らすことができます。ある場合には、ルート登録が100倍も早くなります!ルートキャッシュを登録するには、route:catch Arisanコマンドを実行するだけです。

php artisan route:cache

これだけです!キャッシュされたルートファイルは、app/Http/routes.phpファイルの代わりに使用されるようになります。その代わりに、新しいルートを追加するには、キャッシュルートを再構築する必要があります。ですから、プロジェクトの開発期間の最後に、一度だけroute:cacheを実行するほうが良いでしょう。

新しいキャッシュルートのファイルを生成せず削除するためには、route:clearコマンドを使います。

php artisan route:clear