Laravelのmax file sizeのValidationメッセージでKBをMBにする方法


概要

タイトル通りです。
max file sizeのValidationはデフォルトでKB表示になっているので、それをMBやGBに変更する方法を調べたので備忘録です。

環境

PHP: 7.2.22
Laravel: 6.18.3

事前準備

以下のようにRequestオブジェクトにvalidationのルールを記述すると「inputFile」フォームからアップロードするファイルの上限を1MBに設定します。

app/Http/Requests/FileUploadRequest.php
    public function rules()
    {
        return [
            'inputFile' => 'max:1024'
        ];
    }

1MB以上のファイルをアップロードした場合は以下のように「The input file may not be greater than 1024 kilobytes.」と表示されるので、これをメガバイト表示に修正していきます。

設定変更

方法1: メッセージを固定する

一番手軽に解決できます。
該当のフォームがvalidationに引っかかった場合に表示するメッセージを〜megabytesで固定します。

app/Http/Requests/FileUploadRequest.php
    public function rules()
    {
        return [
            'inputFile' => 'max:1024'
        ];
    }

    public function messages()
    {
        return [
            'inputFile.max' => 'The input file may not be greater than 1 megabytes.'
        ];
    }

方法2: カスタムValiationルールを作成する

方法1のやり方だと上限の1MBが2MB等に変更になったときにメッセージも都度修正しないといけないので面倒です。
なので、KBではなくMB表示できるような新しいvalidationのルールを作成します。
参考1(公式ドキュメント)
参考2(stack overflow)

app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Validator;
use Illuminate\Support\ServiceProvider;
use InvalidArgumentException;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        // max_mb ファイルサイズの最大値をメガバイトで指定するvalidationルールを追加する
        Validator::extend('max_mb', function ($attribute, $value, $parameters, $validator) {
            // パラメータ数のチェック
            $this->requireParameterCount(1, $parameters, 'max_mb');

            // アップロードに成功しているかの判定
            if ($value instanceof UploadedFile && ! $value->isValid()) {
                return false;
            }

            // ファイルサイズをMBに変換
            $megaBytes = $value->getSize() / 1024 / 1024;

            // $parametersにルールで設定した引数より小さければ問題なし
            return $megaBytes <= $parameters[0];
        });

        // validationメッセージ「The :attribute may not be greater than :max_mb megabytes.」の
        // 「:max_mb」部分をパラメータとして与えられた値と置き換える
        Validator::replacer('max_mb', function ($message, $attribute, $rule, $parameters) {
            return str_replace(':max_mb', $parameters[0], $message);
        });
    }

    /**
     * ルールに与えられるパラメータ数のチェックを行う
     *
     * @param integer $count
     * @param array $parameters
     * @param string $rule
     * @return void
     */
    protected function requireParameterCount($count, $parameters, $rule)
    {
        if (count($parameters) < $count) {
            throw new InvalidArgumentException("Validation rule $rule requires at least $count parameters.");
        }
    }
}
validation.php
    'max_mb' => 'The :attribute may not be greater than :max_mb megabytes.'

AppServiceProviderにValidationルールを書くのが嫌な場合は、新しくServiceProviderを作成してそっちに記述する必要があります。

方法3: ルールオブジェクトを作成する

方法2はLaravel5.4までで行われていた方法のようで、Laravel5.5以降はルールオブジェクトを作成することでのカスタムValidationルールの作成が可能でしたので、そちらも試します。
参考(公式ドキュメント)

まず、下記コマンドを実行します。

$ php artisan make:rule MegaBytes

app/Rules/MegaBytes.phpが作成されたので以下のように編集します。

MegaBytes.php
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class MegaBytes implements Rule
{
    protected $param;

    public function __construct($param)
    {
        $this->param = $param;
    }

    public function passes($attribute, $value)
    {
        $megaBytes = $value->getSize() / 1024 / 1024;

        return $megaBytes <= $this->param;
    }

    public function message()
    {
        return trans('validation.max_mb', ['max_mb' => $this->param]);
    }
}

messageメソッドではtransヘルパーを利用して方法2と同様にvalidation.phpにメッセージを記述して、それを呼び出しています。
このルールを呼び出す時はForm Requestだと以下のように書けます。

<?php

namespace App\Http\Requests;

use App\Rules\MegaBytes;
use Illuminate\Foundation\Http\FormRequest;

//
// 中略
// 
    public function rules()
    {
        return [
            'inputFile' => [new MegaBytes(1)]
        ];
    }

方法4: Validator::replacerだけで値を修正する(2020/05/02追記)

コメントでご指摘いただきました。多謝。
方法2ではValidator::extendでvalidationルールを追加していますが、Validator::replacerだけでも同じような動作を実現できます。

Validator::replacer('max', function ($message, $attribute, $rule, $parameters) {
    return str_replace(':max_mb', $parameters[0] / 1024, $message);
});
    public function rules()
    {
        return [
            'inputFile' => 'max:1024'
        ];
    }

    public function messages()
    {
        return [
            'inputFile.max' => 'The input file may not be greater than :max_mb megabytes.'
        ];
    }

所感

個人的には方法2が分かりやすかったです。

他にやり方があるようでしたら是非コメントをお願いしますー。