Laravel11に対応した内容に更新しています。

目次

バリデーション(validation)とは

WEBアプリケーションの世界ではユーザが入力フォームで入力した値がアプリケーションにとって妥当な値をチェックすることをバリデーションと呼びます。例えばショッピングサイトから商品を初めて購入した場合は必ず住所の入力が必要となります。入力した郵便番号に漏れがないか郵便番号の桁数が7桁になっているかなどチェックすることをバリデーションといいます。

基本的なバリデーションの動作についてはLaravel5, Laravel6, Laravel7, Laravel8, Laravel9, Laravel10, Laravel11で共通です。またバリデーションという機能はLaravel特有のものではなく他の言語やフレームワークでも利用されているものなのでLaravelでのバリデーションを理解できれば基本的な知識は他でも幅広く活用することができます。バリデーションはアプリケーションの開発者であれば必須の知識となります。

本文書を読み終えるとバリデーションの下記の理解を深めることができます。

  • バリデーションとは何か
  • Laravelソースコードから実際に実装されているバリデーションを理解
  • バリデーションの方法
  • バリデーションエラーの表示と表示場所の設定
  • バリデーションエラーの日本語化
  • カスタムバリデーションの作成方法

バリデーションって難しいの??

バリデーションという言葉を聴き慣れていない人であればバリデーションは非常に難しく複雑なものだと思うかもしれませんがバリデーションの意味を理解することだけであればは非常にシンプルです。入力した値に対してルールを設定し、入力した値がそのルールにパスするか失敗するかチェックを行うだけです。仕組みはシンプルですが、バリデーションが失敗した場合にどのようにユーザに対してメッセージを伝えるかがバリデーションを使いこなす上で重要になります。また各自がルールを作成するとバリデーションコードに漏れやバグが入り込む可能性もあります。そのためLaravelでは頻繁に利用されるルールを事前に準備してくれている上、バリデーションに失敗した場合のエラーの表示機能についても簡単に行えるような仕組みを用意してくれています。

Laravelのソースコードを見るとバリデーションを実行するまで処理、エラーを保持する処理など複雑なものもありますが各ルールで実装されているバリデーション処理自体はシンプルです。
fukidashi

ソースコードの確認

バリデーションの動作を確認する前にLaravelのソースコード(ValidatesAttributes.php)を確認してルールがシンプルであること、実際にどのような処理を行っているのかを見ておきましょう。最もシンプルなルールの一つに入力フォームから送られてきた値が数値がどうかチェックするvalidateNumeric関数というものがあります。実際の数値かどうかのチェック方法は以下の通りis_numeric関数を利用しています。シンプルなルールはこれだけのコードで終わります。これなら入門者の人でも自作できるレベルです。


public function validateNumeric($attribute, $value)
{
    return is_numeric($value);
}
ValidatesAttributes.phpファイルにはvalidate+ルール名で各ルールの関数が登録されています。どのような処理を実際に行っていくか理解するだけでもPHPのスキルが上がることは間違いなのでぜひチェックしてみてください。ファイルはvendor/laravel/framework/src/Illuminate/Validation/Concernsに保存されています。(保存先はLaravel10,11で確認済)
fukidashi

もしルールにパスしなかった場合(Numericのルールであれば数値以外のものが入力された場合)は、ルール名を利用してメッセージ用のファイルlang¥en¥validation.phpにその名前のルールがあるかチェックを行い、もしその名前がある場合はバリデーションに関するエラーメッセージを保存する入れ物MessageBagに登録しているだけです。MessageBagについては後半に説明を行っています。


    'numeric' => 'The :attribute must be a number.',

Laravel10,11ではデフォルトではlangフォルダは存在しません。langフォルダを作成するためには”php artisan lang:publish”を実行する必要があります。


 % php artisan lang:publish

   INFO  Language files published successfully.  

実行すると/lang/enフォルダがプロジェクトフォルダ直下に作成されます。enフォルダにはauth.php, pagination.php, passwords.php, validation.phpが保存されています。

【補足】

入力値がアルファベットかどうかチェックを行いたい場合にalphaというルールを利用すると日本語でもルールにパスします。自分がイメージするルールの単語と実際の処理内容が異なっている場合があるのでそのような時はぜひValidatesAttributes.phpファイルを確認してみてください。

動作確認環境の準備

バリデーションというものがどういうものなのかある程度イメージがつかめたと思うので実際にLaravelを利用しながら理解を深めていきます。バリデーションの基本設定、バリデーションによるエラーメッセージの表示場所を確認するため動作確認環境の構築を行います。

動作検証のデータベースの場合はSQLiteデータベース環境を構築すると簡単です。Laravel11ではプロジェクトを作成すると同時にデータベースを作成するのでこれまでのように別でデータベースを構築する必要がないので楽です。データベースが存在することを前提に動作確認を行います。

postsテーブルの準備

postsテーブルを作成して動作確認の環境を構築します。postsテーブルは、titleとbodyの2つ列から構成されます。

Postモデルとマイグレーションファイルの作成を行います。Postモデルと同時にマイグレーションファイルを作成するためphp artisan make:modelコマンドに-mオプションをつけて実行します。


 % php artisan make:model Post -m

   INFO  Model [app/Models/Post.php] created successfully.  

   INFO  Migration [database/migrations/2024_07_30_003153_create_posts_table.php] created successfully.

モデルPost.phpファイルはappディレクトリの下にマイグレーションファイルはdatabase/migrationsディレクトリの下に作成されます。

Laravel8からはモデルファイルはapp\modelsの下に保存されます。
fukidashi

postsテーブルを作成するマイグレーションファイルにtitle, bodyの列情報を追加します。


<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('body');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

postsテーブルのtitle, body列の挿入が行えるようにPost.phpファイルを更新します。


<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title', 'body', 
    ];    
    
}

postsテーブルの準備ができたので、php artisan migrateコマンドでpostsテーブルを作成します。


 % php artisan migrate

   INFO  Running migrations.  

  2024_07_30_003153_create_posts_table  ....................... 6ms DONE

ルーティングの設定

web.phpに以下のルーティングの設定を行います。

Laravel8以降の記述方法


use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;

//略

Route::get('post/create',[PostController::class,'create']);

Route::post('post',[PostController::class,'store']);

Laravel7までの記述方法


Route::get('post/create', 'PostController@create');

Route::post('post', 'PostController@store');

コントローラーの作成

php artisan make:controllerコマンドを使ってPostController.phpの作成を行います。


 %  php artisan make:controller PostController

   INFO  Controller [app/Http/Controllers/PostController.php] created successfully.  

ルーティングファイルweb.phpで追加したcreateメソッドとstoreメソッドを記述します。createメソッドでは入力フォームを表示するビューファイルを指定して、storeメソッドの中にバリデーションのロジックを記述します。


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
    public function create()
    {
        return view('post.create');
    }

    public function store(Request $request)
    {
        // ここにValidationを行うロジックを記述する
    }
}

ビューの作成

入力フォームを表示させるためのビューの作成を行います。resources/views/postディレクトリの下にcreate.blade.phpを行います。

ビューファイルの中身は下記の通りです。


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Create Post</title>
</head>
<body>
	<form method="POST" action="/post" enctype="multipart/form-data">

          @csrf
         // {{ csrf_field() }}

    <div>
      <label for="title">name:</label>
    </div>
    <div>
      <input id="title" type="text" name="title" value="">
    </div>

    <div>
      <label for="body">body:</label>
    </div>
    <div>
      <textarea id="body" name="body" cols="25" rows="5"></textarea>
    </div>

    <button type="submit">登録する</button>
	</form>
</body>
</html>

php artisan serveコマンドで開発サーバを起動してブラウザからhttp://127.0.0.1:8000/post/createにアクセスすると作成した入力フォームが表示されます。


 % php artisan serve

   INFO  Server running on [http://127.0.0.1:8000].  

  Press Ctrl+C to stop the server
入力フォームの表示
入力フォームの表示

バリデーションのメソッドとルール

validateメソッドについて

入力フォームから入力した値のチェックを行うためにPostControllerのstoreメソッド内にバリデーションのコードを追加します。バリデーションはvalidateメソッドを用いて行い、テーブルの各列に対してルールを設定し、入力値のチェックを行います。ルールは各列に対して、複数設定することもできます。複数のルールを設定する場合は、区切り文字”|”を使って分けます。

validateメソッドの記述方法は下記となります。

validateメソッド

validateメソッド

Laravel5.4などの古いバージョンを利用している場合に上記の記述では、Method validate does not exist.とエラーが表示されます。その場合は下記のように記述を書き換えてください。


$this->validate($request,['列名A' => 'ルール1']);
validationの方法には、validateメソッド以外にもValiidationファザードを用いたものなどあります。本文書では一番シンプルなvalidateメソッドを利用することでバリデーションの理解を深めます。
fukidashi

postsテーブルのtitle列には、入力が必須となるルールrequiredと入力した行と重複の確認を行うルールuniqueを設定します。body列には、ルールrequiredのみ設定しています。


public function store(Request $request)
{
    $request->validate([
	     'title' => 'required|unique:posts',
	     'body' => 'required',
    ]);
}
// ルールは配列でも可能
public function store(Request $request)
{
    $request->validate([
	     'title' => ['required','unique:posts'],
	     'body' =>['required'],
    ]);
     //バリデーションにパスした後の処理を記述
}

バリデーションに失敗した場合の流れ

validateメソッドを使用してバリデーションに失敗した場合はLaravelが内部でエラーの処理を行い自動で入力フォーム画面にリダイレクトされます。validateメソッドによるバリデーションにパスした場合はそのまま次の処理が実行されます。

JavaScriptからのリクエスト

ブラウザからアクセスした場合にバリデーションに失敗した場合はそのまま入力画面にリダイレクトが行われますが、fetch関数、axiosライブラリなどを利用してPOSTリクエストを送信した場合はリダイレクトの処理ではなくステータスコード422と一緒にバリデーションのエラーメッセージが戻されます。Laravelがリクエストの内容を見てどのようなResponseを行うのかを自動で判別してくれています。XHRリクエストの場合は戻されるエラーメッセージを利用してユーザに表示する処理を各自が実装する必要があります。

バリデーションルール

required, unique以外にもたくさんのバリデーションルールが事前に用意されています。Laravelのドキュメントを確認しながら必要なルールを見つけ適用していきます。 Laravelのバージョンアップとともにバリデーションの数も増えています。Laravel11のバリーデーションルールと5.8のバリデーションルールを掲載しているのでバリデーションルールが増えていることが確認できます。10から11でもルールが追加されています。

Laravel11のバリデーションルール
Laravel11のバリデーションルール
Laravel5.8のバリデーションルール
Laravel5.8のバリデーションルール
冒頭でも説明しましたが、もしバリデーションがどのような処理を実際に行っているのか知りたい場合は、vendor¥laravel¥framework¥src¥illuminate¥Validation¥
Concerns¥ValidatesAttributes.phpファイルを確認してください。(Laravel11で確認済)
fukidashi

ビューでのエラーメッセージの表示

バリデーションに失敗した場合にはユーザにフォームのどの入力項目でのエラーなのかメッセージで伝える必要があります。メッセージの表示設定はビューファイルで行います。

バリデーションに失敗するとブラウザとのSession情報にエラーメッセージが保存されます。先ほど説明した通りバリデーションに失敗すると入力フォーム画面にリダイレクトされるのでSessionに保存したエラーメッセージを使うことでユーザに入力内容にエラーがあったことを伝えることができます。

エラーメッセージを表示できるように入力フォームのビューであるcreate.blade.phpにメッセージを表示できる要素を追加します。


//略
@if ($errors->any())
    <div>
        <ul>
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </ul>
    </div>
@endif 
<form method="POST" action="/post" enctype="multipart/form-data">
//略

$errorsはバリデーションを実行するしないに関わらずビューからアクセスすることができる変数です。

$errors->any()は$errors変数の中にエラーメッセージが含まれているかどうかチェックを行うメソッドです。エラーメッセージがあればtrue、なければfalseを戻します。

$errors->all()は$errors変数からエラーを取得するメソッドで、戻り値にはバリデーションの中のチェックで発生したエラー情報が配列として保持しています。foreachを使用することで1つ1つのメッセージを取り出すことができます。

エラーメッセージの表示

バリデーションの動作確認を行うため入力フォームには何も入力せず”登録する”ボタンをクリックします。

入力フォームの表示
入力フォームの表示

titleにもbodyにも入力を行なっていなかったため、”field is required”のメッセージが表示されます。

バリデーションエラーの表示
バリデーションエラーの表示
app.phpファイルでlocaleをjaにしている場合にvalidation.requiredとエラーが表示された場合はlocaleをenに戻してメッセージが表示されるか確認してください。もしくはjaディレクトリを作成し、validation.phpファイルをenディレクトリから複製するとメッセージが表示されます。localeの設定によりアクセスするファイルが異なるためにこのような問題が発生します。
fukidashi

ここまでの動作確認でバリデーションの設定方法とバリデーションに失敗した場合のエラーメッセージの表示方法を確認できました。

カスタマイズしたエラーメッセージの設定

初期設定ではエラーメッセージは英語で表示されます。メッセージをカスタマイズすることも可能です。以下のようにvalidateメソッドに表示したいメッセージの配列を追加します。


public function store(Request $request)
{
    $request->validate([
        'title' => 'required|unique:posts',
        'body' => 'required',
    ],
    [
        'title.required' => 'タイトルは必須です。',
        'body.required' => 'bodyは必須項目です。'
    ]);
}

再度入力フォームに何も入力せず、登録ボタンを押すと追加したカスタマイズしたメッセージが表示されます。

カスタマイズしたエラーメッセージ
カスタマイズしたエラーメッセージ

@errorディレクティブ

errors変数を利用せず@errorディレクティブを利用することもできます。


//略
@error('title')
    <div>{{ $message }}</div>
@enderror
@error('body')
    <div>{{ $message }}</div>
@enderror

<form method="POST" action="/post" enctype="multipart/form-data">
//略

エラーメッセージの日本語化

Laravel9からエラーファイルの保存場所が変更になります。Laravel9ではデフォルトのメッセージファイルは/lang/en/validation.phpファイルです。Laravel8まではresources/lang/en/validation.phpファイルです。validation.phpファイルが存在しない場合にはphp artisanコマンドを利用して作成することができます。


 % php artisan lang:publish

   INFO  Language files published successfully.  

エラーメッセージをカスタマイズして日本語化する方法の確認を行いましたが、validation毎に個別に設定を行うのは非効率のため、一括で日本語化を行う方法を確認します。日本語化までの流れは下記の通りです。

Laravel9/10/11の場合

  1. config/app.phpファイルでロケールの変更
  2. langディレクトリにjaディレクトリ作成
  3. lang/en/validation.phpファイルをjaディレクトリに複製
  4. jaディレクトリ内のvalidation.phpファイルの更新

Laravel8以前までの場合

  1. config/app.phpファイルでロケールの変更
  2. resources/langディレクトリにjaディレクトリ作成
  3. resources/lang/en/validation.phpファイルをjaディレクトリに複製
  4. jaディレクトリ内のvalidation.phpファイルの更新

validationのエラーメッセージの一覧が登録されているファイルは、validation.phpに登録されています。


<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines contain the default error messages used by
    | the validator class. Some of these rules have multiple versions such
    | as the size rules. Feel free to tweak each of these messages here.
    |
    */

    'accepted' => 'The :attribute must be accepted.',
    'active_url' => 'The :attribute is not a valid URL.',
        ・
    'required' => 'The :attribute field is required.',
        ・

ロケールの設定

初期設定では、ロケールの設定が”en”になっているために”ja”に変更する必要があります。設定ファイルは、Laravelインストールディレクトリのconfig/app.phpで行います。Laravel10までは下記のように’en’を’ja’に変更します。


    /*
    |--------------------------------------------------------------------------
    | Application Locale Configuration
    |--------------------------------------------------------------------------
    |
    | The application locale determines the default locale that will be used
    | by the translation service provider. You are free to set this value
    | to any of the locales which will be supported by the application.
    |
    */

    'locale' => 'ja',

Laravel11で環境変数からlocalの値を設定します。


    /*
    |--------------------------------------------------------------------------
    | Application Locale Configuration
    |--------------------------------------------------------------------------
    |
    | The application locale determines the default locale that will be used
    | by Laravel's translation / localization methods. This option can be
    | set to any locale for which you plan to have translation strings.
    |
    */

    'locale' => env('APP_LOCALE', 'en'),

.envファイルを確認するとAPP_LOCALEの値が’en’に設定されているので’ja’に変更します。


APP_LOCALE=ja

validation.phpファイル複製

.envファイルまたはapp.phpファイルでロケールの設定完了後、langディレクトリにjaディレクトリを作成し、enディレクトリに保存されているvalidation.phpファイルをjaディレクトリの下に保存します。保存したvalidation.phpの中にあるrequiredを日本語に変更します。


return [
//略
    'regex' => 'The :attribute field format is invalid.',
    'required' => ':attribute は必須です。',
    'required_array_keys' => 'The :attribute field must contain entries for: :values.',
//略

下記はLarave8以前の場合です。

validationメッセージを日本語化

validationメッセージを日本語化

再度入力フォームに何も入力せず、ja/validation.phpファイルで日本語化したメッセージが表示されます。

validation.phpファイルで日本語化した後
validation.phpファイルで日本語化した後

requiredルールのみvalidation.phpファイルを利用して日本語化を行いましたが、他のルールのメッセージも英語から日本語に変更することですべてのエラーメッセージを日本語化することが可能になります。

validation.phpファイルをすべて自分で日本語化するのは大変なのでインターネットを検索するとvalidation.phpファイルを日本語化して公開している人がいるので参考にするのがいいです。

エラーメッセージの表示場所

エラーメッセージに取得に関するメソッド

入力した値毎にエラーメッセージを表示することが可能です。下記の方法で入力した項目(フィールド)のエラーメッセージを取り出すことが可能です。

firstメソッドでエラーメッセージを取得

firstメソッドでエラーメッセージを取得

firstメソッドでは、項目のvalidationでエラーになったルールのメッセージを1つしか取得することができません。すべてのルールのエラーメッセージを取得するためには、getメソッドを使用します。

getメソッドですべてのエラーを取得

getメソッドですべてのエラーを取得

getメソッドの場合、エラーメッセージは配列で取得されるため、foreachでテキストとして展開する必要があります。
fukidashi

各項目にエラーメッセージが入っているかどうかをチェックするhasメソッドもあります。

エラーメッセージを持っているかの確認

エラーメッセージを持っているかの確認

項目ごとのエラーメッセージ

hasメソッドとfirstメソッドを利用してエラーメッセージを表示します。hasメソッドでbodyフィールドにエラーがあるかチェックを行い、エラーがある場合のみfirstメソッドを利用してエラーを表示しています。


@if($errors->has('body'))
  {{ $errors->first('body') }}
@endif

hasメソッドとgetメソッドを利用してエラーメッセージを表示します。hasメソッドでtitleフィールドにエラーがあるかチェックを行い、エラーがある場合にはgetメソッドですべてのエラーを配列で取得してforeach関数で展開してエラーメッセージを表示させています。


@if($errors->has('title'))
   @foreach($errors->get('title') as $message)
      {{ $message }}
@endforeach @endif

項目別にエラーメッセージを表示

これまでのエラーメッセージの設定を使って、エラーメッセージを表示場所を項目の下に表示させます。


<!DOCTYPE html>
<html lang="ja">
<head>
	<meta charset="UTF-8">
	<title>Create Post</title>
</head>
<body>
	<form method="POST" action="/post" enctype="multipart/form-data">

		{{ csrf_field() }}

    <div>
      <label for="title">name:</label>
    </div>
		@if($errors->has('title'))
			@foreach($errors->get('title') as $message)
				{{ $message }}<br>
			@endforeach
		@endif 
    <div>
      <input id="title" type="text" name="title" value="">
    </div>

    <div>
      <label for="body">body:</label>
    </div>
		@if($errors->has('body'))
			{{ $errors->first('body') }}<br>
		@endif 
    <div>
      <textarea id="body" name="body" cols="25" rows="5"></textarea>
    </div>
    
    <button type="submit">登録する</button>
	</form>
</body>
</html>

再度入力フォームに何も入力せず、登録ボタンを押すと入力項目の下にエラーメッセージが表示されます。

エラーメッセージの表示場所を変更

エラーメッセージの表示場所を変更

入力項目毎にエラーメッセージを表示することでどの入力が間違っているかすぐにわかるためユーザビリティも向上します。
fukidashi

フィールド名を変更する

項目別にエラーメッセージを表示することができましたが、titleは必須ですはテーブル作成時の列名(フィールド名)なのでこれを日本語のタイトルに変更したい場合もあるかと思います。

その場合は、validator.phpファイルのattributesに追加することで変更することができます。


    /*
    |--------------------------------------------------------------------------
    | Custom Validation Attributes
    |--------------------------------------------------------------------------
    |
    | The following language lines are used to swap our attribute placeholder
    | with something more reader friendly such as "E-Mail Address" instead
    | of "email". This simply helps us make our message more expressive.
    |
    */

    'attributes' => ['title' => 'タイトル'],

titleをタイトルに変更すると以下のようにバリデーションエラーメッセージのtitleがタイトルに変わります。

titleからタイトルへ
titleからタイトルへ

カスタムバリデーション

Laravelにはデフォルトでさまざまなバリデーションが準備されていますが独自のバリデーションを作成したいということもあるかもしれません。その場合はカスタムバリデーションルールを利用することで対応することができます。カスタムバリデーションの作成方法についてはLaravel9から変更になっています。

ルールファイルの作成

入力フォームで住所を入力した場合の郵便番号のカスタムバリエーションを作成してみましょう。


 % php artisan make:rule Zipcode

   INFO  Rule [app/Rules/Zipcode.php] created successfully.

app\Rulesフォルダの下にZipcode.phpファイルが作成されます。

作成したZipcodeファイルは下記のようにバリデーションで設定します。


use App\Rules\Zipcode;
//
public function store(Request $request)
{
    $request->validate([
        'zip_code' => ['required',new Zipcode],
        'address' => 'required',
    ]);
}

Laravel9から

Laravel9からはZipcode.phpファイルにはvalidatedメソッドのみ入っています。

validateメソッドの引数$attribute, $valueと$failを受け取って$valueの値が条件を満たすかチェックを行います。条件を満たさない場合には$fail関数の引数にエラーメッセージに記述します。


<?php

namespace App\Rules;

use Closure;
use Illuminate\Contracts\Validation\ValidationRule;

class Zipcode implements ValidationRule
{
    /**
     * Run the validation rule.
     *
     * @param  \Closure(string): \Illuminate\Translation\PotentiallyTranslatedString  $fail
     */
    public function validate(string $attribute, mixed $value, Closure $fail): void
    {
    }
}

バリデーション条件の設定

郵便番号の形式は3桁-4桁なので正規表現を利用してチェックを行います。


public function validate(string $attribute, mixed $value, Closure $fail): void
{
    if(!preg_match('/^\d{3}[-]\d{4}$/', $value)){
        $fail('郵便番号の書式に誤りがあります');
    }
}

実際に入力した郵便番号でチェックすると163-8001ではバリデーションをパスしますが1638001や郵便の桁数の不足するものまた数字以外を入力すると”郵便番号の書式に誤りがあります”がエラーで戻されます。

メッセージの変更方法

属性の情報を表示したい場合は、:attributeを利用することでメッセージに属性名を表示させることができます。今回はzipcodeと表示されます。


public function validate(string $attribute, mixed $value, Closure $fail): void
{
    if(!preg_match('/^\d{3}[-]\d{4}$/', $value)){
        $fail(':attributeの書式に誤りがあります');
    }
}

エラー内容を記述したvalidation.phpファイルに記述された内容のメッセージを表示させたい場合は、translateメソッドを利用することができます。意図的にdateルールのメッセージを利用した場合は下記のように設定します。メッセージは”zipcode is not a valid date.”と表示されます。


$fail('validation.date')->translate();

zipcodeというメッセージをValication.phpファイルに追加することも可能です。validation.phpファイルを開いて下記を追加します。

zipcodeというメッセージをValication.phpファイルに追加することも可能です。validation.phpファイルを開いて下記を追加します。


//略
'uuid' => 'The :attribute must be a valid UUID.',
'zipcode' => 'エラー',
//略

ルールファイルのZipcode.phpファイルのメッセージ関数を以下のように変更します。


$fail('validation.zipcode')->translate();

バリデーションに失敗するとメッセージで”エラー”が表示されます。

Laravel8まで

Laravel8まではZipcode.phpファイルの中身はpassesとmessageメソッドが入っています。passesメソッドは引数に$attributeと$valueを受け取って$valueの値が条件を満たすかチェックを行います。今回は$valueの値が郵便番号のフォーマットの条件を満たせばtrueを戻し、満たさなければfalseを戻します。もし、条件を持たさなかった場合は、messageメソッドに記述した内容がエラーメッセージとして戻されます。


namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class Zipcode implements Rule
{
    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        //
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return 'The validation error message.';
    }
}

バリデーション条件の設定

郵便番号の形式は3桁-4桁なので正規表現を利用してチェックを行います。


public function passes($attribute, $value)
{
    return preg_match('/^\d{3}[-]\d{4}$/', $value);
}

実際に入力した郵便番号でチェックすると163-8001ではバリデーションをパスしますが、1638001や郵便の桁数の不足するものまた数字以外を入力するとmessage関数のThe validation error messageがエラーで戻されます。

メッセージの変更方法

メッセージを変更したい場合は下記のように直接messageメソッドを変更することも可能です。


    public function message()
    {
        return '郵便番号の書式に誤りがあります';
    }

属性の情報を表示したい場合は、:attributeを利用することでメッセージに属性名を表示させることができます。今回はzipcodeと表示されます。


     public function message()
    {
        return ':attributeの書式に誤りがあります';
    }

エラー内容を記述したvalidation.phpファイルに記述された内容のメッセージを表示させたい場合は、trans関数を利用することができます。意図的にdateルールのメッセージを利用した場合は下記のように設定します。


    public function message()
    {
        return trans('validation.date');
    }

メッセージは”zipcode is not a valid date.”と表示されます。

zipcodeというメッセージをValication.phpファイルに追加することも可能です。validation.phpファイルを開いて下記を追加します。


//略
'uuid' => 'The :attribute must be a valid UUID.',
'zipcode' => 'エラー',
//略

ルールファイルのZipcode.phpファイルのメッセージ関数を以下のように変更します。


    public function message()
    {
        return trans('validation.zipcode');
    }

バリデーションに失敗するとメッセージで”エラー”が表示されます。

その他

validateメソッドの戻り値

validateメソッドを利用してバリデーションに失敗した場合には自動でリダイレクトが行われました。バリデーションに成功した場合にvalidateメソッドから戻される値を確認します。


public function store(Request $request)
{
    $valiteedData = $request->validate([
        'title' => 'required|unique:posts',
        'body' => 'required',
    ]);

    dd($valiteedData);

}

titleに”Laravel Validate”, bodyに”バリデーションについての説明”を入力した場合にはバリデーションにパスしたフィールドと値を持つ配列が戻されます。


array:2 [▼ // app/Http/Controllers/PostController.php:21
  "title" => "Laravel Validation"
  "body" => "バリデーションについての説明"
]

エラーメッセージを保存する場所を指定

バリデーションのエラーメッセージは$errors変数に保存されているので$errors->all()でメッセージを取得することができました。さらに細かくエラーの保存場所を指定したい場合にはvalidateWithBagを利用することができます。validateWithBagメソッドの第一引数に保存する場所の名前を指定します。ここでは”post”を設定しています。Laravelではエラーメッセージを保存している場所をMessageBagという呼びます。validateWithBagメソッドによってMessageBagの名前をpostに変更しています。


public function store(Request $request)
{
    $valiteedData = $request->validateWithBag('post',[
        'title' => 'required|unique:posts',
        'body' => 'required',
    ]);
}

エラーを表示させるためにはBladeファイル側の更新も必要となります。


<ul>
    @foreach ($errors->post->all() as $error)
        <li>{{ $error }}</li>
    @endforeach
</ul>

Bladeファイルでエラーのデバッグを行う

Bladeファイルで$errors変数の中にどのような値が保存されているのかdd関数を利用して確認します。


@if ($errors->any())
{{ dd($errors) }}
<div>
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif 

メッセージはViewErrorBagの中に入っていることがわかります。さらにMessageBagの名前が”default”であることもわかります。

$errors変数の中身
$errors変数の中身

ViewErrorBagはvendor/larave/framework/src/illuminate/Support/にあるViewErrorBag.phpファイルに対応するのでViewErrorBag.phpファイルを確認することでドキュメントに記載されていないメソッドなどを確認することができます。例えばcountメソッドを利用することでdefaultバッグに保存されているメッセージの数を表示することができます。


public function count(): int
{
    return $this->getBag('default')->count();
}

<p>{{ $errors->count() }}</p>
@if ($errors->any())
<div>
    <ul>
        @foreach ($errors->all() as $error)
            <li>{{ $error }}</li>
        @endforeach
    </ul>
</div>
@endif 
MessageBagが持つメソッドを確認したい場合にはvendor/larave/framework/src/illuminate/Contracts/SupportのMessageBag.phpファイルで確認できます。エラーメッセージの取得で確認したhas, get, allメソッドをMessageBagが持っていることを確認することができます。/
fukidashi

$errors-count()の値は最初はエラーがないため0と表示されていますがエラーが発生するとtitleとbodyの2つのメッセージを持っているので2と表示されます。

validateWithBagメソッドを利用した場合にはどのような変化が起こるのか確認します。


public function store(Request $request)
{
    $valiteedData = $request->validateWithBag('post',[
        'title' => 'required|unique:posts',
        'body' => 'required',
    ]);
} 

Bladeファイルではdd関数を利用してデバッグします。


@if ($errors->post->any())
{{ dd($errors)}}
@endif 

一見先程と同じ内容にみえますが”default”が”post”になっていることがわかります。validateWithBagによってMessageBagの名前を”default”から”post”に変更していることがわかります。

validateWithBagを利用した場合
validateWithBagを利用した場合

sessionヘルパー関数を利用してエラーメッセージを取得

エラーの情報はSessionに保存されるという話を本文書の冒頭で説明しましたがsessionヘルパー関数を利用してバリデーションのエラーメッセージを取得することができます。


@if ($errors->any())
{{ dd(session('errors')) }}
@endif 
$errors変数の中身
sessionヘルパー関数を利用した場合

エラーをSessionファイルで確認

バリデーションのエラーはSessionに保存されているのでSessionファイルにもエラーメッセージが保存されています。storage/framework/sessionsに保存されているSessionファイルを開いてください。ファイル名はSession毎に設定されているため環境により異なります。


a:5:{s:6:"_token";s:40:"js8YPnRN5r2SLAy1S2g5Sp1lik0ARIAQdpA5pznO";s:9:"_previous";a:1:{s:3:"url";s:33:"http://127.0.0.1:8000/post/create";}s:6:"_flash";a:2:{s:3:"old";a:2:{i:0;s:10:"_old_input";i:1;s:6:"errors";}s:3:"new";a:0:{}}s:10:"_old_input";a:3:{s:6:"_token";s:40:"js8YPnRN5r2SLAy1S2g5Sp1lik0ARIAQdpA5pznO";s:5:"title";N;s:4:"body";N;}s:6:"errors";O:31:"Illuminate\Support\ViewErrorBag":1:{s:7:"^@*^@bags";a:1:{s:7:"default";O:29:"Illuminate\Support\MessageBag":2:{s:11:"^@*^@messages";a:2:{s:5:"title";a:1:{i:0;s:31:"タイトル は必須です。";}s:4:"body";a:1:{i:0;s:23:"body は必須です。";}}s:9:"^@*^@format";s:8:":message";}}}}

アプリケーションを構築する際にどのルールを利用するか個別に吟味する必要がありますが本文書を読み終えたのでLaravelのバリデーションの最初の一歩を踏み出すことができます。Laravelのドキュメンテーションを見ると今回の説明はLaravelバリデーションを一部にすぎません。本文書をベースにバリデーションの理解をさらに深めていってください。