I'm on "zendframework/zend-inputfilter" v2.8.1. Quite surprisingly for me - I wasn't able to find the configuration or setup option for next scenario:
We have 2 fields, and either one or another needs to be populated.
For example: we have 2 fields: "year" and "age". I want to create a validation config where either "year" or "age" needs to be set.
So my valid payload should look like this
{
"year": 2000
}
Or
{
"age": 18
}
Or
{
"year": 2000,
"age": 18
}
This should be invalid:
{}
Unfortunately it seems other questions like this (Conditionally required in Zend Framework's 2 InputFilter) are either outdated or not accurate. For example if I try to make the field "year" optional, for payloads
{
"age": 18
}
and
{}
it's getting skipped because of this code in \Zend\InputFilter\BaseInputFilter::validateInputs
// If input is optional (not required), and value is not set, then ignore.
if (! array_key_exists($name, $data)
&& ! $input->isRequired()
) {
continue;
}
If I make it required, I'm hitting condition in \Zend\InputFilter\Input::isValid
if (! $hasValue && $required) {
if ($this->errorMessage === null) {
$this->errorMessage = $this->prepareRequiredValidationFailureMessage();
}
return false;
}
I'm hesitant to override the BaseInputFilter or Input classes, but from what I can see right now that seems like my only option. However maybe I'm missing something. I'll appreciate any advice, thanks!
I believe what you need is a custom validator.
You can do something like.
class AgeYearValidator extends Zend\Validator\AbstractValidator
{
const AGE = 'age';
const YEAR = 'year';
const EMPTY = 'empty';
protected $messageTemplates = array(
self::AGE => "Age is invalid. It must be between 1 to 110.",
self::YEAR => "Year is invalid. It must between 1900 to 2050.",
self::EMPTY => "Age and Year input fields are both empty."
);
public function isValid($value, $context = null)
{
$isValid = true;
$year = null;
$age = null;
if(isset($context['year'])){
$year = (int)$context['year'];
}
if(isset($context['age'])){
$age = (int)$context['age'];
}
if(is_null($year) && is_null($age)) {
$this->error(self::EMPTY);
$isValid = false;
} else {
$isAgeValid = false;
if($age > 0 && $age < 110) {
$isAgeValid = true;
}
$isYearValid = false;
if($year > 1900 && $year < 2050) {
$isYearValid = true;
}
if($isAgeValid || $isYearValid) {
$isValid = true;
} else if (!$isAgeValid) {
$this->error(self::AGE);
$isValid = false;
} else if (!isYearValid) {
$this->error(self::YEAR);
$isValid = false;
}
}
return $isValid;
}
}
I have used something similar before and it works nicely. The code itself is self-explanatory. You can find further info on Zend Validators. I can see they have some missing info on zend doco which I have added in my code for it to work.