【问题标题】:Input validation exclusive or输入验证异或
【发布时间】:2014-12-20 06:21:55
【问题描述】:

我有一个名为 Answer 的模型。

这个模型有两种可能的关系。 QuestionProduct。 但是,Answer 应该只有一个关系。问题或产品。

有一个表格可以创建答案。

此表单具有三个输入。其中两个是<select> 输入。另一种是文本输入,称为名称。

我希望我的验证只允许填写一个。

我目前的验证:

$validator = Validator::make(
    Input::all(),
    array('name' => array('required'))
);

$validator->sometimes('product', array('required', 'numeric'), function ($input) {
    return !is_numeric($input->question);
});

$validator->sometimes('question', array('required', 'numeric'), function ($input) {
    return !is_numeric($input->product);
});

要求至少填写一项,但也允许填写两项。

所以,我的问题是:如何更改我的验证以仅允许填写其中一项选择。 但必须始终填写其中一项。

选择 1:

<select name="question" class="form-control">
    <option>None</option>
    <option value="1" selected="selected">Question 1</option>
    <option value="2">Question 2</option>
</select>

选择 2:

<select name="product" class="form-control">
    <option>None</option>
    <option value="2" selected="selected">Product 1</option>
    <option value="3">Product 2</option>
</select>

【问题讨论】:

    标签: php laravel laravel-4 laravel-validation


    【解决方案1】:

    首先。您必须在“无”选项中指定一个空值:

    <option value=''>None</option>
    

    您正在寻找XOR 运算符,在这种情况下您需要创建自定义验证规则:

    Validator::extendImplicit('xor', function($attribute, $value, $parameters)
    {
        if( $value XOR app('request')->get($parameters[0]))
            return true;
        return false;
    });
    Validator::replacer('xor', function($message, $attribute, $rule, $parameters)
    {
        // add indefinite articles
        $IAattribute = (stristr('aeiou', $attribute[0]) ? 'an ' : 'a ') . $attribute;
        $parameters[0] = (stristr('aeiou', $parameters[0][0]) ? 'an ' : 'a ') . $parameters[0];
    
        if(app('request')->get($attribute))
            return 'You cannot choose both '.$IAattribute.' and '.$parameters[0].'.';
        return $IAattribute.' or '.$parameters[0].' is required.';
    });
    
    
    $validator = Validator::make(
        app('request')->all(),
        array('name' => array('required')
        ,'product' => array('xor:question')
    ));
    

    【讨论】:

    • 第一个闭包(又名匿名函数)中的逻辑可以合并和缩减。我已相应地编辑了您的答案。也可以考虑使用“新”数组样式[]
    【解决方案2】:

    @Razor 的自定义 XOR 验证规则非常好,但如果您不想创建自定义规则,还有另一种方法。您可以使用 Input::mergeInput 添加代表您的约束的值,然后使用这些值进行验证:

    Input::merge(array(
        'hasBoth'    => Input::has('product')  && Input::has('question'),
        'hasNeither' => !Input::has('product') && !Input::has('question')
    ));
    
    $validator = Validator::make(
        Input::all(), array(
            'name'       => 'required',
            'hasNeither' => 'size:0',
            'hasBoth'    => 'size:0',
        ), array(
            'hasNeither.size' => 'A question or a product is required.',
            'hasBoth.size'    => 'You cannot choose both a question and a product.'         
        )
    );
    

    您仍应将表单中的空值更改为&lt;option value=''&gt;None&lt;/option&gt;

    与使用 XOR 比较不同,此方法允许您针对 无值两个值 返回单独的错误消息,而无需任何进一步的错误检查。

    【讨论】:

    • 非常好的解决方法,我喜欢它。但是,它不可重复使用。此外,通过 XOR 比较,您可以返回单独的错误消息,检查我的编辑(我收到您的消息:p)。如果@CharliePrynn 不需要以其他形式重用此逻辑,那么您的答案可能是最好的。
    • 是的,如果需要的话,它不容易重复使用。但是,如果需要可重用性,我认为将相同的逻辑(将输入组合在一起并测试它们是否存在或都不存在)抽象到自定义验证器类中是有意义的。我可以设想一个像 'group'=&gt;'hasAll:product,question,other''group'=&gt;'hasNone:product,question,other' 这样的构造来处理 Input::merge 部分中的逻辑。这样,您仍然可以轻松地独立测试这两个条件,还可以为每个条件单独设置自定义错误消息。
    • 再想一想,扩展 Validator 类以包含“has”功能会很棒,它可以接受一个数组或字段列表,然后将它们作为一个组进行验证,例如: 'product,question,other' =&gt; 'hasMoreThan:0''hasLessThen:2'/'hasBetween:0,2'/'has:all'/'has:none'/'has:5' 等。然后您可以完全控制错误消息,并且该逻辑可用于任意数量的字段。在@CharliePrynn 的情况下,您将运行'product,question' =&gt; 'hasMoreThan:0|hasLessThan:2' 并能够为每个条件返回单独的错误消息。
    【解决方案3】:

    required_withoutvalidation rule 可能是您想要的:

    验证中的字段必须仅在其他任何 指定的字段不存在。

    question 字段设置为required_without:product,将product 字段设置为required_without:question

    【讨论】:

    • 这将使验证工作类似于当前的工作方式。这意味着用户仍然可以同时选择两者,并且验证将通过。我可以在控制器中有额外的逻辑来处理这个并选择一个,但我真的不想采用这种方法。如果我能找到一种方法让验证处理它,我会更喜欢。
    猜你喜欢
    • 2023-03-15
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多