Как установить пользовательское сообщение об ошибке для обязательного поля формы в 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()),

Другие вопросы по тегам