Laravel Validator 複数の日付フォーマットに対応したい場合

# やりたいこと
Laravelのバリデーションで複数のフォーマットを許可するバリデーションを書きたい。

具体的には
- 2018/01/01 (Y/m/d)
- 2018/1/01 (Y/n/d)
- 2018/01/1 (Y/m/j)
- 2018/1/1 (Y/n/j)

のどれかでだったらOKというバリデーションが書きたかった。

※そもそもなんでそんな状況になる？ というのは触れずに。。。

# 前提
Laravel 5.5
PHP 7.2

# 解決方法
複数記載できるバリデータを作成した。
フォーマットのチエック処理は本家に合わせた
→[本家 date_formatバリデータの実装](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Validation/Concerns/ValidatesAttributes.php#L353)

```php:app/Rules/DateFormats.php
<?php

namespace App\Rules;

use DateTime;
use Illuminate\Contracts\Validation\Rule;

class DateFormats implements Rule
{
    protected $dateFormats = [];

    /**
     * Create a new rule instance.
     *
     * @return void
     */
    public function __construct(array $dateFormats)
    {
        $this->dateFormats = $dateFormats;
    }

    /**
     * Determine if the validation rule passes.
     *
     * @param  string  $attribute
     * @param  mixed  $value
     * @return bool
     */
    public function passes($attribute, $value)
    {
        foreach ($this->dateFormats as $key => $format) {
            if (! is_string($value) && ! is_numeric($value)) {
                return false;
            }

            $date = DateTime::createFromFormat('!'.$format, $value);
            $isValidated = $date && $date->format($format) == $value;

            if($isValidated)
            {
                //バリデーションが成功した時点で true 返却
                return true;
            }
        }

        return false;
    }

    /**
     * Get the validation error message.
     *
     * @return string
     */
    public function message()
    {
        return ':attribute に正しい日付を入力してください';
    }
}

```

#使い方

```php:○○FormRequest
public function rules()
{
    return [
        'inputDate' => [
            'required',
            new App\Rules\DateFormats(['Y/m/d', 'Y/n/d', 'Y/m/j', 'Y/n/j'])
        ]
    ];
}
```

# テストコード

```php:tests/Unit/Rules/DateFormatsTest.php
<?php

namespace Tests\Unit\App\Rules;

use Validator;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;

use App\Rules\DateFormats;

class DateFormatsTest extends TestCase
{
    

    protected $dateFormats = ['Y/m/d', 'Y/n/d', 'Y/m/j', 'Y/n/j'];

    /**
     *
     * @return void
     */
    public function test_date_formats()
    {   
        $testInput = [
            '2018/01/01' => false,
            '2018/01/1' => false,
            '2018/1/01' => false,
            '2018/1/1' => false,
            '12:00' => true,
            '23:00' => true,
        ];

        foreach ($testInput as $dateValue => $expected) {
        
            $input['inputDate'] = $dateValue;
            $validator = Validator::make($input, [
                'inputDate' => [
                    new DateFormats($this->dateFormats)
                ]
            ]);
            $this->assertEquals( $validator->fails() ,$expected);
        }
    }
}
```

```console

# ./vendor/bin/phpunit ./tests/Unit/Rules/DateFormatsTest.php
PHPUnit 6.5.7 by Sebastian Bergmann and contributors.

Error:         No code coverage driver is available

.                                                                   1 / 1 (100%)

Time: 805 ms, Memory: 12.00MB
```