バリデーションをカスタマイズする
フォームリクエスト
コントローラはそれぞれのアクションで実行すべきビジネスロジックなどを実行することになるため、
「入力された値のチェック」などはできれば他に切り離したい。
(フォームの項目にバリデーション機能を実装する際に、各コントローラに書くのは面倒。)
そこでLarabelでは「フォームリクエスト」と呼ばれる機能を考えました。
フォームリクエストの作成
フォームリクエストは「artisan make:request」というコマンドを使って作成します。
% php artisan make:request HelloRequest
フォームリクエストの基本コード
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class HelloRequest extends FormRequest
{
public function authorize()
{
return false;
}
public function rules()
{
return [
//
];
}
}
- authorize
フォームリクエストの利用が許可されているかどうかを指します。
(trueだと許可され、falseだと不許可になりHttpExceptionの例外処理が発生してドーム処理が行えなくなる。) - rules
適用されるバリデーションの検証ルールを設定します。
ここでreturnされた検証ルールをもとに、FormRequestでバリデーションチェックが実行されます。
フォームリクエストの修正
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class HelloRequest extends FormRequest
{
**「Hello」からのアクセスの時のみフォームリクエストを使用できるようにする**
public function authorize()
{
if ($this->path() == 'hello')
{
return true;
} else {
return false;
}
}
**バリデーション検証ルールを設定する**
public function rules()
{
return [
'name' => 'required',
'mail' => 'email',
'age' => 'numeric|between:0,150',
];
}
}
メッセージのカスタマイズ
エラーメッセージをカスタマイズするには、
フォームリクエストに「messages」というメソッドを追加します。
public function messages()
{
return [
'name.required' => '名前は必ず入力してください。',
'mail.email' => 'メールアドレスが必要です。',
'age.numeric' => '年齢を整数で記入ください。',
'age.between' => '年齢は0〜150の間で入力してください。',
];
}
このmessages
は、FormRequestのバリデーション機能が
エラーメッセージを必要とした時に呼び出されるメソッドです。
return [
'**項目名**.**ルール名**' => '**メッセージ**',
];
1つの項目に複数のルールが設定してある場合は、ルールごとに設定する。
(設定していない場合は、デフォルトのメッセージ<英語>がそのまま使われます。)
バリデータを使う
「エラーがあったらフォームページにリダイレクトせず、別の処理を行わせたい」時や、
「フォームの値以外でバリデーションチェックを行わせたい」時に、
バリデータを独自に用意して処理することもできます。
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use App\Http\Requests\HelloRequest;
use Illuminate\Support\Facades\Validator; **バリデータ使えるよう追記**
class HelloController extends Controller
{
public function index(Request $request) {
return view('hello.index',['msg'=>'フォームを入力']);
}
public function post(Request $request) {
$validator = Validator::make($request->all(), [
'name' => 'required',
'mail' => 'email',
'age' => 'numeric|between:0,150',
]);
if ($validator->fails()) {
return redirect('hello')
->withErrors($validator)
->withInput();
};
return view('hello.index',['msg'=>'正しく入力されました!']);
}
}
バリデータを使用できようにする際の追記の仕方がうまくいかなかったので、
以下のURLを参考にuse Illuminate\Support\Facades\Validator;
と
追加するすることで利用できるようになった。
call to undefined method Dotenv\Validator::make
バリデータの基本
validator = Validator::make(**値の配列**,**ルールの配列**)
第一引数に、チェックする値をまとめた配列を用意する。
第二引数に、バリデータで使用する検証ルールの情報を配列にまとめたものを指定する。
if ($validator->fails()) {**エラー時の処理**};
「fail」はValidatorクラスにあるメソッドで、バリデーションチェックに失敗したかどうか確認するためのメソッド。
戻り値が「true」ならエラーが発生しているので、
エラー時の処理を記述します。
if ($validator->fails()) {
return redirect('hello')
->withErrors($validator)
->withInput();
};
エラーが発生したらGETページにリダイレクトする処理を記述。
単にリダイレクトするだけでは、エラーメッセージやフォームの値などが受け取れないので、
上記のように記述します。
- withErrors
エラーメッセージの情報をリダイレクト時に渡す。 - withInput
フォームの入力情報をリダイレクト時に渡す。
クエリー文字列にバリデータを適用する
public function index(Request $request) {
$validator = Validator::make($request->query(), [
'id' => 'required',
'pass' => 'required',
]);
if ($validator->fails()) {
$msg = 'クエリ文字に問題がります。';
} else {
$msg = 'ID/PASSを受け付けました。フォームを入力ください。';
};
return view('hello.index',['msg'=>$msg,]);
}
request->query()
は、送信されたクエリー文字列を配列の形にまとめたものを返す。
エラーメッセージのカスタマイズ
validator = Validator::make(**値の配列**,**ルールの配列**,**メッセージ配列**)
public function post(Request $request) {
$rules = [
'name' => 'required',
'mail' => 'email',
'age' => 'numeric|between:0,150',
];
$messages = [
'name.required' => '名前は必ず入力してください。',
'mail.email' => 'メールアドレスが必要です。',
'age.numeric' => '年齢を整数で記入ください。',
'age.between' => '年齢は0〜150の間で入力してください。',
];
$validator = Validator::make($request->all(), $rules,$messages);
if ($validator->fails()) {
return redirect('hello')
->withErrors($validator)
->withInput();
};
return view('hello.index',['msg'=>'正しく入力されました!']);
}
条件に応じてルールを追加する
validator->sometimes(**項目名**,**ルール名**,**クロージャ**)
クロージャは、ルールをを追加すべきどうかを決定するものです。
function($input){
**処理を実行**
return 真偽値;
}
引数$input
は入力された値をまとめたものが渡される。
ここから、$input->name
といった具合にしてフォームの値を取り出すことができます。
戻り値は、ルールを追加するべきかどうか指定する真偽値になります。
false
の場合は、sometimesで指定したルールを指定した項目に追加します。
ルール追加の記述を追加する
public function post(Request $request) {
$rules = [
'name' => 'required',
'mail' => 'email',
'age' => 'numeric', **条件を整数のみに変更**
];
$messages = [
'name.required' => '名前は必ず入力してください。',
'mail.email' => 'メールアドレスが必要です。',
'age.numeric' => '年齢を整数で記入ください。',
'age.min' => '年齢はゼロ歳以上で記入ください。', **条件を追加**
'age.max' => '年齢は200歳以下で記入ください。', **条件を追加**
];
$validator = Validator::make($request->all(), $rules,$messages);
**追加したい条件を定義する**
$validator->sometimes('age', 'min:0',function ($input){
return !is_int($input->age);
});
**追加したい条件を定義する**
$validator->sometimes('age', 'max:200',function ($input){
return !is_int($input->age);
});
if ($validator->fails()) {
return redirect('hello')
->withErrors($validator)
->withInput();
};
return view('hello.index',['msg'=>'正しく入力されました!']);
}
$validator->sometimes('age', 'min:0',function ($input){
return !is_int($input->age);
});
!is_int($input->age);
により、$input->age
の値が整数の場合は、
「false」が返され、min:0
のルールがage
に追加されます。
オリジナルバリデータの作成
ルールそのものを新たに定義したい場合は、
「バリデータ」そのものを作成し、独自に処理を定義する方法があります。
バリデータクラスを作成する際に、コードを自動生成する機能はないので、
手作業でスクリプトファイルを作成する。
<?php
namespace App\Http\Validators;
use Illuminate\Validation\Validator;
class HelloValidator extends Validator
{
public function validateHello($attribute, $value, $parameters)
{
return $value % 2 == 0;
}
}
作成したHelloValidatorを組み込むためには、
サービスプロバイダを利用します。
以前作成した「HelloServiseProvider」というサービスプロバイダを再利用します。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use Dotenv\Validator;
use App\Http\Validators\HelloValidator;
class HelloServiceProvider extends ServiceProvider
{
public function boot()
{
$validator = $this->app['validator'];
$validator->resolver(function($translator, $data, $rules, $messages) {
return new HelloValidator($translator, $data, $rules, $messages);
});
}
}
バリデータは、$this->app['validator']
というところに保管されている。
このresolver
というメソッドで、リゾルブ(バリデーションの処理を行う)の処理を設定できる。
function($translator, $data, $rules, $messages) {
return **バリデータのインスタンス**;
}
この関数で、バリデータのインスタンスを戻り値で返すことによって、
このサービスプロバイダをバリデーションの処理として設定している。
new HelloValidator
の引数には、resolver
で渡された4つの引数を
そのまま指定している。
HelloValidatorのルールを使用する
今回は以前に作成した「HelloRequest.php」を利用する。
class HelloRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'required',
'mail' => 'email',
'age' => 'numeric|hello', **バリデータを指定**
];
}
public function messages()
{
return [
'name.required' => '名前は必ず入力してください。',
'mail.email' => 'メールアドレスが必要です。',
'age.numeric' => '年齢を整数で記入ください。',
'age.hello' => 'Hello!入力は偶数のみ受け付けます。', **バリデータを使用した際のメッセージを変更**
];
}
}
Validator::extend
を利用する
「このフォームでだけ、ちょっとしたカスタマイズしたルールを使いたい」場合は、
Validatorクラスの「extend」メソッドを利用します。
Validator::extend(*名前*, *クロージャ*);
第一引数は、指定した名前で、
第二引数は、クロージャをルールとして追加します。
クロージャは以下のように定義します。
public function validateHello($attribute, $value, $parameters,$validator)
{
*バリデーションの処理*
return *真偽値*;
}
引数にバリデータクラスを作成した時に定義したメソッドの引数($attribute, $value, $parameters)
と
バリデータのインスタンスを付け加えた4つの値が用意されます。
戻り値にtrue
を返せば、問題なし。
false
を返せばエラーが発生したことを示します。
実行すると、「Call to undefined method Dotenv\Validator::extend()」と、
Dotenv\Validator
クラスにある「extend」メソッドが定義されていないとエラーが出たので、
下記のURLを参考にuseを変更。
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\View;
use Illuminate\Support\Facades\Validator;
use App\Http\Validators\HelloValidator;
class HelloServiceProvider extends ServiceProvider
{
public function boot()
{
Validator::extend('hello', function($attribute, $value, $parameters, $validator) {
return $value % 2 == 0;
});
}
}
バリデーションルールを作る
Validatorクラスを利用したバリデータは、
サービスプロバイダのbootなどを組み込んで利用します。
この方法は、わかっていれば難しくはないが、バリデータの仕組みがわかっていないと、
うまく組み込めない可能性があります。
そこで、バリデータで利用する「ルール」を作って利用する方法もある。
バリデーションルールは「Illuminate\Contracts\Validation」名前空間の「Rule」という
クラスを継承して作られています。
このルールを継承したクラスを用意すれば、そのクラスをバリデーションのルールとして使えるようになります。
% php artisan make:rule Myrule
このコマンドによって、「app」のフォルダの中に、
「Myrule.php」というファイルが作られます。
バリデーションルールの基本形
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Myrule implements Rule
{
public function __construct()
{
//
}
public function passes($attribute, $value)
{
//
}
public function message()
{
return 'The validation error message.';
}
}
-
passes
passes
は、ルールの通過条件を設定します、
引数にはルールの属性(ルールの後に用意される設定関係)をまとめた$attribute
と、
チェックする値である$value
が用意されています。 -
message
message
は、問題発生時のメッセージを返すメソッドです。
ここでテキストを戻り値にすることで、エラーメッセージとして使うことができます。
Myruleクラスを作成する
<?php
namespace App\Rules;
use Illuminate\Contracts\Validation\Rule;
class Myrule implements Rule
{
public $num=2;
public function __construct($n)
{
$this->num = $n;
}
public function passes($attribute, $value)
{
return $value % $this->num == 0;
}
public function message()
{
return $this->num . 'で割り切れる値が必要です。';
}
}
<?php
namespace App\Http\Requests;
use App\Rules\Myrule;
use Illuminate\Foundation\Http\FormRequest;
class HelloRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'required',
'mail' => 'email',
'age' => 'numeric', new Myrule(5),
];
}
}
*エラーは出なかったが、正しく挙動しなかったので、復習時に再検証。