概要
- バリデーションエラーログのフォーマットをカスタマイズ
バージョンとか
- Laravel 5.6
- PHP7.2
シナリオ
Webアプリケーションを作成する案件で、フレームワークや言語等は問わない。
今回は、 PHPの Laravel
で開発することにしました。
社内では Golang
か NodeJs
で行うのがデフォルトっぽく、
特に 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
を継承したサービスモジュールを作成します。
<?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を実装します。
<?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
を作成する。
<?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使ってるので、エラーハンドリングとかをもっとマスターしていきたいなと。
以上