フォームリクエストの作成
現在バリデーションの実装でフォームリクエスト
を使用している。
公式ドキュメントより(一部抜粋)
より複雑なバリデーションのシナリオでは、「フォームリクエスト」を生成したほうが良いでしょう。フォームリクエストは、バリデーションロジックを含んだカスタムリクエストクラスです。
上記に「複雑なバリデーション」とあるが、今回の内容は至って簡単。投稿記事articleのタイトルと内容が入力されているかどうかの確認だ。
早速以下のコマンドを実行し、ArticleRequest
の作成を編集を行う。
$ php artisan make:request ArticleRequest
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ArticleRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'title' => 'required',
'content' => 'required',
];
}
public function messages()
{
return [
'title.required' => 'タイトルを入力してください。',
'content.required' => '内容を入力してください。',
];
}
}
ArticleController
に追記・修正を行う箇所はこれだけだった。
# 省略
use App\Http\Requests\ArticleRequest;
# 省略
public function create(ArticleRequest $request)
# 省略
public function update(ArticleRequest $request)
# 省略
新規登録機能のバリデーション
フォームを以下のように編集した。詳しい説明は後に編集用のビューで行うので、今回は省略する。
@extends('...layouts.layout')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
<h4>投稿作成</h4>
@if (count($errors) > 0)
<p>入力項目を再度確認してください。</p>
@endif
<form action='{{ route('article_create') }}' method='post' class="form">
{{ csrf_field() }}
<div class="form-group">
@if ($errors->has('title'))
@foreach($errors->get('title') as $title_error)
<ul>
<li>
{{ $title_error }}
</li>
</ul>
@endforeach
@endif
<input type="text" class="form-control" name='title' value = "{{ old('title') }}" placeholder="タイトル">
</div>
<div class="form-group">
@if ($errors->has('content'))
@foreach($errors->get('content') as $content_error)
<ul>
<li>
{{ $content_error }}
</li>
</ul>
@endforeach
@endif
<textarea class="form-control" name='content' placeholder="内容" rows="3">{{ old('content') }}</textarea>
</div>
<div class="form-group">
<input type='submit' button class="btn btn-embossed btn-primary"></button>
</div>
</form>
</div>
</div>
</div>
@endsection
編集機能のバリデーション
課題
編集機能にバリデーションを適用してビューに反映させる方法は、新規登録機能のそれと少し異なる。以下に、行うべき処理を書き出した。
- 編集ボタンをクリックした直後のフォームには、
以前に登録した内容
が入っている。 - 編集後にバリデーションで弾かれた場合、以前登録した内容ではなく
直前に入力した内容
をフォームに反映させたい。 - そのため、
バリデーションが通った場合、弾かれた場合の2種類の処理
を用意する必要がある。
ビューで解決
本来ならば、ビュー側であれこれ処理をさせるのは良くない。しかし、他に解決策が思いつかなかったのでとりあえずこれで実装した。かなりお見苦しいが、何かの参考になればと思い、コードを全て掲載する。
非常に見辛いため、いくつかに分割して説明する。
其の一
- ここは以前と同じ。
@extends('...layouts.layout')
@section('content')
<div class="container">
<div class="row">
<div class="col-md-8 offset-md-2">
投稿編集<br>
<form action='{{ route('article_update') }}' method='post'>
{{ csrf_field() }}
其の二
- ここは、バリデーションを無事通過した場合の処理である。
@if (!(count($errors) > 0))
でバリデーションエラーの有無を判断しているが、その他に大幅な変更はない。 -
$errors
にはバリデーションで発生したエラーメッセージが格納されている。これはフォームリクエストの実行により作成されたインスタンスで、コントローラから渡されている訳ではではない。
@if (!(count($errors) > 0))
<input type='hidden' name='id' value='{{ $article->id }}'>
<div class="form-group">
名前:{{ $article->user->name }}
</div>
<div class="form-group">
タイトル:<input type='text' class="form-control" name='title' value='{{ $article->title }}'>
</div>
<div class="form-group">
内容:<textarea class="form-control" name='content' rows="3">{{ $article->content }}</textarea>
</div>
其の三
- ここから、バリデーションで弾かれた場合の処理になる。
直前に入力した内容
をフォームに反映させるため、old関数
を使用している。
old関数の注意点については、前回の記事を参考していただければ。
【Laravel】Bladeにおけるold関数の使い方
@else
<p>入力項目を再度確認してください。</p>
<input type='hidden' name='id' value='{{ old('id') }}'>
<div class="form-group">
名前:{{ $article->user->name }}
</div>
其の四
-
@if ($errors->has('title'))
でhasメソッド
を利用し、引数の'title'に関するエラー
の有無を確認する。 - エラーがあれば、
$errors->get('title')
のgetメソッド
でエラーメッセージを配列形式で取得し、順次表示させていく。 - 今回バリデーションで使用した検証ルールは
required
のみだが、検証ルールを複数併用することも可能である。 - しかし、
requiredと他の検証ルールを併用
すると、requiredで最初に弾かれた場合に他のエラーメッセージが表示されなかった。(そもそも、required後のバリデーションも行われていたのだろうか?)
<div class="form-group">
@if ($errors->has('title'))
@foreach($errors->get('title') as $title_error)
<ul>
<li>
{{ $title_error }}
</li>
</ul>
@endforeach
@endif
<input type="text" class="form-control" name='title' value = "{{ old('title') }}">
</div>
<div class="form-group">
@if ($errors->has('content'))
@foreach($errors->get('content') as $content_error)
<ul>
<li>
{{ $content_error }}
</li>
</ul>
@endforeach
@endif
<textarea class="form-control" name='content' placeholder="内容" rows="3">{{ old('content') }}</textarea>
</div>
@endif
<div class="form-group">
<input type='submit' button class="btn btn-embossed btn-primary"></button>
</div>
</form>
</div>
</div>
</div>
@endsection
本当はこうしたい
- 編集用のビューは、バリデーション通過の有無を問わず同じものを使用しているので、渡す変数だけを変更したい。
- コントローラではなく、フォームリクエストに処理をまとめたい。
- ビュー自体をリファタリングしたい。
今回はここまで。