0

在我的Form我有一个Fieldset, 包含两个元素foobar. 他们的业务规则是,必须设置一个。因此,字段集在设置fooOR时有效,在bar未设置时无效。

我解决了这个问题:

public function getInputFilterSpecification()
{
    return [
        'foo' => [
            'required' => empty($this->get('bar')->getValue())
        ],
        'bar' => [
            'required' => empty($this->get('foo')->getValue())
        ],
    ];
}

在职的。但是错误消息仍然存在问题:如果机器人字段为空,则用户会为每个字段获取消息“值是必需的并且不能为空”。用户认为,他必须填写这两个字段。

如何自定义required字段的错误消息,以显示正确的消息,例如“需要 foo 的值并且不能为空,如果 bar 未设置。” 和“如果未设置 foo,则 bar 的值是必需的并且不能为空。” ?

4

2 回答 2

0

您可以通过扩展默认链来编写自定义验证器链

然后,您可以覆盖此方法:

/**
 * 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,但它也可以访问上下文 - 这意味着您也可以获取所有其他字段值。

修改逻辑以检查任何一个验证器是否为真返回真很简单。

然后,您只需附加您想要成为“其中一个必填项”的所有字段

于 2016-11-07T10:35:20.617 回答
-1

您可能最终会得到这样的自定义验证器:

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 中或在您的 Module.php 中使用public function getValidatorConfig()。不要同时使用两者,它是一个或另一个:

如何在你的 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)当您调用时,表单中的上下文是 formData $form->setData($this->getRequest()->getPost())

于 2016-11-14T14:42:38.477 回答