【Laravel】フォームリクエストで新規・編集のバリデーション を行う

# フォームリクエストの作成

現在バリデーションの実装で``フォームリクエスト``を使用している。 

公式ドキュメントより（一部抜粋）

>より複雑なバリデーションのシナリオでは、「フォームリクエスト」を生成したほうが良いでしょう。フォームリクエストは、バリデーションロジックを含んだカスタムリクエストクラスです。

上記に「複雑なバリデーション」とあるが、今回の内容は至って簡単。投稿記事articleのタイトルと内容が入力されているかどうかの確認だ。

早速以下のコマンドを実行し、``ArticleRequest``の作成を編集を行う。

```
$ php artisan make:request ArticleRequest
```

```ArticleRequest.php
<?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``に追記・修正を行う箇所はこれだけだった。

```ArticleController.php
# 省略
use App\Http\Requests\ArticleRequest;
# 省略
public function create(ArticleRequest $request)
# 省略
public function update(ArticleRequest $request)
# 省略
```
# 新規登録機能のバリデーション

フォームを以下のように編集した。詳しい説明は後に編集用のビューで行うので、今回は省略する。

```article/add.blade.php
@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
```


# 編集機能のバリデーション 

## 課題

編集機能にバリデーションを適用してビューに反映させる方法は、新規登録機能のそれと少し異なる。以下に、行うべき処理を書き出した。

- 編集ボタンをクリックした直後のフォームには、``以前に登録した内容``が入っている。
- 編集後にバリデーションで弾かれた場合、以前登録した内容ではなく``直前に入力した内容``をフォームに反映させたい。
- そのため、``バリデーションが通った場合、弾かれた場合の２種類の処理``を用意する必要がある。

## ビューで解決

本来ならば、ビュー側であれこれ処理をさせるのは良くない。しかし、他に解決策が思いつかなかったのでとりあえずこれで実装した。かなりお見苦しいが、何かの参考になればと思い、コードを全て掲載する。

非常に見辛いため、いくつかに分割して説明する。

### 其の一

- ここは以前と同じ。

```article/edit.blade.php
@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``にはバリデーションで発生したエラーメッセージが格納されている。これはフォームリクエストの実行により作成されたインスタンスで、コントローラから渡されている訳ではではない。

```article/edit.blade.php
                @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関数の使い方](https://qiita.com/33yuki/items/8bddeba1150437389eb0)

```article/edit.blade.php
                @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後のバリデーションも行われていたのだろうか？）

```article/edit.blade.php
                    <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
```

## 本当はこうしたい

- 編集用のビューは、バリデーション通過の有無を問わず同じものを使用しているので、渡す変数だけを変更したい。
- コントローラではなく、フォームリクエストに処理をまとめたい。
- ビュー自体をリファタリングしたい。

今回はここまで。