使用 Dingo\API 中的 FormRequest 時,422 錯誤提示的 message 自定義,以及提示漢化。

SylviaYuan發表於2019-02-20

使用 FormRequest ,會讓 Controller 看起來更為整潔。因為專案需求,我們專案中使用的是 Dingo\Api\Http\FormRequest 。本文主要解決的是,在該種情況下 422 錯誤提示的漢化以及message 的自定義。
這只是我個人的解決辦法,如有好的解決方法可以指出,但不要噴我,會受不了鳥~~

一、問題狀況闡述

原始程式碼如下:

<?php

namespace App\Http\Requests;

use Dingo\Api\Http\FormRequest;

class PostRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
        switch ($this->method()) {
            case 'PUT':
                return [
                    'title' => 'required'
                ];
            case 'POST':
                return [
                    'title' => 'required'
                ];
            default:
                return [];
        }
    }
}

預設錯誤提示如下:

{
    "message": "422 Unprocessable Entity.",
    "status_code": 422,
    "errors": {
        "title": [
            "The title field is required."
        ]
    }
}

需要優化點:
1、提示為中文提示
2、422錯誤時,message 預設為errors 中的第一條

期望出現的提示如下:

{
    "message": "必須指定:標題",
    "status_code": 422,
    "errors": {
        "title": [
            "必須指定:標題"
        ]
    }
}

二、解決問題

第一步:首先將專案中的語言漢化(若已漢化,請跳過次步驟)

1、 在 resources/lang 下目錄下,建立一個與 en 對應的資料夾 zh
zh資料夾下新建如下四個檔案:

auth.php:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Authentication Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used during authentication for various
    | messages that we need to display to the user. You are free to modify
    | these language lines according to your application's requirements.
    |
    */

    'failed' => '當前憑證與我們的記錄不相符',
    'throttle' => '登入操作太頻繁,請等待 :seconds 秒後重試。',

];

pagination.php:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Pagination Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are used by the paginator library to build
    | the simple pagination links. You are free to change them to anything
    | you want to customize your views to better match your application.
    |
    */

    'previous' => '« 上一頁',
    'next' => '下一頁 »',

];

passwords.php:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Password Reset Language Lines
    |--------------------------------------------------------------------------
    |
    | The following language lines are the default lines which match reasons
    | that are given by the password broker for a password update attempt
    | has failed, such as for an invalid token or invalid new password.
    |
    */

    'password' => '密碼必須最少為 6 個字元並與確認密碼相同。',
    'reset' => '您的密碼已重置!',
    'sent' => '我們已將密碼重置連結傳送到您的郵箱!',
    'token' => '重置密碼的令牌無效。',
    'user' => "未找到使用此郵箱的使用者。",

];

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' => ':attribute 必須為已接受',
    'active_url' => ':attribute 不是有效的 URL',
    'after' => ':attribute 必須大於 :date',
    'after_or_equal' => ':attribute 必須大於或等於 :date',
    'alpha' => ':attribute 可接受型別:字母',
    'alpha_dash' => ':attribute 可接受型別:字母、數字、短劃線和下劃線',
    'alpha_num' => ':attribute 可接受型別:字母、數字',
    'array' => ':attribute 可接受型別:陣列',
    'before' => ':attribute 必須小於 :date',
    'before_or_equal' => ':attribute 必須小於或等於 :date',
    'between' => [
        'numeric' => ':attribute 必須介於 [:min - :max] 之間',
        'file' => ':attribute 最小::min KB,最大::max KB',
        'string' => ':attribute 最少::min 個字元,最多::max 個字元',
        'array' => ':attribute 最少::min 項,最多::max 項',
    ],
    'boolean' => ':attribute 可接受型別:是 或 否',
    'confirmed' => 'The :attribute confirmation does not match.',
    'date' => ':attribute 不是有效的日期',
    'date_format' => ':attribute 格式錯誤,格式::format.',
    'different' => ':attribute 不能等於 :other',
    'digits' => ':attribute 必須是 :digits 位數',
    'digits_between' => ':attribute 最少 :min 位數,最多::max 位數',
    'dimensions' => ':attribute 圖片尺寸不匹配',
    'distinct' => ':attribute 已存在相同的選項',
    'email' => ':attribute 不是有效的郵箱地址',
    'exists' => '不存在的選項::attribute',
    'file' => ':attribute 必須是一個有效的檔案',
    'filled' => ':attribute 必須填寫',
    'gt' => [
        'numeric' => ':attribute 必須大於 :value.',
        'file' => ':attribute 必須大於 :value KB',
        'string' => ':attribute 必須大於 :value 個字元',
        'array' => ':attribute 必須大於 :value 項',
    ],
    'gte' => [
        'numeric' => ':attribute 必須大於或等於 :value',
        'file' => ':attribute 必須大於或等於 :value KB',
        'string' => ':attribute 必須大於或等於 :value 個字元',
        'array' => ':attribute 必須大於或等於 :value 項',
    ],
    'image' => ':attribute 必須是一個影像',
    'in' => ':attribute 不是一個有效的值',
    'in_array' => ':other 不包含 :attribute',
    'integer' => ':attribute 必須是整數',
    'ip' => ':attribute 無效的 IP 地址',
    'ipv4' => ':attribute 無效的 IPv4 地址',
    'ipv6' => ':attribute 無效的 IPv6 地址',
    'json' => ':attribute 無效的 JSON 字串',
    'lt' => [
        'numeric' => ':attribute 必須小於 :value.',
        'file' => ':attribute 必須小於 :value KB',
        'string' => ':attribute 必須小於 :value 個字元',
        'array' => ':attribute 必須小於 :value 項',
    ],
    'lte' => [
        'numeric' => ':attribute 必須小於或等於 :value',
        'file' => ':attribute 必須小於或等於 :value KB',
        'string' => ':attribute 必須小於或等於 :value 個字元',
        'array' => ':attribute 必須小於或等於 :value 項',
    ],
    'max' => [
        'numeric' => ':attribute 不能大於 :max',
        'file' => ':attribute 不能大於 :max KB',
        'string' => ':attribute 不能大於 :max 個字元',
        'array' => ':attribute 不能多於 :max 項',
    ],
    'mimes' => ':attribute 的檔案型別必須是: :values.',
    'mimetypes' => ':attribute 的檔案型別必須是: :values.',
    'min' => [
        'numeric' => ':attribute 最小值::min.',
        'file' => ':attribute 不能小於 :min KB',
        'string' => ':attribute 最少 :min 個字元',
        'array' => ':attribute 最少包含 :min 項',
    ],
    'not_in' => '當前選項 :attribute 無效',
    'not_regex' => ':attribute 格式錯誤',
    'numeric' => ':attribute 必須是數值',
    'present' => ':attribute 必須存在',
    'regex' => ':attribute 格式錯誤',
    'required' => '必須指定::attribute',
    'required_if' => '當 :other 等於 :value 時,必須指定::attribute',
    'required_unless' => '除非 :values 包含 :other,否則必須指定::attribute',
    'required_with' => '當 :values 存在時,必須指定::attribute',
    'required_with_all' => '當 :values 存在時,必須指定::attribute',
    'required_without' => '當 :values 不存在時,必須指定::attribute',
    'required_without_all' => '當 :values 未指定時,必須指定::attribute',
    'same' => ':attribute 必須與 :other 相匹配',
    'size' => [
        'numeric' => ':attribute 必須是 :size',
        'file' => ':attribute 必須是 :size KB',
        'string' => ':attribute 必須是 :size 個字元',
        'array' => ':attribute 必須是 :size 項',
    ],
    'string' => ':attribute 必須是字串',
    'timezone' => ':attribute 必須是有效的時區',
    'unique' => ':attribute 不能與已存在的項相同',
    'uploaded' => ':attribute 上傳失敗',
    'url' => ':attribute 格式錯誤',

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Language Lines
    |--------------------------------------------------------------------------
    |
    | Here you may specify custom validation messages for attributes using the
    | convention "attribute.rule" to name the lines. This makes it quick to
    | specify a specific custom language line for a given attribute rule.
    |
    */

    'custom' => [
        'attribute-name' => [
            'rule-name' => 'custom-message',
        ],
    ],

    /*
    |--------------------------------------------------------------------------
    | Custom Validation Attributes
    |--------------------------------------------------------------------------
    |
    | The following language lines are used to swap attribute place-holders
    | with something more reader friendly such as E-Mail Address instead
    | of "email". This simply helps us make messages a little cleaner.
    |
    */

    'attributes' => [],

];

2 、指定預設語言為中文
修改 config/app.php 檔案 中的 locale

 'locale' => 'zh',

第二步:指定 request 檔案中對應的屬性中文名

修改對應的 request 檔案,新增attributes方法。指定對應的屬性中文名

<?php

namespace App\Http\Requests;

use Dingo\Api\Http\FormRequest;

class PostRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function attributes()
    {
        return [
            'title' => "標題",
        ];
    }

    public function rules()
    {
        switch ($this->method()) {
            case 'PUT':
                return [
                    'title' => 'required'
                ];
            case 'POST':
                return [
                    'title' => 'required'
                ];
            default:
                return [];
        }
    }
}

此時、422 提示資訊如下

{
    "message": "422 Unprocessable Entity.",
    "status_code": 422,
    "errors": {
        "title": [
            "必須指定:標題"
        ]
    }
}

第三步:修改 message 提示內容

重寫 FormRequest 中的 failedValidation 方法即可

    protected function failedValidation(Validator $validator)
    {
        if ($this->container['request'] instanceof \Illuminate\Http\Request) {
            throw new ResourceException($validator->errors()->first(), $validator->errors());
        }

        throw (new ValidationException($validator))
            ->errorBag($this->errorBag)
            ->redirectTo($this->getRedirectUrl());
    }

由於 failedValidationauthorize 方法在所有的 request 中都一樣,SO 我們提出一個基類出來。程式碼檔案如下:
App\Http\Requests 中 Request 基類檔案:

<?php
namespace App\Http\Requests;

use Dingo\Api\Exception\ResourceException;
use Illuminate\Contracts\Validation\Validator;
use Dingo\Api\Http\FormRequest;
use Illuminate\Validation\ValidationException;

class Request extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    protected function failedValidation(Validator $validator)
    {
        if ($this->container['request'] instanceof \Illuminate\Http\Request) {
            throw new ResourceException($validator->errors()->first(), $validator->errors());
        }

        throw (new ValidationException($validator))
            ->errorBag($this->errorBag)
            ->redirectTo($this->getRedirectUrl());
    }
}

其他所有的 request 檔案都繼承該基類

<?php

namespace App\Http\Requests;

class PostRequest extends Request
{
    public function attributes()
    {
        return [
            'title' => "標題",
        ];
    }

    public function rules()
    {
        switch ($this->method()) {
            case 'PUT':
                return [
                    'title' => 'required'
                ];
            case 'POST':
                return [
                    'title' => 'required'
                ];
            default:
                return [];
        }
    }
}

最後出現的422提示格式

{
    "message": "必須指定:標題",
    "status_code": 422,
    "errors": {
        "title": [
            "必須指定:標題"
        ]
    }
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章