I needed to create a validation rule in Laravel that would accept either of the two inputs, but not both and at least one had to be supplied. In other words, I had to apply the XOR logic operation on them:
A | B | XOR |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 0 |
The search results did offer many solutions but I did not like any of them
in particular, mostly due to their complexity or lack of clear
re-usability. The closer I could get while keeping complexity at minimum
was to use the required_without
Laravel validation rule like this:
<?php
public function rules(): array
{
return [
input1 => [
'required_without:input2',
],
input2 => [
'required_without:input1',
],
];
}
However this was still not sufficient as this is not a XOR operation, this is a plain OR operation:
A | B | OR |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
If both inputs are supplied, the validator would happily accept them.
Thinking a little bit I found that there is also a prohibits
Laravel
validation operator, so I applied it:
<?php
public function rules(): array
{
return [
input1 => [
'required_without:input2',
'prohibits:input2',
],
input2 => [
'required_without:input1',
'prohibits:input1',
],
];
}
This works as expected. The XOR operation is applied to both input1
and
input2
.
Validation messages
The only drawback was the validation message returned:
{
"message": "The given data was invalid.",
"errors": {
"qrcode": ["validation.prohibits"],
"code": ["validation.prohibits"]
}
}
The above means that the message is simply not supplied and its "path"
returned. Filling in the path validation.prohibits
with a string value
would return an error messages. This is a core part of the Laravel
validator, see links for documentation. To reduce the code repetition, the
result could look like this:
<?php
public function messages(): array
{
return [
...$this->customMessage('input1', 'input2'),
...$this->customMessage('input2', 'input1'),
];
}
private function customMessage(string $input, string $otherInput): array
{
return [
"$input.prohibits" => "The $input field is prohibited when $otherInput is present."
];
}
Hope this helps. Enjoy!