18
20

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でValidationを実装した話

Last updated at Posted at 2018-08-09

概要

  • バリデーションエラーログのフォーマットをカスタマイズ

バージョンとか

  • Laravel 5.6
  • PHP7.2

シナリオ

Webアプリケーションを作成する案件で、フレームワークや言語等は問わない。
今回は、 PHPの Laravel で開発することにしました。

社内では GolangNodeJs で行うのがデフォルトっぽく、
特に Golang をメインで開発を行っているみたいです。

管理方法

管理管轄
 |
 +- DockerContainer(App) Golangだったり
 |
 +- DockerContainer(App) Nodejsだったり
 |
 +- DockerContainer(本App)
    |
    +- src
       |
       [Laravel Project]

Dockerでまとめて管理する方法で、エラーログをAPPごとに標準出力で出すことにより、
管理側で一括でログを確認できるような構造になっています。

フォーム内容

form-data 形式でフォームデータをPOSTでリクエストします。

name        = (必須,英数字+[.-_],255文字以内)
id          = (必須,英数字20~24桁) 
recorded_at = (必須,タイムスタンプ数値10桁)

バリデーションフォーマット

バリデーションのフォーマットは仕様書により固定されており、
以下がバリデーションエラー時のフォーマットである。

Key: {keyname}, Value: {values}, Violation: {violation}

API

バリデーション時のAPIレスポンスは基本400エラーとします
エラーレスポンスはJSONで返します。
バリデーションエラーではないものは、メッセージをそのまま返します。
(以下の表はすべてサンプルで作成した仕様です)

|エラーコード|フォーマット|内容|
|:---:|:---|:----|:--:|
|A0001|Key:, Value:, Violation:|バリデーションエラー時|
|A0005|File Extension Error|ファイル拡張子エラー時|

{
	"errors":[
		{
			"code":"A0001",
			"message":"Key: {keyname}, Value: {values}, Violation: {violation}"
		},
		{
			"code":"A0005",
			"message":"File Extension Error"
		},
	]
}

本題

Laravelでバリデーションエラーが出た場合、自動的にメッセージが作成されますが、
今回は指定されたメッセージに変更しないといけないので、変更していきます。

基本

RouteやControllerなどの説明は省きます。

基本的なバリデーションはこちらのコードで行なえます

$validator = Validator::make($request->all(), [
            "name"        => "required|max:255|not_regex:/[^a-zA-Z0-9._-]/",
            "id"          => "required|not_regex:/[^a-zA-Z0-9]/",
            "recorded_at" => "required|digits:10"
        ]);

エラーハンドリングをする際は、以下のコードでハンドリングが行えます。

if ($validator->fails()) {
    foreach ($validator->errors()->all() as $error_text) {
     	   // $error_textにエラー内容が入る
    }
}

カスタムエラーメッセージ

カスタムエラーメッセージを使用したい場合は、Validator::make()の第三引数に配列で指定できます。
指定の方法はたくさんありますので公式を御覧ください。
https://laravel.com/docs/5.6/validation#custom-error-messages


$err_msg = "Key: :attribute, Value: :values, Violation: ";
$custom_error_msg = [
    "required"            => $err_msg . "required",
    "max"                 => $err_msg . "maximum length",
    "alpha_num"           => $err_msg . "alphabet&number",
    "digits"              => $err_msg . "number length",
    "device_id.not_regex" => $err_msg . "alphabet&number",
    "name.not_regex"      => $err_msg . "alphabet&number+[._-]"
];

$validator = Validator::make($request->all(), [
    "name"        => "required|max:255|not_regex:/[^a-zA-Z0-9._-]/",
    "device_id"   => "required|not_regex:/[^a-zA-Z0-9]/",
    "recorded_at" => "required|digits:10"
    ], $custom_error_msg);

ですが、これだとエラー出力時にこう出力されます。

{
	"errors":[
		{
			"code":"A0001",
			"message":"Key: name, Value: :values, Violation: alphabet&number+[._-]"
		},

**:values**が置換されていません。
LaravelのValidatorは標準で :attribute をKey名に置換されて出力されるのですが、
それ以外のプレースホルダーは自分で実装しなければいけません。

カスタムプレースホルダー

まず Illuminate\Validation\Validator を継承したサービスモジュールを作成します。

app/Service/TestValidator.php

<?php
namespace App\Service;
use Illuminate\Validation\Validator;

class TestValidator extends Validator
{
    public function __construct($translator, $data, $rules, $messages = [])
    {
        parent::__construct($translator, $data, $rules, $messages);

        // ここに記述
    }
}

次に、Replacerを実装します。

app/Service/TestValidator.php

<?php
namespace App\Service;

use Illuminate\Validation\Validator;

class TestValidator extends Validator
{
    public function __construct($translator, $data, $rules, $messages = [])
    {
        parent::__construct($translator, $data, $rules, $messages);
		
		 // $message    = カスタムエラーメッセージの内容
		 // $attribute  = エラーが発生したキー名
		 // $rule       = バリデーションのルール 例:required
		 // $parameters = 場合によって変わるが、digitsであれば文字数などが配列で入る
		 //
		 // クロージャなので、$dataを値渡ししてあげる。
		 // $data = リクエストデータが入る
        $replacer = function($message, $attribute, $rule, $parameters) use ($data) {
            
            // $message 内の :values を $data[$attribute] に置換する
            return str_replace(':values', $data[$attribute], $message);
        };

		 // 上記のクロージャを適応するルール
        $this->addReplacers([
            "required"=>$replacer,
            "max" => $replacer,
            "alpha_num" => $replacer,
            "digits" => $replacer,
            "mimes" => $replacer,
            "file" => $replacer,
            "not_regex" => $replacer
        ]);

    }
}

$this->addReplacers() により、置換が行われます。

ValidatorServiceProviderを作成

このままではValidator::makeを実行しても上記の TestValidator を読み取ってくれないので、
ValidatorServiceProviderを作成する。

app/Providers/ValidatorServiceProvider.php

<?php

namespace App\Providers;

use App\Service\TestValidation;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Validator;

class ValidatorServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        Validator::resolver(function ($translator, $data, $rules, $messages) {
            return new TestValidation($translator, $data, $rules, $messages);
        });
    }

    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}

これでしっかりエラーメッセージが表示されます。

{
	"errors":[
		{
			"code":"A0001",
			"message":"Key: name, Value: 全角文字ダメ!, Violation: alphabet&number+[._-]"
		},

おわりに

やり方がわかるまで苦労しましたが、そこまで変更点もなく自由にエラーメッセージを変更できたのでとても楽でした。
ずっとLaravel使ってるので、エラーハンドリングとかをもっとマスターしていきたいなと。

以上

18
20
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
18
20

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?