Laravelにおける複数フィールドの最低限必須のバリデーション


TL;DR

required_without_allルールを使いましょう。

required_without_allルールについてと挙動の確認

公式ドキュメントを丹念に探せば見つかるのですが、わかりづらいバリデーションとして、
複数あるフィールドの中で、最低限ひとつは入力してもらいたい場合をチェックするバリデーションがあると思います。
例えば上のキャプチャのような、いくつかのSNSアカウントを入力するフィールドがあって、その中のどれかひとつでも入力してくれればオーケーみたいな場合です。
これはrequired_without_allルールでバリデーションできます。

https://laravel.com/docs/6.x/validation#rule-required-without-all
https://readouble.com/laravel/6.x/ja/validation.html#rule-required-without-all

指定した他のフィールドがすべて存在していない場合、このフィールドが存在し、かつ空でないことをバリデートします。

よく読めばこれが求めていたルールです! と納得するのですが、流し見程度だとちょっとわかりづらい。。
そこで今回はフォームリクエストのサンプルを作り、それをテストしてrequired_without_allルールの動きを確認します。
尚、Laravelのバージョンは6です。

$ php artisan make:request SampleFormRequest
Request created successfully.
$ php artisan make:test --unit SampleFormRequestTest
Test created successfully.
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class SampleFormRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'qiita'     => 'required_without_all:github,twitter,instagram',
            'github'    => '',
            'twitter'   => '',
            'instagram' => '',
        ];
    }

    public function messages()
    {
        return [
            'qiita.required_without_all' => 'Qiita / GitHub / Twitter / Instagramの中で1個以上の項目を必ず入力してください。',
        ];
    }
}

required_without_allのパラメータで他の項目を羅列します。

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Support\Facades\Validator;
use App\Http\Requests\SampleFormRequest;

class SampleFormRequestTest extends TestCase
{
    /**
     * required_without_allルールのフォームリクエストのテスト
     *
     * @dataProvider validationDataProvider
     *
     * @param array $inputs
     * @param array $expected
     * @return void
     */
    public function testValidation(array $inputs, array $expected)
    {
        $request   = new SampleFormRequest();
        $validator = Validator::make($inputs, $request->rules(), $request->messages());
        $result    = $validator->passes();
        $errors    = $validator->errors();

        $this->assertEquals($expected['response'], $result);
        $this->assertEquals($expected['errors'], $errors->toArray());
    }

    public function validationDataProvider()
    {
        return [
            'エラー' => [
                [
                    'qiita'     => '',
                    'github'    => '',
                    'twitter'   => '',
                    'instagram' => '',
                ],
                [
                    'response' => false,
                    'errors'   => [
                        'qiita' => ['Qiita / GitHub / Twitter / Instagramの中で1個以上の項目を必ず入力してください。'],
                    ]
                ]
            ],
            '正常1' => [
                [
                    'qiita'     => 'kiyc',
                    'github'    => '',
                    'twitter'   => '',
                    'instagram' => '',
                ],
                [
                    'response' => true,
                    'errors'   => []
                ]
            ],
            '正常2' => [
                [
                    'qiita'     => '',
                    'github'    => 'kiyc',
                    'twitter'   => '',
                    'instagram' => '',
                ],
                [
                    'response' => true,
                    'errors'   => []
                ]
            ],
        ];
    }
}
$ vendor/bin/phpunit tests/Unit/SampleFormRequestTest.php 
PHPUnit 8.4.1 by Sebastian Bergmann and contributors.

...                                                                 3 / 3 (100%)

Time: 396 ms, Memory: 16.00 MB

OK (3 tests, 6 assertions)

すべて未入力だとエラーになり、ルールを指定したフィールドに入力がある場合、またはルールを指定していないフィールドに入力がない場合でもエラーにならないことを確認できました
このルールを見つけられなかったばかりに、私はわざわざカスタムルールを作ってしまったので、皆さん公式ドキュメントはしっかり読みましょう