Laravelでのリクエストデータの取得を行った際には簡単な入力チェックを行っていました。今回はLaravelできちんとしたバリデーションを行っていきます。 バリデーションについては、「バリデーションとは」を読みましょう。

Laravelでバリデーション

3年以内に更新されました。情報が古い可能性があります。
更新日 : 2020年02月04日

Laravelでのリクエストデータの取得を行った際には簡単な入力チェックを行っていました。今回はLaravelできちんとしたバリデーションを行っていきます。

バリデーションについては、「バリデーションとは」を読みましょう。

バリデーションの実装

Laravelでのリクエストデータの取得を編集して、バリデーションを実装していきます。主にフォームを表示するビューファイルと、コントローラーの修正になります。

まずは前回のProfileControllerを見ていきます。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class ProfileController extends Controller {

    /**
     * フォーム表示
     */
    public function form() {
        return view('profile.form');
    }

    /**
     * プロフィール表示
     */
    public function show(Request $request) {
        // メモが入力されているか確認
        if($request->filled('memo')) {
            $memo = $request->input('memo');
        } else {
            $memo = 'なし';
        }
        // ビューで使う配列データの作成
        $profile = array(
            'name' => $request->input('name'),
            'age' => $request->input('age'),
            'gender' => $request->input('gender'),
            'favorites' => $request->input('favorites', array('なし')),
            'memo' => $memo
        );
        return view('profile.show', $profile);
    }
}

前回はメモの入力確認を簡単に行っただけでした。

Laravelできちんとしたバリデーションを行うためには、コントローラーの引数にあるRequestオブジェクトを利用します。今回のコントローラーには$requestという変数にこのインスタンスが格納されているため、これを利用していきます。バリデーションを行うために以下のように編集しましょう。

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;

class ProfileController extends Controller {

    /**
     * フォーム表示
     */
    public function form() {
        return view('profile.form');
    }

	/**
	 * プロフィール表示
	 */
    public function show(Request $request) {
        // バリデーション
        $validatedData = $request->validate([
            'name' => 'required|string|max:30',
            'age' => 'required|string',
            'gender' => 'required|string',
            'favorites' => 'nullable|array',
            'memo' => 'present'
        ]);

        // ビューで使う配列データの作成
        $profile = array(
            'name' => $request->input('name'),
            'age' => $request->input('age'),
            'gender' => $request->input('gender'),
            'favorites' => $request->input('favorites', array('なし')),
            'memo' => $request->input('memo')
        );
        return view('profile.show', $profile);
    }
}

変更点はshowメソッドのみです。showメソッド内で、$request->validateメソッドを利用しています。

このメソッドの引数には、連想配列を入れます。連想配列の形式は、キー名には入力されるname属性値を指定し、値には必要なバリデーションルールを|この記号で複数指定することができます

例えば、nameキーにはrequred|string|max:30という値を指定していますが、これはname属性の入力値に対して「必須・文字列・30文字まで」というルールを適用しています。これらのルールはLaravelのドキュメントにたくさんの種類が存在します。

これでバリデーションは終了です。入力値にバリデーションルールに基づかないエラーが見つかると、自動的に元のフォームページにリダイレクトされます

最後にバリデーションエラーを表示していきましょう。バリデーションのエラーが見つかったところで、ユーザーにどの入力値が悪かったのか表示してあげる必要があります。

バリデーションエラーを表示できるようにビューを編集していきましょう。

バリデーションエラーの表示

コントローラーにバリデーションルールを実装することで、不適切な入力値を事前に弾くことができるようになりました。最後にユーザーにどの入力値が悪かったのかをエラーとして表示してあげましょう。

フォームを表示するビューファイルを以下のように編集します。

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravelのフォーム表示</title>

    <!-- Fonts -->
    <link href="https://fonts.googleapis.com/css?family=Nunito:200,600" rel="stylesheet">

    <!-- Styles -->
    <style>
        html, body {
            background-color: #fff;
            color: #636b6f;
            font-family: 'Nunito', sans-serif;
            font-weight: 200;
            height: 100vh;
            margin: 0;
        }

        .flex-center {
            align-items: center;
            margin: 100px 300px 100px 300px;
            justify-content: center;
        }

        .position-ref {
            position: relative;
        }

        .alert {
            color: red;
        }
    </style>
</head>
<body>
    <div class="flex-center position-ref">
        <h1>Laravelのフォームテスト</h1>
        @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
        @endif
        <form method="POST" action="show">
            @csrf
            <dl>
                <dt>名前</dt>
                <dd><input type="text" name="name" value="{{ old('name') }}"></dd>
            </dl>
            <dl>
                <dt>年齢</dt>
                <dd>
                    <select name="age">
                        <option value="">-----</option>
                        @for ($i = 20; $i <= 50; $i++)
                            <option value="{{ $i }}歳" @if(old('age') === "{$i}歳") selected @endif>{{ $i }}歳</option>
                        @endfor
                    </select>
                </dd>
            </dl>
            <dl>
                <dt>性別</dt>
                <dd>
                    <input type="radio" name="gender" value="男性" @if(old('gender') === "男性") checked @endif>男性
                    <input type="radio" name="gender" value="女性" @if(old('gender') === "女性") checked @endif>女性
                </dd>
            </dl>
            <dl>
                <dt>好きなもの</dt>
                <dd>
                    <input type="checkbox" name="favorites[]" value="テレビ" @if(is_array(old('favorites')) && in_array("テレビ", old('favorites'))) checked @endif>テレビ
                    <input type="checkbox" name="favorites[]" value="ラジオ" @if(is_array(old('favorites')) && in_array("ラジオ", old('favorites'))) checked @endif>ラジオ
                    <input type="checkbox" name="favorites[]" value="映画" @if(is_array(old('favorites')) && in_array("映画", old('favorites'))) checked @endif>映画
                    <input type="checkbox" name="favorites[]" value="本" @if(is_array(old('favorites')) && in_array("本", old('favorites'))) checked @endif></dd>
            </dl>
            <dl>
                <dt>メモ</dt>
                <dd><textarea name="memo">{{ old('memo') }}</textarea></dd>
            </dl>
            <input type="submit" value="!送信!">
        </form>
    </div>
</body>
</html>

特に大きな変更点は以下の部分です。

@if ($errors->any())
<div class="alert alert-danger">
    <ul>
        @foreach ($errors->all() as $error)
        <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif

バリデーションのエラーが見つかると、Laravelが自動的にバリデーションエラー項目をセッションに格納してくれた上で、元のフォームにリダイレクトしてくれます。

バリデーションエラー項目は$errors変数を利用することでビューファイルで取得することができます。どのようにバリデーションエラーを表示しているかは以下に解説します。

  1. まず、@if ($errors->any())とすることで、バリデーションエラーがあるかどうかを調べる。
  2. $errors->all()とすると、バリデーションエラーが配列で取得できるため、これを@foreachでループさせる。
  3. @foreachを利用して$error変数にバリデーションエラーのメッセージが格納されるため、これをHTMLのリストで表示する。

これでバリデーションエラーの表示は完了です。

oldヘルパ関数の利用について

今回は名前を入力するinputタグなどにold関数を利用しました。例えば<input type="text" name="name" value="{{ old('name') }}">このようなものです。

old('属性値')とすることで、バリデーションに失敗した際の入力値を取得することができます。old('name')とすれば、前回入力した名前のデータを取得できます。

あとはinputタグにあるvalue属性を利用することで、フォームにデータが格納された状態で表示することができます。

old関数を利用することでユーザーが入力データを間違えたとしても、間違えていなかった入力値に関しては再度入力する必要がなくなります

チェックボックスに関してもin_array('本', old('favorites'))というように利用することで、前回のデータにが含まれていればchecked属性を付与するという処理が実現できます

まとめ

Laravelでバリデーションの実装を行っていきました。

バリデーションは本来正規表現などの面倒な処理を行わないといけませんが、Laravelのデフォルトで用意されているバリデーションルールを利用することで簡単にバリデーションを実装できます。

バリデーションエラー表示についても英語であれば簡単に追加できます。日本語でバリデーションエラーの表示などを行いたい場合には、ドキュメントに記載されているフォームリクエストバリデーションを利用します。

こちらについてはコントローラーに追記するだけのバリデーションとはまた異なるため、改めて記事で解説します。