フォームのビジネスロジック(検証や保存)をコントローラに書くと、どうでも良いコードでコントローラが重くなってくる。フォームが複数ある場合、だいたい似たり寄ったりのコードが量産されていく。本エントリでは、Laravel5 の Form Request Validation によってコントローラからバリデーションロジックを完全分離する方法について記述する。
Form Request Validation – バリデーションの分離
流れは以下の通り。
- App\Http\Requests\Requestクラスを派生し、ContactRequestクラスを作成する。
- コントローラメソッドにて、App\Http\Requests\Requestクラスのインスタンスではなく ContractRequestクラスのインスタンスを受けるようにする。
- コントローラメソッドに入ったときには既にContactRequestクラスによるバリデーションが完了していて、データが正しい前提で処理できる。
ContactRequestクラス、ContactRequestTraitクラスの例を以下に示す。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
<?php namespace App\Http\Requests; class ContactRequest extends Request { use ConfirmRequestTrait; /** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() { return true; } /** * Get the validation rules that apply to the request. * * @return array */ public function rules() { return [ 'name' => 'required', 'email' => 'required|email', 'subject' => 'required', 'content' => 'required', ]; } /** * Set custom messages for validator errors. * * @return array */ public function messages() { return [ // ]; } /** * Set custom attributes for validator errors. * * @return array */ public function attributes() { return [ 'name' => 'お名前', 'email' => 'メールアドレス', 'subject' => '件名', 'content' => '内容', ]; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
<?php namespace App\Http\Requests; use Illuminate\Contracts\Validation\Validator; trait ConfirmRequestTrait { /** * Set custom messages for validator errors. * * @param \Illuminate\Contracts\Validation\Factory $factory * * @return \Illuminate\Contracts\Validation\Validator */ public function validator($factory) { // 値検証前の処理 if (method_exists($this, 'beforeValidate')) { $this->beforeValidate(); } $validator = $factory->make( $this->all(), $rules, $this->messages(), $this->attributes() ); $validator->after(function ($validator) { $failed = $validator->failed(); // 値検証後の処理 if (method_exists($this, 'afterValidate')) { $this->afterValidate($validator); } }); return $validator; } /** * Format the errors from the given Validator instance. * * @param \Illuminate\Contracts\Validation\Validator $validator * * @return array */ protected function formatErrors(Validator $validator) { $errors = parent::formatErrors($validator); return $errors; } } |
Form Request Validation – コントローラ側
ポイントは、storeメソッドの引数に ContactRequestヒントが渡されていること。sotreメソッドに入る前にContactRequestによりバリデーションが実行され、バリデーションに成功した時に限り、sotre()メソッドに入る。バリデーションが失敗すると、その前のアドレスにリダイレクトされる。コントローラから一切のバリデーションロジックを排除できた。
<?phpnamespace App¥Http¥Controllers;
use App¥Http¥Requests¥ContactRequest;
use App¥Repositories¥ContactRepository;class ContactController extends Controller
{
/**
/* @var ContactRepository
*/
protected $repository;/**
/* @constructor
/* param ContactRepository $repository
*/
public function __construct(ContactRepository $repository)
{
$this->repository = $repository;
}/*
*
*/
public function index()
{
...
}/**
* @var ContactRequest $request
*
*/
public function store(ContactRequest $request)
{}
}