Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Input validation exclusive or

I have a model called Answer.

This model has two possible relations. A Question or a Product. But, Answer should only ever have one relation. Either Question or Product.

There is a form to create answers.

This form has three inputs. two of them are <select> inputs. The other is a text input, called name.

I want my validation to only allow one to be filled out.

My current validation:

$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);
});

Requires at least one of the selected to be filled out, but will also allow two.

So, my question is: How can I change my validation to only allow one of the selects to be filled out. But one of them must always be filled out.

Select 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>

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>
like image 201
CharliePrynn Avatar asked Sep 04 '25 17:09

CharliePrynn


1 Answers

@Razor's custom XOR validation rule is pretty nice, but there's another route if you don't want to create a custom rule. You can add values to Input representing your constraints, using Input::merge, then use those for validation:

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.'         
    )
);

You should still change the empty value in your form to <option value=''>None</option>.

Unlike using an XOR comparison, this method allows you to return separate error messages for no values vs. two values without any further error checking.

like image 124
damiani Avatar answered Sep 07 '25 06:09

damiani