【laravel】ruleオブジェクトによる検証ルールの追加

# 概要
laravelではいくつかの方法でバリデーションをかけることができます。
そのため一度に投稿するとボリュームが多くなるので複数回に分けます。

[・validateメソッドによるバリデーション]()
[・FormRequestによるバリデーション]()
[・Validatorによるバリデーション]()
[・バリデーションエラーの表示と日本語化]()

# 検証ルールの追加
用意されている検証ルールは多数ありますが、独自の検証ルールを設定することも可能です。
ここでは`Illuminate\Contracts\Validation`のRuleクラスを継承する方法を投稿します。

# オブジェクトの作成
バリデーションの条件とエラーメッセージを設定するオブジェクトを作成します。

## コマンド
手作業でも作成できますがartisanコマンドの`make:rule`を利用すれば自動で作成されます。
ここではSampleRuleというクラスを作成します。

```:コマンド
php artisan make:rule SampleRule
```

## ディレクトリ構造
appにRelesフォルダが作成されます。
フォームリクエストは指定がなければapp内に配置されます。

```:ディレクトリ
app
├─ Rules
|  ├─ Myrule.php
```

## 作成されるファイル
artisanコマンドで作成した場合は以下のような内容が自動で作成されます。
長くなるのでコメント部分は割愛します。

```php:SampleRule
<?php

namespace App\Rules;

use Illuminate\Contracts\Validation\Rule;

class SampleRule implements Rule
{
  public function __construct()
  {
    //
  }

  public function passes($attribute, $value)
  {
    //
  }

  public function message()
  {
    return 'The validation error message.';
  }
}
```

## ルールオブジェクトの中身
ルールオブジェクトはRuleクラスを継承して作成され、__constructとpassesメソッド、messageメソッドが用意されます。
__constructはPHPのコンストラクタと同じ使い方をします。
passesメソッドはbool型で、messageメソッドはString型となっています。

### passes($attribute, $value)
ここに適用されたいバリデーションのルールを記述します。
trueならバリデーションを通過し、falseならエラーメッセージが返されます。
passesはルールの通貨条件を設定しており、引数にルールの設定関係をまとめたattributeとチェックする値であるvalueが用意されています。

### message()
ここでエラーメッセージを記述します。
記入した文字列をreturnすればエラーメッセージとして表示されます。

# 検証ルールの作成（正規表現）
標準で用意されているバリデーションでも、正規表現のように毎回記述すると煩雑な内容をクラスとして作成しておけば呼び出しが楽になるのでここでの例にします。

```php:SampleRule
public function passes($attribute, $value)
{
  $param = '/^[a-zA-Z0-9]+$/u';
  return preg_match($param, $value);
}
```

# エラーメッセージの作成
エラーメッセージの作成には2つの方法があります。
・ruleオブジェクトのmessageメソッドでreturnする
・resourcesのlangに登録する

## messageメソッドでreturn
あれこれ登録する手間がないため、シンプルなエラーメッセージの場合はこの方法が楽でわかりやすいです。

```php:SampleRule
public function message()
{
  return '半角英数字で入力してください';
}
```

## resourcesのlangに登録
ここで作成したような半角英数字くらいの内容なら同じエラーメッセージでも問題ありませんが、使用する場面ごとにエラーメッセージを選択する場合には`resources\lang`へ登録すると便利です。
この場合はtransヘルパで取得するメッセージを指定します。

```php:SampleRule
public function message()
{
  return trans('validation.halfrule');
}

// 記述方法：trans('言語ファイル．対象のattributes名')
```

```php:resources/lang/ja/validation
return [
  'halfrule' => ':attribute半角英数字で入力してください。',
  ],

  'attributes' => [
    'name' => 'ユーザー名は',
    'address' => '住所は',
  ],

// 記述方法：'attributes名' => ':attributeエラーメッセージ'
// 'attributes' => [ ，　…は対象の:attributeに入る値の連想配列
```

# バリデーションの定義
バリデーションの検証ルールにnewすることでバリデーションが定義されま。

```php:FormRequest
public function rules()
{
  return [
    'name' => new SampleRule(),
}
```

# コンストラクタを使用したバリデーション
せっかくコンストラクタで引数を指定できるので、上記した正規表現のバリデーションと同じ内容を作成します。

## バリデーションの作成
コンストラクタの引数をString型に指定した内容にしました。
このようにコンストラクタを活用すれば正規表現のバリデーションクラスが作成できます。

例を書いてから気づいたのですが、正規表現は検証ルールとして用意されているのでわざわざクラスとして作成する必要はなかったですね…

```php:SampleRule
public function __construct(String $s)
{
  $this->str = $s;
}

public function passes($attribute, $value)
{
  return preg_match($this->str, $value);
}

public function message()
{
  return trans('validation.SampleRule');
}
```
## エラーメッセージの作成
ここでは`resources\lang`へ登録する方法を例にします。


```php:SampleRule
public function message()
{
  return trans('validation.SampleRule');
}
```

```php:resources/lang/ja/validation
return [
  'SampleRule' => ':attribute半角英数字で入力してください。',

  'attributes' => [
    'name' => 'ユーザー名は',
    'handphone' => 'ハイフンを含めた',
  ],
```

## バリデーションの定義
ここでは引数に`$name`と`$handphone`の変数を入れています。

```php:FormRequest
public function rules()
{
  $name = '/^[a-zA-Z0-9]+$/u';
  $handphone = '/^(070|080|090)-\d{4}-\d{4}$/u';

  return [
    'name' => new SampleRule($name),
    'handphone' => new SampleRule($tell),
}
```

## 用意されている検証ルールでバリデーションする
PHPなのでダブルクォーテーション`""`で囲めば変数を文字列化せずに読んでくれます。
正規表現を使うならこっちの方が確実に楽です。

```php:FormRequest
public function rules()
{
  $name = '/^[a-zA-Z0-9]+$/u';
  $handphone = '/^(070|080|090)-\d{4}-\d{4}$/u';

  return [
    'name' => ["regex:$name"],
    'handphone' => ["regex:$handphone"],
}

public function messages()
{
  return [
    'name.regex' => trans('validation.kana'),
    'handphone.regex' => trans('validation.kana'),
  ]
}
```


# 補足
検証ルールを追加する方法には`Illuminate\Validation`のValidatorクラスを継承する方法もあります。
この方法はメソッドを呼び出して作成できるためページごとに検証ルールをまとめれて便利なので。
ですが、サービスプロバイダへ登録するひと手間と、エラーメッセージを毎回記述する必要があるため煩雑に感じて割愛しました。
ちなみに`Validatorによるバリデーション`で使用したValidatorは`Illuminate\Support\Facades\Validator`のため異なるValidatorクラスです。


# 参考


[Laravel 6.x バリデーション / 使用可能なバリデーションルール]
(https://readouble.com/laravel/6.x/ja/validation.html#available-validation-rules)
[【Laravel5.6】カスタムバリデーションはルールオブジェクトを使おう]
(https://nextat.co.jp/staff/archives/207)
[はじめてLaravel6.0：バリデーション追加＆カスタムバリデーション／入力画面（２）](https://arakan-pgm-ai.hatenablog.com/entry/2019/10/30/000000)
[Laravelのフォームリクエストクラスでバリデーションロジックをコントローラから分離する / 独自バリデーションの追加）](https://www.ritolab.com/entry/41#aj_6)
[【保存版】バリデーションルールまとめ]
(https://www.wakuwakubank.com/posts/376-laravel-validation/)