我有一个基本用户表单,我为每个用例子类化,即注册,编辑等。
某些表单元素对于所有用例都是通用的,对于这些,我使用表单作为元素工厂,例如$ this-> addElement('text','first_name',array(...))。这很好。
对于仅在某些用例中需要的元素,我在基本表单类中创建它们,但不添加它们,例如$ this-> createElement('text','id',array(...))。当我到达子类本身时,那就是我实际添加这些可选元素的时候。
现在,我认为在子类中我可以使用以下任一方式添加元素:
$this->addElement($this->getElement('id'));
或者
$this->addElement($this->id);
但事实并非如此。我得到一个例外,说我正在尝试addElement(NULL)。
我能获得所需结果的唯一方法是专门将create元素分配给成员变量,然后再使用该变量名。
e.g。在基本形式:
$this->id = $this->createElement('text', 'id', array(...));
然后在子类中:
$this->addElement($this->id);
在我看来,这应该产生一个变量名称冲突。如果createElement没有命名我的元素'id',那么命名它是什么?
修改
我在父类和子类中使用init()方法,并且子节点的init()调用父init()作为其第一个任务。
答案 0 :(得分:4)
一切都按预期工作。没有名称冲突因为当你使用$ this-> createElement()时,你创建的元素实际上并没有保留在任何地方。使用此方法,您必须将元素显式保留在某个变量中(如成员变量),然后使用$ this-> addElement()将其添加到表单元素集中。
如果您查看Zend_Form源代码,您会注意到:
1-调用createElement()时,会创建元素并立即返回;换句话说,元素不是内部保留在任何地方,所以你必须自己保留它并将其添加到后者:
public function createElement($type, $name, $options = null)
{
...
$element = new $class($name, $options);
return $element;
}
2-调用addElement()时,该元素随后会添加到表单中,并在内部保存在名为_elements的受保护成员数组中。这与做同样的事情:
$this->id = $this->createElement('text', 'id', array(...));
神奇地调用addElement()(由用户user594791在他的评论中指出)。你也可以直接把元素放在_elements数组中,但我建议不要这样做,因为addElement()做了一些进一步的处理。没有名称冲突,因为你做了两次相同的动作(正如Marcin在另一个答案中指出的那样),并且在第二次你用自己覆盖了元素。
最后,我还建议不要实例化你不会使用的元素(浪费资源而不是很好的编程习惯)。最好为父类中可能必需的元素保留一个关联的配置数组;然后,在您的子类中,您只使用预先存储在父类中的相应配置数组来实例化您真正需要的元素。一个例子:
class ParentForm extends Zend_Form {
...
protected $_elementConfig;
...
public function init() {
...
// Add element configuration, but don't instantiate element right now
$this->_elementConfig = array();
// Element 1, a text input
$this->elementConfig['myTextInput'] = array(
'Text',
array(
'label' => 'Theme',
'description' => 'Main application theme',
'maxLength' => 128,
'validators' => array(
array('StringLength', false, array('max' => 128))
),
'filters' => array(
array('HtmlEntities')
)
)
);
// Element 2, a submit button
$this->elementConfig['mySubmitButton'] = array(
'Submit',
array(
'label' => 'Save'
)
);
// Element 3, something else
...
}
...
}
class ChildForm extends ParentForm {
public function init() {
parent::__construct(); // Parent init() is called by the parent constructor
...
// Will use the submit button
$this->addElement(
$this->_elementConfig['mySubmitButton'][0], // Type of element
'mySubmitButton', // Name of element
$this->_elementConfig['mySubmitButton'][1] // Config of element
);
}
}
如果您有很多元素,并且不希望非常污染父init()方法,我建议您将完整的元素定义放在外部文件中,该文件可以是返回PHP数组的PHP文件。完整配置,XML文件,INI文件或Zend_Config支持的任何其他格式(您可以在没有实际PHP代码的情况下定义元素 - here - 在页面底部 - 是一个定义的示例带有INI文件的元素。)
答案 1 :(得分:3)
createElement
不会向表单添加元素,只是创建它。除非您将其添加到表单中,否则表单将不会知道它。这就是为什么$this->id
和
$this->getElement('id')
在您的第一个示例中不起作用。
在第二个示例中,您首先将新创建的元素添加到表单(即$this->id = $this->createElement('text', 'id', array(...));
),然后您似乎再次添加它(即$this->addElement($this->id);
)。我相信不会有任何名字冲突,因为Zend_Form会重新分配它。因此,我认为$this->addElement($this->id);
实际上并不需要。
希望这有帮助。
答案 2 :(得分:0)
假设您正在使用Zend_Form :: init()而不在子类中调用parent :: init(),则可能会覆盖父类的方法。这意味着您的所有基本元素都不会添加到子类表单中。如果将parent :: init()添加到子类的init()中,它将继承子元素表单的父元素。然后,您可以根据需要添加和删除子类。
public function init()
{
parent::init();
/** Additional code here **/
}