关于 php:Zend_Form 任意数量的键值对字段

Zend_Form arbitrary number of key-value pair fields

我正在尝试使用 Zend_Form(Zend_Framework 组件)创建一个表单。用户应该能够添加任意数量的字段。就像您可以使用 gmail GUI 上传文件一样。
示例:

1
[_____] [+]

点击[ ]按钮后:

1
2
[_____]
[_____] [+]

为了让事情变得复杂,我想添加字段对,所以它看起来像这样:

1
2
[_____] [_____]
[_____] [_____] [+]

在实现此功能时,如何保持简单的内置验证和分配方法的可用性?我需要一个子表单吗?我需要别的东西吗?提交表单后,代码应该可以将字段映射到数组中。

恐怕我必须继承 Zend_Form 或 SubForm,但我想知道最简单/最漂亮的方法。


这里最简单的方法是使用一个简单的自定义 Zend Validator,它将解析输入元素作为整个数组 PHP 看到的那样,因此您可以自动执行以下操作。

  • 独立验证每个输入元素并显示与每个元素关联的错误消息。
  • 返回一个可解析的数组以重建刚刚提交的表单。
  • 对于 Zend_Validator

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    class Validate_InputArray extends Zend_Validate_Abstract
    {
     const INVALID = 'invalid';
     const ERROR   = 'error';

     /**
      * Failed array elements used to regenerate same elements
      * on next form build
      *
      */

     protected $_elements = array();

        protected $_messageTemplates = array(
            self::INVALID =>"Could not locate post element %value%",
      self::ERROR   =>"YOUR ERROR MESSAGE|%value% is required"
        );

        public function __construct()
        {}

        public function isValid($element)
        {
            if (!$_POST[$element]) {
       $this->_error(self::INVALID);
       return false;
      }

      $elements = array();

      if (is_array($_POST[$element])) {

       $fail = false;

       foreach ($_POST[$element] as $k => $v) {
        if (!$this->_validateElement($v)) {
         $this->_error(self::ERROR);
         $elements[$k] = self::ERROR;
        }
       }

       $this->_setElements($elements);

       if ($fail) {
        return false;
       }

      } else {
       if (!$this->_validateElement($_POST[$element])) {

        $this->_error(self::ERROR);
        $elements[0] = self::ERROR;

        $this->_setElements($elements);

        return false;
       }
      }
        }

     protected function _setElements($elements)
     {
      $this->_elements = $elements;
      return $this;
     }

     public function getElements()
     {
      return $this->_elements;
     }

     private function _validateElement($value)
     {
      // do your validation here
      // return true/false
     }
    }

    现在代码使用它来解析一个可能的数组作为一个值的输入,并验证每个元素并重新生成提交的确切表单,具有相同的任意字段。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    $fail = false;

    if ($this->getRequest()->isPost()) {

     require 'Validate_InputArray.php';

     $validator = new Validate_InputArray();
     $elements  = array();

     if (!$validator->isValid($validator)) {

      $fail = true;

      foreach ($validator->getElements() as $k => $v) {
       $elements[$k] = $v;
      }
     }
    }

    if ($fail) {

     $messages = $validator->getMessages();

     foreach ($elements as $k => $v) {
      // Add custom methods here
      $element = $form->createElement('text', 'elementName[]');
            $element->addErrorMessages($messages[$k]);
     }

    } else {
     $form->addElement('elementName[]');
    }

    这将允许您根据需要验证任意数量的任意输入元素,而无需子表单,或者担心在任意元素验证失败并需要重新构建时需要重新添加表单元素在客户端。


    这是我自己的解决方案:
    我创建了两个隐藏字段,一个用于键,一个用于值。一段 javascript 代码在 deamand 和 onChange 上创建假字段对,它使用 JSON 将所有假字段映射到隐藏字段。
    在服务器端很容易处理,但是使用的javascript技术不是离散的。


    这里是如何添加十个输入字段,每个字段都有 Alpha 验证:

    1
    2
    3
    4
    5
    6
    7
    8
    $sub_test = new Zend_Form_SubForm();
    $num_fields = 10;
    for ( $i = 0; $i < $num_fields; $i++ ) {
      $element = $form->createElement('text', strval($i));
      $element->addValidator('Alpha'); // just to see in action
      $sub_test->addElement($element);
    }
    $form->addSubForm($sub_test, 'test'); // values mapped to $_POST['test'][0..9]

    要确定要创建/显示多少,当然,您需要做更多的工作,但这似乎很简单。

  • 查看 $_POST[\\'test\\'] 以查看填充了多少值 - 始终包括这些值。
  • 查看另一个隐藏变量以了解要显示的总字段数——即使是那些为空的字段。
  • 等等。