Laravel5.5 LTS 日本語ドキュメント

このリポジトリはPHP Webアプリフレームワークである、LaravelのLTSバージョンである5.5の公式英文ドキュメントを日本語へ翻訳しています。

This project is maintained by okinaka

コントローラ

イントロダクション

全リクエストの処理をルートファイルのクロージャで定義するよりも、コントローラクラスにより組織立てたいと、皆さんも考えるでしょう。関連のあるHTTPリクエストの処理ロジックを一つのクラスへまとめ、グループ分けができます。コントローラはapp/Http/Controllersディレクトリ下に設置します。

基本のコントローラ

コントローラの定義

これは基本的なコントローラの一例です。全てのLaravelコントローラはLaravelに含まれている基本コントローラクラスを拡張します。コントローラアクションにミドルウェアを追加するために使うmiddlewareメソッドのように、便利なメソッドをベースクラスは提供しています。

<?php

namespace App\Http\Controllers;

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

class UserController extends Controller
{
    /**
     * 指定ユーザーのプロフィール表示
     *
     * @param  int  $id
     * @return Response
     */
    public function show($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

コントローラアクションへルート付けるには、次のようにします。

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

これで指定したルートのURIにリクエストが一致すれば、UserControllershowメソッドが実行されます。もちろん、ルートパラメーターはメソッドに渡されます。

{tip} コントローラはベースクラスの拡張を要求してはいません。しかし、middlewarevalidatedispatchのような便利な機能へアクセスできなくなります。

コントローラと名前空間

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

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

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

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

アクションを一つだけ含むコントローラを定義したい場合は、そのコントローラに__invokeメソッドを設置してください。

<?php

namespace App\Http\Controllers;

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

class ShowProfile extends Controller
{
    /**
     * 指定ユーザーのプロフィール表示
     *
     * @param  int  $id
     * @return Response
     */
    public function __invoke($id)
    {
        return view('user.profile', ['user' => User::findOrFail($id)]);
    }
}

シングルアクションコントローラへのルートを定義するとき、メソッドを指定する必要はありません。

Route::get('user/{id}', 'ShowProfile');

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

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

Route::get('profile', 'UserController@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);
});

{tip} コントローラアクションの一部へミドルウェアを適用することはできますが、しかしながら、これはコントローラが大きくなりすぎたことを示しています。代わりに、コントローラを複数の小さなコントローラへ分割することを考えてください。

リソースコントローラ

Laravelリソースルートは一行のコードで、典型的な「CRUD」ルートをコントローラへ割り付けます。たとえば、アプリケーションへ保存されている「写真(photo)」に対する全HTTPリクエストを処理するコントローラを作成したいとしましょう。make:controller Artisanコマンドを使えば、このようなコントローラは素早く生成できます。

php artisan make:controller PhotoController --resource

このArtisanコマンドはapp/Http/Controllers/PhotoController.phpとしてコントローラファイルを生成します。コントローラは使用可能な各リソース操作に対するメソッドを含んでいます。

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

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

リソースに対する様々なアクションを処理する、複数のルートがこの1定義により生成されます。これらのアクションをHTTP動詞と処理するURIの情報を注記と一緒に含むスタブメソッドとして、生成されたコントローラはすでに含んでいます。

一度に多くのリソースコントローラを登録するには、resourcesメソッドへ配列で渡します。

Route::resources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);

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

動詞 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

リソースモデルの指定

ルートモデル結合を使用しているが、リソースコントローラのメソッドでタイプヒントされるモデルインスタンスを指定したい場合は、コントローラの生成時に--modelオプションを使用します。

php artisan make:controller PhotoController --resource --model=Photo

擬似フォームメソッド

HTMLフォームはPUTPATCHDELETEリクエストを作成できませんので、HTTP動詞を偽装するために、_method隠しフィールドを追加する必要が起きるでしょう。method_fieldヘルパで、このフィールドを生成できます。

部分的なリソースルート

リソースルートの宣言時に、デフォルトアクション全部を指定する代わりに、ルートで処理するアクションの一部を指定可能です。

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

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

APIリソースルート

APIに使用するリソースルートを宣言する場合、createeditのようなHTMLテンプレートを提供するルートを除外したいことがよく起こります。そのため、これらの2ルートを自動的に除外する、apiResourceメソッドが使用できます。

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

apiResourcesメソッドに配列として渡すことで、一度に複数のAPIリソースコントローラを登録できます。

Route::apiResources([
    'photos' => 'PhotoController',
    'posts' => 'PostController'
]);

リソースルートの命名

全てのリソースコントローラアクションは、デフォルトのルート名が決められています。しかし、オプションにnames配列を渡せば、こうした名前をオーバーライドできます。

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

リソースルートパラメータの命名

Route::resourceはデフォルトで、リソース名の「単数形」にもとづき、リソースルートのルートパラメータを生成します。オプション配列でparametersを指定することで簡単に、このリソース毎の基本的な命名規約をオーバーライドできます。parameters配列は、リソース名とパラメータ名の連想配列で指定します。

Route::resource('user', 'AdminUserController', ['parameters' => [
    'user' => 'admin_user'
]]);

上記のサンプルコードは、リソースのshowルートで次のURIを生成します。

/user/{admin_user}

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

Route::resourceはデフォルトで、リソースURIに英語の動詞を使います。createeditアクションの動詞をローカライズする場合は、Route::resourceVerbsメソッドを使います。このメソッドは、AppServiceProviderbootメソッド中で呼び出します。

use Illuminate\Support\Facades\Route;

/**
 * 全アプリケーションサービスの初期起動処理
 *
 * @return void
 */
public function boot()
{
    Route::resourceVerbs([
        'create' => 'crear',
        'edit' => 'editar',
    ]);
}

動詞をカスタマイズすると、Route::resource('fotos', 'PhotoController')のようなリソースルートの登録により、以下のようなURIが生成されるようになります。

/fotos/crear

/fotos/{foto}/editar

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

デフォルトのリソースルート以外のルートをリソースコントローラへ追加する場合は、Route::resourceの呼び出しより前に定義する必要があります。そうしないと、resourceメソッドにより定義されるルートが、追加のルートより意図に反して優先されます。

Route::get('photos/popular', 'PhotoController@method');

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

{tip} コントローラの責務を限定することを思い出してください。典型的なリソースアクションから外れたメソッドが繰り返して必要になっているようであれば、コントローラを2つに分け、小さなコントローラにすることを考えましょう。

依存注入とコントローラ

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

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

<?php

namespace App\Http\Controllers;

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;

class UserController extends Controller
{
    /**
     * 新ユーザーの保存
     *
     * @param  Request  $request
     * @return Response
     */
    public function store(Request $request)
    {
        $name = $request->name;

        //
    }
}

コントローラメソッドへルートパラメーターによる入力値が渡される場合でも、依存定義の後に続けてルート引数を指定するだけです。たとえば以下のようにルートが定義されていれば:

Route::put('user/{id}', 'UserController@update');

下記のようにIlluminate\Http\Requestをタイプヒントで指定しつつ、コントローラメソッドで定義しているidパラメータにアクセスできます。

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    /**
     * 指定ユーザーの更新
     *
     * @param  Request  $request
     * @param  string  $id
     * @return Response
     */
    public function update(Request $request, $id)
    {
        //
    }
}

ルートキャッシュ

{note} ルートキャッシュはクロージャベースのルートには動作しません。ルートキャッシュを使用するには、全クロージャルートをコントローラクラスを使用するように変更する必要があります。

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

php artisan route:cache

このコマンドを実行後、キャッシュ済みルートファイルが、リクエストのたびに読み込まれます。新しいルートを追加する場合は、新しいルートキャッシュを生成する必要があることを覚えておきましょう。ですからプロジェクトの開発期間の最後に、一度だけroute:cacheを実行するほうが良いでしょう。

キャッシュルートのファイルを削除するには、route:clearコマンドを使います。

php artisan route:clear