You probaly end up with a custom validator like this:
class MyCustomValidator extends ZendAbstractValidator
{
const FIELDS_EMPTY = 'fieldsEmpty';
/**
* Error messages
*
* @var array
*/
protected $abstractMessageTemplates = [
self::FIELDS_EMPTY => "Vale for %field1% is required and can't be empty, if %field2% is not set.",
];
/**
* Variables which can be used in the message templates
*
* @var array
*/
protected $abstractMessageVariables = [
'field1' => 'field1',
'field2' => 'field2',
];
/**
* Value of the field
* @var mixed
*/
protected $value;
/**
* Name of the first field to check, which the validator is bind to
* @var mixed
*/
protected $field1;
/**
* Name of the second field to check
* @var string
*/
protected $field2;
/**
* MyCustomValidator constructor.
*
* @param array|null|\Traversable $options
*
* @throws \Exception
*/
public function __construct($options)
{
if ($options instanceof Traversable) {
$options = ArrayUtils::iteratorToArray($options);
}
if (!array_key_exists('field1', $options) || !array_key_exists('field2', $options)) {
throw new \Exception('Options should include both fields to be defined within the form context');
}
$this->field1 = $options['field1'];
$this->field2 = $options['field2'];
parent::__construct($options);
}
/**
* Returns true if and only if $value meets the validation requirements
* If $value fails validation, then this method returns false, and
* getMessages() will return an array of messages that explain why the
* validation failed.
*
* @param mixed $value
* @param array $context
*
* @return bool
*/
public function isValid($value, $context = [])
{
$this->setValue($value);
if (empty($value) && (array_key_exists($this->field2, $context) || empty($context[$this->field2]))) {
$this->error(self::FIELDS_EMPTY);
return false;
}
return true;
}
}
So how to use it:
public function getInputFilterSpecification()
{
return [
'foo' => [
'validators' => [
[
'name' => MyCustomValidator::class,
'options' => [
'field1' => 'foo',
'field2' => 'bar',
]
]
]
],
'bar' => [
'validators' => [
[
'name' => MyCustomValidator::class,
'options' => [
'field1' => 'bar',
'field2' => 'foo',
]
]
]
],
];
}
For those who don't know how to register the MyCustomValidator - in your module.config.php or use the public function getValidatorConfig()
within your Module.php. Don't use both, it's one or the other:
How to register in your module.config.php
'validators' => array(
'factories' => array(
MyCustomValidator::class => MyCustomValidatorFactory::class,
),
),
How to register in your module.php:
/**
* Expected to return \Zend\ServiceManager\Config object or array to
* seed such an object.
* @return array|\Zend\ServiceManager\Config
*/
public function getValidatorConfig()
{
return [
'aliases' => [
'myCustomValidator' => MyCustomValidator::class,
'MyCustomValidator' => MyCustomValidator::class,
'mycustomvalidator' => MyCustomValidator::class,
],
'factories' => [
MyCustomValidator::class => MyCustomValidatorFactory::class,
],
];
}
The Factory class:
class MyCustomValidatorFactory implements FactoryInterface, MutableCreationOptionsInterface
{
/**
* Options for the InputFilter
*
* @var array
*/
protected $options;
/**
* Create InputFilter
*
* @param ServiceLocatorInterface $serviceLocator
*
* @return BlockChangeOnSerialsValidator
*/
public function createService(ServiceLocatorInterface $serviceLocator)
{
return new MyCustomValidator($this->options);
}
/**
* Set creation options
*
* @param array $options
*
* @return void
*/
public function setCreationOptions(array $options)
{
$this->setOptions($options);
}
/**
* Set options
*
* @param array $options
*/
public function setOptions(array $options)
{
$this->options = $options;
}
}
Notice that I kept the validator isValid()
method pretty simple as I'm not sure it was covering your case, but this is to help you push in the right direction. But an improvement that can be made is to reuse the NotEmpty validator to check whether the field is empty or not instead.
Notice that Context witin the isValid($value, $context = null)
form is the formData when you call $form->setData($this->getRequest()->getPost())
.