Как установить пользовательское сообщение об ошибке для обязательного поля формы в Zend Framewor 2?
В моем Form
у меня есть Fieldset
, который содержит два элемента foo
а также bar
, Бизнес-правило для них таково, что нужно установить. Итак, fieldset действителен, когда foo
ИЛИ ЖЕ bar
установлен и недействителен, когда никто не установлен.
Я решил это следующим образом:
public function getInputFilterSpecification()
{
return [
'foo' => [
'required' => empty($this->get('bar')->getValue())
],
'bar' => [
'required' => empty($this->get('foo')->getValue())
],
];
}
За работой. Но есть еще проблема с сообщениями об ошибках: если поля бота пусты, пользователь получает для каждого поля сообщение "Значение является обязательным и не может быть пустым". Пользователь думает тогда, он должен заполнить оба поля.
Как настроить сообщение об ошибке для required
поле, для отображения правильных сообщений типа "Значение для foo является обязательным и не может быть пустым, если панель не установлена". и "Значение для бара обязательно и не может быть пустым, если foo не установлен". ?
2 ответа
Вы можете создать собственную цепочку ValidatorChain, расширив цепочку по умолчанию.
Затем вы можете переопределить этот метод:
/**
* Returns true if and only if $value passes all validations in the chain
*
* Validators are run in the order in which they were added to the chain (FIFO).
*
* @param mixed $value
* @param mixed $context Extra "context" to provide the validator
* @return bool
*/
public function isValid($value, $context = null)
{ .. }
По умолчанию этот метод возвращает значение true, только если ВСЕ валидаторы возвращают значение true, но он также имеет доступ к контексту - это означает, что вы можете получить и все другие значения полей.
Это просто изменить логику, чтобы потом проверить, верен ли какой-либо из валидаторов.
Затем вы просто присоединяете все поля, которые хотите, чтобы они были "одним из обязательных"
Вы, вероятно, в конечном итоге с пользовательским валидатором, как это:
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;
}
}
Так как это использовать:
public function getInputFilterSpecification()
{
return [
'foo' => [
'validators' => [
[
'name' => MyCustomValidator::class,
'options' => [
'field1' => 'foo',
'field2' => 'bar',
]
]
]
],
'bar' => [
'validators' => [
[
'name' => MyCustomValidator::class,
'options' => [
'field1' => 'bar',
'field2' => 'foo',
]
]
]
],
];
}
Для тех, кто не знает, как зарегистрировать MyCustomValidator - в вашем файле module.config.php или используйте public function getValidatorConfig()
в вашем Module.php. Не используйте оба, это одно или другое:
Как зарегистрироваться в вашем module.config.php
'validators' => array(
'factories' => array(
MyCustomValidator::class => MyCustomValidatorFactory::class,
),
),
Как зарегистрироваться в вашем 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,
],
];
}
Фабричный класс:
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;
}
}
Обратите внимание, что я сохранил валидатор isValid()
метод довольно простой, поскольку я не уверен, что он охватывал ваше дело, но это поможет вам двигаться в правильном направлении. Но улучшение, которое можно сделать, - это повторно использовать валидатор NotEmpty, чтобы проверить, является ли поле пустым или нет.
Обратите внимание, что контекст с isValid($value, $context = null)
форма это формаДанные, когда вы звоните $form->setData($this->getRequest()->getPost())
,