フォームのビジネスロジック(検証や保存)をコントローラに書くと、どうでも良いコードでコントローラが重くなってくる。フォームが複数ある場合、だいたい似たり寄ったりのコードが量産されていく。本エントリでは、Laravel5 の Form Request Validation によってコントローラからバリデーションロジックを完全分離する方法について記述する。
Form Request Validation – バリデーションの分離
流れは以下の通り。
- App\Http\Requests\Requestクラスを派生し、ContactRequestクラスを作成する。
- コントローラメソッドにて、App\Http\Requests\Requestクラスのインスタンスではなく ContractRequestクラスのインスタンスを受けるようにする。
- コントローラメソッドに入ったときには既にContactRequestクラスによるバリデーションが完了していて、データが正しい前提で処理できる。
ContactRequestクラス、ContactRequestTraitクラスの例を以下に示す。
<?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' => '内容',
];
}
}
<?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()メソッドに入る。バリデーションが失敗すると、その前のアドレスにリダイレクトされる。コントローラから一切のバリデーションロジックを排除できた。
<?php
namespace 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)
{
}
}