【问题标题】:Validate a field only if another one passes validation (in Laravel 8)仅当另一个字段通过验证时才验证一个字段(在 Laravel 8 中)
【发布时间】:2021-09-14 22:34:39
【问题描述】:

我有一个问题,如果另一个规则通过/失败,你如何添加/删除规则?

public function rules()
{
    $rules = [
        'description' => 'required|unique:orders,description',
        'user_id' => 'required|unique:users,id',
        'supplier_id' => 'required',
        'warehouse_id' => 'required|unique:warehouse,id',
        'warehouse_qty' => 'required'


    ];
    
    return $rules;
}

例如,如果 "warehouse_id" 规则失败,则无需评估 "warehouse_qty" 字段的规则(因为仓库 id 在分贝)。

或者如果 "user_id" 字段的规则成功,则应激活新规则,例如 "user_name""user_phone" 字段.

谢谢!

【问题讨论】:

标签: php laravel forms validation conditional-statements


【解决方案1】:

只有在另一个通过验证时才验证一个字段,有多种解决方案。

方法#2 (推荐)

从 Laravel 5.3.23 开始;只需将依赖于另一个字段规则的任何字段验证移动到 Controller 的 withValidator(...) 方法中,例如:

use Illuminate\Support\Facades\Validator;

// ...

public function withValidator($validator)
{
    $validator->after(function ($validator) {
        // Skip if any previous field was invalid.
        if ($validator->failed()) return;

        // Actual validation (for fields depending on previous).
        Validator::make($this->input(), [
            'warehouse_qty' => ['required']
        ])->validate();
    });
}

这样做的好处是可以像往常一样简单地使用现有规则(而不是像下面的方法那样重写“required”规则的源代码)。

另见related Laracast post

注意如果没有定义rules()方法, withValidator(...) 永远不会被调用(调用$this->input() 可能会导致函数未定义错误)。

方法#1 (旧答案)

从 Laravel 5.6 及更高版本开始,我们可以执行以下操作:

use Illuminate\Support\Facades\Validator;

// ...

public function rules()
{
    $result = [
        // ...
        'warehouse_id' => 'required|unique:warehouse,id',
    ];

    if (Validator::make($this->input(), $result)->passes()) {
        $result['warehouse_qty'] = [
            function ($attribute, $value, $fail) {
                if (empty($value)) {
                    $fail('The '.$attribute.' is required.');
                }
            },
        ];
    }

    return $result;
}

请注意,要使上述工作正常,字段顺序很重要,应将closure 添加到数组所依赖的字段之后。

-------===--------

虽然上面是自定义方法(对于询问的问题),但为 same 字段的规则执行此操作是 Laravel 内置的。

  1. 如果通过了另一条规则,则添加一条规则很容易:
    • 规则从左到右执行。
    • 使用竖线(| 字符)分隔规则。
    • 而且,只要左边的规则通过,后面的规则就会被添加和/或执行。
  2. 如果另一条规则失败,则删除一条规则也可以通过管道实现。

    仅仅是因为失败的规则之后的任何规则都被忽略了。

  3. 但是上述两个语句的相反是不可能的:
    • 如果上一条失败,我们无法添加和/或执行下一条规则。
    • 如果之前通过,我们无法删除下一条规则。
    • 至少,不是没有自定义函数。

【讨论】:

    【解决方案2】:

    感谢所有为我的问题提供解决方案的人,尤其是Top-Master,因为他的解释让我看到了另一种观点。

    我终于能够解决我的问题,这就是我的解决方案。如果有人可以改进代码,欢迎。

    public function rules()
    {   
    
        $rules = [
            'description' => 'required|unique:orders,description',
            'user_id' => 'required|unique:users,id',
            'supplier_id' => 'required'
        ];
      
        $rules = $this->validateItems($rules);
        
        return $rules;
    }
    
    public function validateItems($rules){
    
    
            $rules["warehouse_id"] = ['required', 
                                      'unique:warehouse,id'];
            
            //Here I validate if the rules of the "warehouse_id" field fail or not.
            $validator = Validator::make($this->input('warehouse_id'), [
                "id" => ['required', 
                         'unique:warehouse,id']
            ]);
    
            //If the validation doesn't fail, the "warehouse_qty" field is added to $rule                                 
            if(!($validator->fails())){
                $rules["warehouse_qty"] = ['required'];
            }
            
        }
        return $rules;
    }
    

    【讨论】:

    • 查看我的方法#2,它喜欢你的答案,其优点是直接使用规则(如required)而不重写它们(但没有你的答案缺点)。
    • 缺点:你正在复制和运行warehouse_id 字段的规则(我的方法#2 没有这样做),而且 Laravel 会重做它(让你的代码慢一点)。
    猜你喜欢
    • 1970-01-01
    • 2016-01-11
    • 1970-01-01
    • 1970-01-01
    • 2016-09-21
    • 2020-10-23
    • 1970-01-01
    • 1970-01-01
    • 2013-06-15
    相关资源
    最近更新 更多