イントロダクション
全リクエストの処理をたった一つのroutes.php
ファイルで定義するよりも、コントローラークラスによりロジックごとにカテゴリー分けしたいと、皆さんも思われるでしょう。関係しているHTTPリクエストロジックをコントローラーによりクラス毎にまとめられます。基本的にコントローラーはapp/Http/Controllers
ディレクトリー下に設置します。
基本のコントローラー
これは基本的なコントローラーの一例です。全てのLaravelコントローラーはLaravelにデフォルトで含まれている基本コントローラークラスを拡張します。
<?php
namespace App\Http\Controllers;
use App\User;
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');
これで指定したルートのURIにリクエストが一致すれば、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を生成するにはroute
ヘルパが使用できます。
$url = route('name');
さらにaction
ヘルパメソッドを使い、コントローラークラスとメソッド名によるURLを生成できます。この場合もベースとなるApp\Http\Controllers
名前空間に引き続くコントローラークラス名の部分のみ指定してください。
$url = action('FooController@method');
Route
ファサードのcurrentRouteAction
メソッドを実行すれば、コントローラーとアクション名にアクセスできます。
$action = Route::currentRouteAction();
コントローラーミドルウェア
ミドルウェアは、コントローラーアクションに対して、次のように指定します。
Route::get('profile', [
'middleware' => 'auth',
'uses' => 'UserController@showProfile'
]);
またはコントローラーのコンストラクターでも、ミドルウェアを指定できます。middleware
メソッドを使いコントローラーに対しミドルウェアを簡単に指定できます。特定のメソッドに対してだけミドルウェアを指定することも可能です。
class UserController extends Controller
{
/**
* 新しいUserControllerインスタンスの生成
*
* @return void
*/
public function __construct()
{
$this->middleware('auth');
$this->middleware('log', ['only' => ['fooAction', 'barAction']]);
$this->middleware('subscribed', ['except' => ['fooAction', 'barAction']]);
}
}
RESTフルリソースコントローラー
リソースフルコントローラーにより、リソースに関するRESTフルコントローラーを苦労せずに構築できます。例えば、アプリケーションで保存されている「写真(phots)」関係のHTTPリクエストを処理するコントローラーを作成するとしましょう。Artisanコマンドラインでmake:controller
Artisanコマンドを使えば、対応するコントローラをあっという間に生成できます。
php artisan make:controller PhotoController
このArtisanコマンドはapp/Http/Controllers/PhotoController.php
としてコントローラーファイルを生成します。コントローラーは使用可能な各リソース操作に対するメソッドを含んでいます。
次に、コントローラーへのリソースフルルートを登録します。
Route::resource('photo', 'PhotoController');
写真リソースの様々なRESTフルアクションを処理する多くのルートが、この1行のルート定義で作り出されます。同時に、生成されたコントローラーには、どのURI/動詞を処理するのかという情報を含んだスタブメソッドが、それぞれのアクションに対して用意されています。
リソースコントローラーにより処理されるアクション
動詞 | パス | アクション | ルート名 |
---|---|---|---|
GET | /photo |
index | photo.index |
GET | /photo/create |
create | photo.create |
POST | /photo |
store | photo.store |
GET | /photo/{photo} |
show | photo.show |
GET | /photo/{photo}/edit |
edit | photo.edit |
PUT/PATCH | /photo/{photo} |
update | photo.update |
DELETE | /photo/{photo} |
destroy | photo.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にアクセスできるようになります。
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
class PhotoCommentController extends Controller
{
/**
* 特定の写真のコメント表示
*
* @param int $photoId
* @param int $commentId
* @return Response
*/
public function show($photoId, $commentId)
{
//
}
}
リソースコントローラーへのルート追加
デフォルトのリソースルート以外のルートをリソースコントローラーへ追加する場合は、Route::resource
の呼び出しより前に定義する必要があります。そうしないと、resouce
メソッドにより定義されるルートが、追加のルートより意図に反して優先されます。
Route::get('photos/popular', 'PhotoController@method');
Route::resource('photos', 'PhotoController');
暗黙のコントローラー
Laravelでは一つのルート定義だけで、コントローラーの全アクションを簡単に定義できます。最初に、Route::controller
メソッドで、そのルートを定義します。controller
メソッドは2つの引数を取ります。最初はコントローラーが処理するベースのURIで、2つ目はコントローラーのクラス名です。
Route::controller('users', 'UserController');
次にコントローラーへメソッドを追加します。メソッド名はHTTP動詞で始まり、それ以降は先頭を大文字にしたURIのセグメントです。
<?php
namespace App\Http\Controllers;
class UserController extends Controller
{
/**
* GET /usersのリクエストに対応
*/
public function getIndex()
{
//
}
/**
* GET /users/show/1のリクエストに対応
*/
public function getShow($id)
{
//
}
/**
* GET /users/admin-profileのリクエストに対応
*/
public function getAdminProfile()
{
//
}
/**
* POST /users/profileのリクエストに対応
*/
public function postProfile()
{
//
}
}
上の例にあるように、index
メソッドはルートのURI、この場合はusers
をコントローラーで処理するために用意します。
ルート名の指定
コントローラーのルートに名前を付ける場合は、controller
メソッドの第3引数に名前の配列を指定することができます。
Route::controller('users', 'UserController', [
'getShow' => 'user.show',
]);
依存注入とコントローラー
コンストラクターインジェクション
全コントローラーの依存を解決するために、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の契約もタイプヒントに指定できます。コンテナが解決できるのであれば、タイプヒントで指定できます。
メソッドインジェクション
コンストラクターによる注入に加え、コントローラーのメソッドでもタイプヒントにより依存を指定することもできます。たとえば、あるメソッドでIlluminate\Http\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');
//
}
}
コントローラーメソッドへルートパラメーターによる入力値が渡される場合でも、依存定義の後に続けてルート引数を指定するだけです。たとえば以下のようにルートが定義されていれば:
Route::put('user/{id}', 'UserController@update');
下記のようにIlluminate\Http\Request
をタイプヒントで指定しつつ、コントローラーメソッドで定義しているid
ルートパラメータにアクセスできます。
<?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:cache
Arisanコマンドを実行するだけです。
php artisan route:cache
これだけです!キャッシュされたルートファイルは、app/Http/routes.php
ファイルの代わりに使用されるようになります。その代わりに、新しいルートの追加を反映するには、キャッシュしたルートを再構築する必要があります。ですからプロジェクトの開発期間の最後に、一度だけroute:cache
を実行するほうが良いでしょう。
新しいキャッシュルートのファイルを削除するには、route:clear
コマンドを使います。
php artisan route:clear