Laravel验证规则:如果值存在于另一个字段数组中

22

我正在使用Laravel 5.4,需要稍微特定的验证规则,但我认为这应该可以轻松实现,而不必扩展类。只是不确定如何使其工作...

我想做的是,如果program数组包含'Music',则使'music_instrument'表单字段为必填项。

我找到了这个帖子How to set require if value is chosen in another multiple choice field in validation of laravel?,但它并不是一个解决方案(因为一开始就没有解决),而且它不起作用的原因是提交的数组索引不是恒定的(未选中的复选框在索引提交结果时不被考虑...)

我的情况看起来像这样:

<form action="" method="post">
    <fieldset>

        <input name="program[]" value="Anthropology" type="checkbox">Anthropology
        <input name="program[]" value="Biology"      type="checkbox">Biology
        <input name="program[]" value="Chemistry"    type="checkbox">Chemistry
        <input name="program[]" value="Music"        type="checkbox">Music
        <input name="program[]" value="Philosophy"   type="checkbox">Philosophy
        <input name="program[]" value="Zombies"      type="checkbox">Zombies

        <input name="music_instrument" type="text" value"">

        <button type="submit">Submit</button>

    </fieldset>
</form>
如果我从复选框列表中选择一些选项,这可能会在我的$request值中产生此结果。
[program] => Array
    (
        [0] => Anthropology
        [1] => Biology
        [2] => Music
        [3] => Philosophy
    )

[music_instrument] => 'Guitar'

在这里查看验证规则:https://laravel.com/docs/5.4/validation#available-validation-rules,我认为像这样的东西应该可以工作,但实际上我什么也没有得到:

  $validator = Validator::make($request->all(),[
        'program'           => 'required',
        'music_instrument'  => 'required_if:program,in:Music'
  ]);

我也希望这个能行,但没成功:

'music_instrument'  => 'required_if:program,in_array:Music',

有想法吗?建议呢?

谢谢!


从文档中:required_array_keys:foo,bar,... - Fr0zenFyr
5个回答

42

我没有尝试过这个,但通常在数组字段中,您通常会像这样编写:program.*,因此也许像这样会奏效:

  $validator = Validator::make($request->all(),[
        'program'           => 'required',
        'music_instrument'  => 'required_if:program.*,in:Music'
  ]);

如果它不起作用,显然你也可以用另一种方式,例如像这样:

$rules = ['program' => 'required'];

if (in_array('Music', $request->input('program', []))) {
    $rules['music_instrument'] = 'required';
}

$validator = Validator::make($request->all(), $rules);

我尝试了使用星号,但它被忽略了。我能够通过 required_if:program.34,Music,,, 让它工作,但是为此我必须索引我的列表并跟踪 34,这显然不是一个好主意... 我也会尝试这种方法。谢谢。我希望 Laravel 的 in_array 能够起作用,但没有成功。 - GRowing
3
我会接受你提出的第二种方案,因为那正是我采取的方式 :) 谢谢!为了论证,如果其他人提出一个超出传统的、可行的配置,我依然想看看它... 呵呵。 - GRowing

13

我知道这篇文章已经有些年头了,但如果有人再次遇到这个问题。

$validator = Validator::make($request->all(),[
    'program' => 'required',
    'music_instrument'  => 'required_if:program,Music,other values'
]);

谢谢@Noman Sheikh,你节省了我的时间。 - Faridul Khan
来自文档:required_array_keys:foo,bar,... - Fr0zenFyr

4
您可以按照以下方式创建一个名为required_if_array_contains的新自定义规则...

在app / Providers / CustomValidatorProvider.php中添加一个新的私有函数:

/**
 * A version of required_if that works for groups of checkboxes and multi-selects
 */
private function required_if_array_contains(): void
{
    $this->app['validator']->extend('required_if_array_contains',
        function ($attribute, $value, $parameters, Validator $validator){

            // The first item in the array of parameters is the field that we take the value from
            $valueField = array_shift($parameters);

            $valueFieldValues = Input::get($valueField);

            if (is_null($valueFieldValues)) {
                return true;
            }

            foreach ($parameters as $parameter) {
                if (in_array($parameter, $valueFieldValues) && strlen(trim($value)) == 0) {
                    // As soon as we find one of the parameters has been selected, we reject if field is empty

                    $validator->addReplacer('required_if_array_contains', function($message) use ($parameter) {
                        return str_replace(':value', $parameter, $message);
                    });

                    return false;
                }
            }

            // If we've managed to get this far, none of the parameters were selected so it must be valid
            return true;
        });
}

不要忘记在CustomValidatorProvider.php文件的顶部检查是否有use语句,用于我们在新方法中将Validator作为参数使用:

...

use Illuminate\Validation\Validator;

然后在CustomValidatorProvider.php文件的boot()方法中调用您的新的私有方法:

public function boot()
{
    ...

    $this->required_if_array_contains();
}

接下来,将Laravel教会以人类友好的方式编写验证消息,方法是在resources/lang/en/validation.php中添加一个新项到数组中:

return [
    ...

    'required_if_array_contains' => ':attribute must be provided when &quot;:value&quot; is selected.',
]

现在,您可以像这样编写验证规则:
public function rules()
{
    return [
        "animals": "required",
        "animals-other": "required_if_array_contains:animals,other-mamal,other-reptile",
    ];
}

在上面的示例中,animals是一组复选框,animals-other是一个文本输入框,只有在选中other-mamalother-reptile值时才需要填写。
这也适用于启用多项选择的选择输入或任何导致请求中一个输入的值数组的输入。

从文档中:required_array_keys:foo,bar,... - Fr0zenFyr

3

我在处理类似问题时采取的方法是,在我的控制器类中创建一个私有函数,并使用三元表达式来添加所需字段,如果返回值为true。

在这种情况下,大约有20个字段具有复选框以启用输入字段,因此与其他方案相比可能过于繁琐,但随着您的需求增长,它可能会证明有用。

/**
 * Check if the parameterized value is in the submitted list of programs
 *  
 * @param Request $request
 * @param string $value
 */
private function _checkProgram(Request $request, string $value)
{
    if ($request->has('program')) {
        return in_array($value, $request->input('program'));
    }

    return false;
}

使用此函数,您可以为其他程序的其他字段应用相同的逻辑。
然后在存储函数中:
public function store(Request $request)
{
    $this->validate(request(), [
    // ... your other validation here
    'music_instrument'  => ''.($this->_checkProgram($request, 'music') ? 'required' : '').'',
    // or if you have some other validation like max value, just remember to add the |-delimiter:
    'music_instrument'  => 'max:64'.($this->_checkProgram($request, 'music') ? '|required' : '').'',
    ]);

    // rest of your store function
}

2

这是我的一段代码,用于使用Laravel 6验证规则解决类似问题。

我尝试使用上面的代码。

public function rules() 
{
    return [
      "some_array_field.*" => ["required", "integer", "in:1,2,4,5"],
      "another_field" => ["nullable", "required_if:operacao.*,in:1"],
    ];
}

我需要的是当some_array_field的值为1时,必须验证another_field,否则可以为空。使用上述代码时,即使使用required_if:operacao.*,1也无法正常工作。
如果我将规则更改为required_if:operacao.0,1,就可以正常工作,但只有在要查找的值位于索引0时才有效,当顺序改变时,验证失败。
因此,我决定使用自定义闭包函数。
这是对于我来说完美工作的示例最终代码。
public function rules() 
{
    return [
      "some_array_field.*" => ["required", "integer", "in:1,2,4,5"],
      "another_field" => [
          "nullable",
          Rule::requiredIf (
              function () {
                  return in_array(1, (array)$this->request->get("some_array_field"));
              }
          ),
        ]
    ];
}

我希望这也能解决你的麻烦!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接