8
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-05-20

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

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

公式ドキュメントより(一部抜粋)

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

上記に「複雑なバリデーション」とあるが、今回の内容は至って簡単。投稿記事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

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

課題

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

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

ビューで解決

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

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

其の一

  • ここは以前と同じ。
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関数の使い方

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

本当はこうしたい

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

今回はここまで。

8
11
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?