Php Zend_形式任意数量的键值对字段

Php Zend_形式任意数量的键值对字段,php,zend-framework,zend-form,Php,Zend Framework,Zend Form,我正在尝试使用Zend_表单(Zend_框架组件)创建一个表单。用户应该能够添加任意数量的字段。就像你可以用gmail GUI上传文件一样。 例如: 单击[+]按钮后: [_____] [_____] [+] 为了让事情变得复杂,我想添加字段对,所以它看起来像这样: [_____] [_____] [_____] [_____] [+] 在实现此功能时,如何保持易用内置验证和分配方法的可用性?我需要一个子表单吗?我还需要别的吗?提交表单后,代码应该能够将字段映射到和数组中 恐怕我必须对Zen

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

单击[+]按钮后:

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

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


恐怕我必须对Zend_表单或子表单进行子类化,但我想知道最简单/最漂亮的方法。

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

$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]
$sub_test=new Zend_Form_SubForm();
$num_字段=10;
对于($i=0;$i<$num_字段;$i++){
$element=$form->createElement('text',strval($i));
$element->addValidator('Alpha');//只需查看操作
$sub_test->addElement($element);
}
$form->addSubForm($sub_test,'test');//映射到$\u POST['test'][0..9]的值
当然,要确定要创建/显示多少,您需要做更多的工作,但这似乎很简单

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

  • 下面是如何添加十个输入字段,每个字段都有
    Alpha
    验证:

    $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]
    
    $sub_test=new Zend_Form_SubForm();
    $num_字段=10;
    对于($i=0;$i<$num_字段;$i++){
    $element=$form->createElement('text',strval($i));
    $element->addValidator('Alpha');//只需查看操作
    $sub_test->addElement($element);
    }
    $form->addSubForm($sub_test,'test');//映射到$\u POST['test'][0..9]的值
    
    当然,要确定要创建/显示多少,您需要做更多的工作,但这似乎很简单

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

  • 这里最简单的方法是使用一个简单的自定义Zend验证器,当整个数组PHP看到它时,它将解析输入元素,这样您就能够自动执行以下操作

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

    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
     }
    }
    
    现在,代码使用它来解析一个可能的数组作为值的输入,验证每个元素并重新生成提交的精确表单,以及相同的任意字段

    $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[]');
    }
    

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

    这里最简单的方法是使用一个简单的自定义Zend验证器,它将在整个数组PHP看到输入元素时解析输入元素,以便您能够自动执行以下操作

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

    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
     }
    }
    
    现在,代码使用它来解析一个可能的数组作为值的输入,验证每个元素并重新生成提交的精确表单,以及相同的任意字段

    $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上创建假字段对,一旦更改,它就会使用JSON将所有假字段映射到隐藏字段中。 在服务器端很容易处理,但所使用的javascript技术不是离散的。

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

    感谢您的详细回答,我将在几天内尝试它。没问题,让我知道它是如何运行的;)谢谢你的长篇大论,过几天我就要试试。没问题,让我知道它是怎么回事;)