Laravel 复杂条件验证

Laravel Complex Conditional Validation

我正在尝试创建一个至少需要三个输入之一的验证器。

我试过了

protected function validateFundingSource (): array
{
    return request()->validate([
       'title'       => 'required',
       'description' => 'required',
       'national'       => 'nullable',
       'province'       => Rule::requiredIf(!request('national')),
       'url'            => [
           'required_without_all:phone,email',
           'active_url'
       ],
       'phone'          => [
           'required_without_all:url,email|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im'
       ],
       'email' => [
           'required_without_all:url,phone|email:rfc,dns'
       ],
       'categories' => 'exists:categories,id'
   ]);
}

但它只强制第一个字段 (url)。所以我尝试了 Complex Conditional Validation.

protected function validateFundingSource ()
{

    $v = Validator::make(request()->all(), [
            'title'       => 'required',
            'description' => 'required',
            'national'       => 'nullable',
            'categories'     => 'exists:categories,id',
    ]);

    $v->sometimes('province', 'required', function ($input) {
        return ($input->national === null) ;
    });

    $v->sometimes('url', 'required|active_url', function ($input) {
        return (($input->phone === null) && ($input->email === null));
    });

    $v->sometimes('phone', 'required|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im', function ($input) {
        return (($input->url === null) && ($input->email === null));
    });

    $v->sometimes('email', 'required|email:rfc,dns', function ($input) {
        return (($input->url === null) && ($input->phone === null));
    });

    return $v;
}

但仍然没有运气......现在不再需要我可以提交所有三个空字段并且它正在工作......

有什么线索可以帮助我吗?

谢谢!

您的代码运行良好。您只是忘记检查验证是否通过。 因为当你使用 Validator::make 时你需要手动检查它。 for request()->validate laravel 将为您完成。在您的 validateFundingSource () 函数中,只需在 return 之前检查它是否通过验证,如下所示:

private function validateFundingSource () {
        $v = Validator::make(request()->all(), [
                'title'       => 'required',
                'description' => 'required',
                'national'       => 'nullable',
                'categories'     => 'exists:categories,id',
        ]);

        $v->sometimes('province', 'required', function ($input) {
            return ($input->national === null) ;
        });

        $v->sometimes('url', 'required|active_url', function ($input) {
            return (($input->phone === null) && ($input->email === null));
        });

        $v->sometimes('phone', 'required|regex:/^(\+\s?)?1?\-?\.?\s?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4}(?: *#(\d+))?\s*$/im', function ($input) {
            return (($input->url === null) && ($input->email === null));
        });

        $v->sometimes('email', 'required|email:rfc,dns', function ($input) {
            return (($input->url === null) && ($input->phone === null));
        });

        // check if validae failed
        if($v->fails()) {
            dd('fail', $v); // do something when it failed
        }
    }

也很抱歉我的英语不好,希望对您有所帮助

如果您要查找 "at least one of" urlphoneemail,那么您需要使用 required_without。此规则表示当缺少 any 指定字段时,该字段是必需的; required_without_all 表示缺少 所有 指定字段时需要。

您还混淆了规则语法,您必须使用数组或竖线分隔的字符串语法,不能同时使用两者。

您可能还想改进 phone 数字正则表达式; + -. (000-111.9999 #8 不是一个很好的 phone 数字,但会通过您的验证。我建议清理您的值以删除除数字和前导 + 之外的所有内容,然后在剩下的内容上使用更好的模式。

而且,这只是外观上的更改,但您可以像其他规则一样用简单的 required_if 规则替换 Rule::requiredIf(!request('national')),

更改为 form request validation,这看起来像:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

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

    /**
     * Prepare the data for validation.
     *
     * @return void
     */
    protected function prepareForValidation()
    {
        $phone = preg_replace("/[^0-9]/", "", $this->phone);
        if (strpos($this->phone, "+") === 0) {
            $phone = "+$phone";
        }
        $this->merge(["phone"=>$phone]);
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
           'title'       => ['required'],
           'description' => ['required'],
           'national'    => ['nullable'],
           'province'    => ['required_if,national,'],
           'categories'  => ['exists:categories,id']
           'url'         => [
               'required_without:phone,email',
               'active_url'
           ],
           'phone'       => [
               'required_without:url,email',
               'regex:/^\+?1?[2-9][0-9]{5,14}$/'
           ],
           'email'       => [
               'required_without:url,phone',
               'email:rfc,dns'
           ],
       ];
    }
}