はじめに
ララベルのバリデーション実装時に躓いたので、備忘録も兼てまとめたいと思います。
バリデーションの種類
Laravelのバリデーションは大きく分けて二つあります。
1.validateメソッドを使ってコントローラーに記述する
2.フォームリクエストバリデーション
どちらを使った方がいいのか
時と場合によりますが、特に理由がなければフォームバリデーションを使った方が良い。
理由としてファットコントローラーを避けるため。コントローラーにはなるべくロジックは書きたくないので、分けられるなら分けた方が良い
フォームリクエストバリデーションのファイルはバリデーションの処理しか書かないので分かりやすい。
今回はフォームリクエストバリデーションについてまとめたいと思います
フォームリクエストバリデーションの使い方
まずは下記コマンドでフォームリクエストバリデーションを実装するファイルを作ります。
php artisan make:request StoreEventRequest
そうすると
App\Http\Requests配下にStoreEventRequestが生成されます
コントローラー
1.useでStoreEventRequestを参照する
2.保存処理をするメソッドの引数を、StoreEventRequestにする。
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreEventRequest;
class EventController extends Controller
{
// 省略
public function store(StoreEventRequest $request)
{
// 処理
}
// 省略
}
フォームリクエストバリデーション
初期表示
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreEventRequest
extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* @return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* @return array<string, mixed>
*/
public function rules()
{
return [
//
];
}
}
実装後
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class StoreEventRequest
extends FormRequest
{
/**
* 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<string, mixed>
*/
public function rules()
{
return [
'event_name' => ['required', 'max:50'],
'information' => ['required', 'max:200'],
'event_date' => ['required', 'date'],
'start_time' => ['required'],
'end_time' => ['required', 'after:start_time'],
'max_people' => ['required', 'numeric', 'between:1,20'],
'is_visible' => ['required', 'boolean']
];
}
/**
* 定義済みバリデーションルールのエラーメッセージ取得
*
* @return array<string, string>
*/
public function attributes(): array
{
return [
'event_name' => 'イベント名',
'information' =>'イベント詳細',
'event_date' =>'イベント日付',
'start_time' =>'開始時間',
'end_time' =>'終了時間',
'max_people' =>'定員数',
'is_visible' =>'表示・非表示'
];
}
/**
* バリデーションエラーのカスタム属性の取得
*
* @return array<string, string>
*/
public function messages(): array
{
return [
'event_name.required' => ':attributeを入力してください',
'event_name.max_length' => ':attributeは50文字以内で入力してください',
'information.required' =>':attributeを入力してください',
'event_date.required' =>':attributeを入力してください',
'start_time.required' =>':attributeを入力してください',
'end_time.required' =>':attributeを入力してください',
'max_people.required' =>':attributeを入力してください',
'is_visible.required' =>':attributeを選択してください'
];
}
}
説明
rules()について
rules()には、キーにフォームのname要素、バリューにどんなバリデーションをつけたいか記述する。
public function rules()
{
return [
'name要素' => どんなバリデーションにするか,
];
}
バリューに関しては色々なレパートリーがある。
attributes()について
messages()の:attributeの名前を指定することが出来ます。
messages()について
rules()で指定したエラーが起きたときに、attributes()で指定した名前でエラーを表示することが出来ます。
bladeでエラーを表示させる方法
フォームの上に下記記述をすることで、エラーをリスト表示することが出来ます
@if ($errors->any()) //エラーがあるか判定
<div style="color:red" class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li> //エラーを表示
@endforeach
</ul>
</div>
@endif
実際の表示
実際のblade
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
イベント新規登録
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<div class="max-w-2xl py-4 mx-auto">
@if ($errors->any())
<div style="color:red" class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
<form method="POST" action="{{ route('events.store') }}">
@csrf
<div>
<x-jet-label for="event_name" value="イベント名" />
<x-jet-input id="event_name" class="block mt-1 w-full" type="text" name="event_name" :value="old('event_name')" />
</div>
<div class="mt-4">
<x-jet-label for="information" value="イベント詳細" />
<textarea row="3" id="information" name="information" class="block mt-1 w-full">{{ old('information') }}</textarea>
</div>
<div class="md:flex justify-between">
<div class="mt-4">
<x-jet-label for="event" value="イベント日付" />
<x-jet-input id="event_date" class="block mt-1 w-full" type="text" name="event_date" />
</div>
<div class="mt-4">
<x-jet-label for="start_time" value="開始時間" />
<x-jet-input id="start" class="block mt-1 w-full" type="text" name="start_time" />
</div>
<div class="mt-4">
<x-jet-label for="end_time" value="終了時間" />
<x-jet-input id="end_time" class="block mt-1 w-full" type="text" name="end_time" />
</div>
</div>
<div class="md:flex justify-between items-end">
<div class="mt-4">
<x-jet-label for="max_people" value="定員数" />
<x-jet-input id="max_people" class="block mt-1 w-full" type="number" name="max_people" />
</div>
<div class="flex space-x-4 justify-around">
<input type="radio" name="is_visible" value="1" chacked />表示
<input type="radio" name="is_visible" value="0" />非表示
</div>
<x-jet-button class="ml-4">
新規登録
</x-jet-button>
</div>
</form>
</div>
</div>
</div>
</div>
<script src="{{ mix('js/flatpickr.js')}}"></script>
</x-app-layout>
これでフォームリクエストバリデーションを使って、エラーを表示することが出来ました。
次はリスト表示ではなく、入力欄の上にバリデーションメッセージを表示させたいと思います。
実際の表示
すみません。
レイアウト崩れてますが、入力欄の上にバリデーションが表示されています。
実装方法
各入力欄の上に下記記述
@if($errors->has('event_name'))
@foreach ($errors->get('event_name') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
$messageは、StoreEventRequestの、messages()の値を表示させています。
実際のblade
<x-app-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
イベント新規登録
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
<div class="max-w-2xl py-4 mx-auto">
@if ($errors->any())
<p style="color: red">入力内容に誤りがあります</p>
@endif
<form method="POST" action="{{ route('events.store') }}">
@csrf
@if($errors->has('event_name'))
@foreach ($errors->get('event_name') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
<div>
<x-jet-label for="event_name" value="イベント名" />
<x-jet-input id="event_name" class="block mt-1 w-full" type="text" name="event_name" :value="old('event_name')" />
</div>
@if($errors->has('information'))
@foreach ($errors->get('information') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
<div class="mt-4">
<x-jet-label for="information" value="イベント詳細" />
<textarea row="3" id="information" name="information" class="block mt-1 w-full">{{ old('information') }}</textarea>
</div>
<div class="md:flex justify-between">
@if($errors->has('event_date'))
@foreach ($errors->get('event_date') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
<div class="mt-4">
<x-jet-label for="event" value="イベント日付" />
<x-jet-input id="event_date" class="block mt-1 w-full" type="text" name="event_date" />
</div>
@if($errors->has('start_time'))
@foreach ($errors->get('start_time') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
<div class="mt-4">
<x-jet-label for="start_time" value="開始時間" />
<x-jet-input id="start" class="block mt-1 w-full" type="text" name="start_time" />
</div>
@if($errors->has('end_time'))
@foreach ($errors->get('end_time') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
<div class="mt-4">
<x-jet-label for="end_time" value="終了時間" />
<x-jet-input id="end_time" class="block mt-1 w-full" type="text" name="end_time" />
</div>
</div>
@if($errors->has('max_people'))
@foreach ($errors->get('max_people') as $message)
<p style="color: red">{{ $message }}</p>
@endforeach
@endif
<div class="md:flex justify-between items-end">
<div class="mt-4">
<x-jet-label for="max_people" value="定員数" />
<x-jet-input id="max_people" class="block mt-1 w-full" type="number" name="max_people" />
</div>
<div class="flex space-x-4 justify-around">
<input type="radio" name="is_visible" value="1" chacked />表示
<input type="radio" name="is_visible" value="0" />非表示
</div>
<x-jet-button class="ml-4">
新規登録
</x-jet-button>
</div>
</form>
</div>
</div>
</div>
</div>
<script src="{{ mix('js/flatpickr.js')}}"></script>
</x-app-layout>
本日は以上となります。
最後まで見ていただきありがとうございました!