Laravel バリデーションで他のカラムを比較する

# laravel バリデーションでカラム名を使用する

- バリデーションで最大値と最小値のバリデーションをするときカラム名を使用したい時がある
    - max_priceの入力値をmin_priceよりも大きいように指定したいような場合
        - この内容は拡張しなくても使用できるようになっているかも？？(2019/8/19)

```php:
$request->validator([
'min_price' => 'required|integer|digits_between:1,4',
'max_price' => 'required|integer|digits_between:1,4|min:min_price',
]);
```

しかし、min:では整数値しか受け付けないため、カラム名を使用できるように拡張が必要となる

# カスタムバリデーションの作成
## サービスプロバイダーの作成

```shell
# コマンド実行すると次のサービスプロバイダのファイルが生成される
$ php artisan make:provider ValidatorServiceProvider
```

生成されたファイルのboot()メソッドの編集


```php:app/Providers/ValidatorServiceProvider.php
<?php

namespace App\Providers;

use Validator;
use App\Services\CustomValidator;
use Illuminate\Support\ServiceProvider;

class ValidatorServiceProvider extends ServiceProvider
{
  /**
   * 全アプリケーションサービスの登録
   *
   * @return void
   */
  public function register()
  {
    //
  }

  /**
   * 全アプリケーションサービスの初期起動
   *
   * @return void
   */
  public function boot()
  {
    Validator::resolver(function ($translator, $data, $rules, $messages) {
      return new CustomValidator($translator, $data, $rules, $messages);
    });
  }
}
```

## 作成したサービスプロバイダーを設定ファイルに追記

```php:config/app.php
'providers' => [
    ...

    App\Providers\ValidatorServiceProvider::class,

    ...
```



## minの拡張
- `Illuminate\Validation\Concerns\ValidatesAttributes::validateMin`の内容をオーバーライドして拡張

```php:Illuminate\Validation\Concerns\ValidatesAttributes::validateMin
    /**
     * Validate the size of an attribute is greater than a minimum value.
     *
     * @param  string  $attribute
     * @param  mixed   $value
     * @param  array   $parameters
     * @return bool
     */
    public function validateMin($attribute, $value, $parameters)
    {
        $this->requireParameterCount(1, $parameters, 'min');

        return $this->getSize($attribute, $value) >= $parameters[0];
    }
```


- `App\Services\CustomValidator.php`を作成し、`\Illuminate\Validation\Validator` を継承してオーバーライドする内容を書く


```php:App\Services\CustomValidator.php
<?php

namespace App\Services;

class CustomValidator extends \Illuminate\Validation\Validator
{
  /**
   * 最小値 min
   * @param string $attribute
   * @param string $value
   * @param array $parameters 0 => 比較するカラム名
   * @return true
   */
  public function validateMin($attribute, $value, $parameters)
  {
    if (
      !is_numeric($parameters[0]) &&
      !is_null($val = $this->getValue($parameters[0]))
    ) {
      $parameters[0] = $val;
    }

    return parent::validateMin($attribute, $value, $parameters);
  }
}
```

- https://laravel.com/api/5.8/Illuminate/Validation/Concerns/ValidatesAttributes.html#method_validateMin
- https://www.larajapan.com/2016/10/15/%E3%83%90%E3%83%AA%E3%83%87%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3-6-%E4%BB%96%E3%81%AE%E5%B1%9E%E6%80%A7%E3%81%AE%E5%80%A4%E3%82%92%E5%8F%82%E7%85%A7/


# バリデーションのカラム名の日本語化
- **resources/lang/ja/validation.php**の100行目あたりに、**Custom Validation Attributes**という項目がある。

```php:
    /*
    |--------------------------------------------------------------------------
    | カスタムバリデーション属性名
    |--------------------------------------------------------------------------
    |
    | 以下の言語行は、例えば"email"の代わりに「メールアドレス」のように、
    | 読み手にフレンドリーな表現でプレースホルダーを置き換えるために指定する
    | 言語行です。これはメッセージをよりきれいに表示するために役に立ちます。
    |
    */

    'attributes' => [
    // 追記する内容
            'email'=>'メールアドレス',
            'password'=>'パスワード',
            'name'=>'名前',
            'category'=>'種別',
            'min_price'=>'最低価格',
            'max_price'=>'最高価格',
            'deadline'=>'募集期限',
            'detail'=>'詳細',
            'title'=>'タイトル',
            'price'=>'価格',
    ],
```

## を引数に入れた場合の日本語化

- カラム名を引数に取れるように拡張した min, max で英文字のカラム名が展開できるのは、数値が与えられたときの標準の展開がそのまま適用されており、対応が必要
    - https://www.larajapan.com/author/rapidexp/


## valueの値を日本語にする

- minの場合次のように定義されており、attributeの文字を日本語にしても:minの値が数値が与えられたときのみに対応されるようになっている
    - https://qiita.com/UNILORN/items/ca422ccb0d76e1e24351


```php:resources\lang\ja\validator.php
'min'=> [
    'numeric' => ':attributeには、:min以上の数字を指定してください。',
]
```

- CustomValidatorのコンストラクタを追記し、最終的には次のようにする


```php:App\Services\CustomValidator.php
<?php

namespace App\Services;

class CustomValidator extends \Illuminate\Validation\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(':'.$rule, $data[$attribute], $message);
    };
      // 表示させる文字列を入れることもできる
      return str_replace(':'.$rule, '最低価格', $message);
    };

    // 上記のクロージャを適応するルール
    $this->addReplacers([
      "min" => $replacer,
    ]);
  }

  /**
   * 最小値 min
   * @param string $attribute
   * @param string $value
   * @param array $parameters 0 => 比較するカラム名
   * @return true
   */
  public function validateMin($attribute, $value, $parameters)
  {
    if (
      !is_numeric($parameters[0]) &&
      !is_null($val = $this->getValue($parameters[0]))
    ) {
      $parameters[0] = $val;
    }

    return parent::validateMin($attribute, $value, $parameters);
  }
}

```