使用Zend Framework验证多个可选表单字段

时间:2021-07-15 11:10:19

I am trying to validate Zend_Form which has several optional fields and I want at least one of them to be filled in. In my case I have mobile, home and office phone numbers and I want at least one of them to be provided.

我正在尝试验证Zend_Form,它有几个可选字段,我想要至少填写其中一个。在我的情况下,我有手机,家庭和办公室电话号码,我希望至少提供其中一个。

I am trying to achieve this though Validation Context (as suggested here) by creating custom validator which extends Zend_Validate_Abstract. The problem is that if all optional fields are empty they are missing from the form $context (passed to the validator class) and this way not validated at all. So if you fill any or several of the three options (mobile, home, work) they are all going to be validated (which is fine, but for this no custom validator is needed), but if you fill none of them, there is no option to force the customer to fill at least one of the fields (which is my aim).

我试图通过创建扩展Zend_Validate_Abstract的自定义验证器来实现验证上下文(如此处所建议的)。问题是,如果所有可选字段都为空,则表单$ context(传递给验证程序类)中缺少这些字段,并且这种方式根本没有验证。因此,如果您填写三个选项中的任何一个或几个(移动,家庭,工作),他们都将被验证(这很好,但为此不需要自定义验证器),但如果您没有填写它们,那么没有选择强迫客户填写至少一个字段(这是我的目标)。

Here is what I have:

这是我有的:

1. my form

<?php

class Application_Form_Application extends Zend_Form {

  public function init() {
    $this->setName('application');

    // attach sub forms to main form
    $this->addSubForms(array(
      'application' => $this->application(),
      ...
    ));
  }

  private function application() {
    $application = new Zend_Form_SubForm();
    // custom phone validation
    $phone_validation = array('phone_mobile' => 'Mobile', 'phone_home' => 'Home', 'phone_work' => 'Work');
    // phone mobile
    $app['phone_mobile'] = new Zend_Form_Element_Text('phone_mobile');
    $app['phone_mobile']->setLabel('Mobile')
                        ->addFilter('StripTags')
                        ->addFilter('StringTrim')
                        ->addValidator('Regex', false, array('/^[0-9]{8}$/i'))
                        ->addValidator(new Application_Form_PhoneMobileHomeWork($phone_validation), false);
    // phone home
    $app['phone_home'] = new Zend_Form_Element_Text('phone_home');
    $app['phone_home']->setLabel('Home')
                      ->addFilter('StripTags')
                      ->addFilter('StringTrim')
                      ->addValidator('Regex', false, array('/^[0-9]{8}$/i'))
                      ->addValidator(new Application_Form_PhoneMobileHomeWork($phone_validation), false);
    // phone work
    $app['phone_work'] = new Zend_Form_Element_Text('phone_work');
    $app['phone_work']->setLabel('Work')
                      ->addFilter('StripTags')
                      ->addFilter('StringTrim')
                      ->addValidator('Regex', false, array('/^[0-9]{8}$/i'))
                      ->addValidator(new Application_Form_PhoneMobileHomeWork($phone_validation), false);
    $application->AddElements($app);
  }

}
?>

2. custom validator

<?php

class Application_Form_PhoneMobileHomeWork extends Zend_Validate_Abstract {

  const NOT_PRESENT = 'notPresent';

  protected $_messageTemplates = array(
    self::NOT_PRESENT => 'At least one contact phone shall be provided!'
  );

  protected $_listOfFields;

  public function __construct(array $listOfFields) {
    $this->_listOfFields = $listOfFields;
    var_dump($listOfFields);exit;
  }

  public function isValid($value, $context = null) {
    var_dump($context);exit;
    ...
  }
?>

The validator always passes though the first dump ($listOfFields), but if I remove it, isValid() is never called unless some data is typed into some of the phone fields (which we want to prevent).

验证器总是通过第一个转储($ listOfFields),但是如果我将其删除,则永远不会调用isValid(),除非在某些电话字段(我们想要阻止)中键入一些数据。

When I checked further I found a solution in extending the Zend_Validate class by passing empty fields to the $context parameter, but I would like to have a better solution if someone knows any.

当我进一步检查时,我找到了一个通过将空字段传递给$ context参数来扩展Zend_Validate类的解决方案,但是如果有人知道,我希望有更好的解决方案。

Concluding it in short - how to validate certain form, forcing the user to fill at least one out of several optional fields?

简而言之 - 如何验证某些表单,强制用户填写几个可选字段中的至少一个?

2 个解决方案

#1


1  

If I understand you right, you want your form elements to not be required, but prevent them to be empty (except if one of them is not empty) using a custom validator? Then, in order to not skip the validation chain, you need to prevent them to be empty calling the method setAllowEmpty(false) in each of your elements.

如果我理解正确,您希望不需要表单元素,但是使用自定义验证器阻止它们为空(除非其中一个不为空)?然后,为了不跳过验证链,您需要在每个元素中调用方法setAllowEmpty(false)来阻止它们为空。

Finally, in your custom validator, you will have something like this:

最后,在您的自定义验证器中,您将得到以下内容:

foreach ($this->_listOfFields as $field) {
    if (isset($context[$field]) AND $context[$field])
    {
        return true;
    }
}

Also, make sure your elements are not required (setRequired(false)).

另外,请确保您的元素不是必需的(setRequired(false))。

#2


0  

The problem is that if any field is filled, the multi_checkbox element doesn't exists in the form, and then it won't be validated.

问题是如果填写任何字段,表单中不存在multi_checkbox元素,那么它将不会被验证。

One solution is the follow: Use a hidden option always checked and validate that this always is checked this more one of the others.

一个解决方案如下:使用始终检查的隐藏选项,并验证是否始终检查此更多其他选项。

#1


1  

If I understand you right, you want your form elements to not be required, but prevent them to be empty (except if one of them is not empty) using a custom validator? Then, in order to not skip the validation chain, you need to prevent them to be empty calling the method setAllowEmpty(false) in each of your elements.

如果我理解正确,您希望不需要表单元素,但是使用自定义验证器阻止它们为空(除非其中一个不为空)?然后,为了不跳过验证链,您需要在每个元素中调用方法setAllowEmpty(false)来阻止它们为空。

Finally, in your custom validator, you will have something like this:

最后,在您的自定义验证器中,您将得到以下内容:

foreach ($this->_listOfFields as $field) {
    if (isset($context[$field]) AND $context[$field])
    {
        return true;
    }
}

Also, make sure your elements are not required (setRequired(false)).

另外,请确保您的元素不是必需的(setRequired(false))。

#2


0  

The problem is that if any field is filled, the multi_checkbox element doesn't exists in the form, and then it won't be validated.

问题是如果填写任何字段,表单中不存在multi_checkbox元素,那么它将不会被验证。

One solution is the follow: Use a hidden option always checked and validate that this always is checked this more one of the others.

一个解决方案如下:使用始终检查的隐藏选项,并验证是否始终检查此更多其他选项。