コントローラーのファイルが大きくなってきたな、と思ったら、FormRequestを使ってみようかと真剣に考え始めました。まずは、FormRequestとは何ものかの紹介からです。

FormRequestを使わないコントローラ

FormRequestを使わないコントローラというのは、例えば以下のコードに代表されます。

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth'); //認証したユーザーのみがアクセス可能
    }

    public function edit()
    {
    	$user = auth()->user(); // 認証したユーザーの情報を取得

    	return view('user_edit')->with(compact('user'));
    }

    public function update(Request $request)
    {
       // リクエストのバリデーション
    	$validated = $request->validate([
    		'name'  => 'required',
    		'email' => 'required|email',
    	]);

        // DBの情報を更新
    	auth()->user()->update($validated);

        // ホーム画面へリダイレクト
    	return redirect()->route('home');
    }
}

このコントローラを使用する、routeは以下のように定義されます。

Route::get('/', function () {
    return view('welcome');
});

Auth::routes();

Route::get('/home', 'HomeController@index')->name('home');

Route::get('/user/edit', 'UserController@edit')->name('user.edit');
Route::put('/user/edit', 'UserController@update')->name('user.update');

よく見て欲しいのは、UserController::update()のメソッド。
リクエストの入力値をバリデートして、バリデーションをパスした入力値をそのまま、EloquestUserオブジェクト(auth()->user)のupdate()に渡して更新です。

ちなみに、このコントローラは、ログインしたユーザーが自分の情報を編集するためです。Laravelのデフォルトのプロジェクトにはユーザー認証のコードがついてきますが、この機能はありません。

FormRequestを使用したら

まず、コマンドラインから、FormRequestの作成です。

$ php artisan make:request UserRequest

これで、UserRequest.phpが作成されます。それを以下のように編集します。

amespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true; // すでにUserController::__construct()でチェックしてあるので、true
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'  => 'required',
            'email' => 'required|email',
        ];
    }
}

見ての通り、コントローラにあったバリデーションルールが移動されています。

コントローラの方は、


namespace App\Http\Controllers;

use App\Http\Requests\UserRequest; //ここで宣言

class UserController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }

    public function edit()
    {
    	$user = auth()->user();

    	return view('user_edit')->with(compact('user'));
    }

    public function update(UserRequest $request)
    {
    	auth()->user()->update($request->validated()); // 1行になりました

    	return redirect()->route('home');
    }
}

FormRequestを使うことでコントローラのコードの行数は減りました。しかし、FormRequestの定義のファイルが増えて全体のコードの行数は増えたことも事実。今回のような、簡単なコードではあまり得したことにはならない感じですね。ない方がわかりやすいとも思えます。しかし、もしバリデーションルールがもっとたくさんあったら、FormRequestはベターなのは明らかです。コードが複雑になったらリファクターして新規の関数を作成するのと同じかな。

しかし、FormRequestを使うことに関して他の利点はなんでしょう?次回からそれらの利点を探ってみます。

編集のブレード

参考として、作成したブレードファイルも掲載します。resources/views/auth/register.blade.phpをもとにしましたが、Eメールの入力において、type="email"のところ、type="text"にしています。バリデーションエラーの表示をテストしたかったためです。


@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('Register') }}</div>

                <div class="card-body">
                    <form method="POST" action="{{ route('user.edit') }}">
                        @csrf
                        @method('PUT')

                        <div class="form-group row">
                            <label for="name" class="col-md-4 col-form-label text-md-right">{{ __('Name') }}</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control @error('name') is-invalid @enderror" name="name" value="{{ old('name', $user->name) }}" required autocomplete="name" autofocus>

                                @error('name')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row">
                            <label for="email" class="col-md-4 col-form-label text-md-right">{{ __('E-Mail Address') }}</label>

                            <div class="col-md-6">
                                <input id="email" type="text" class="form-control @error('email') is-invalid @enderror" name="email" value="{{ old('email', $user->email) }}" required autocomplete="email">

                                @error('email')
                                    <span class="invalid-feedback" role="alert">
                                        <strong>{{ $message }}</strong>
                                    </span>
                                @enderror
                            </div>
                        </div>

                        <div class="form-group row mb-0">
                            <div class="col-md-6 offset-md-4">
                                <button type="submit" class="btn btn-primary">
                                    {{ __('Register') }}
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

By khino