2011-07-05 33 views
5

我有我继承为每个用例基本用户的形式,即注册,编辑等如何使用Zend_Form->的createElement()

一些表单元素共同所有的用例,并为这些我使用表单作为元素工厂,例如$ this-> addElement('text','first_name',array(...))。这工作正常。

对于仅在某些用例中需要的元素,我在基本窗体类中创建它们,但不添加它们,例如, $ this-> createElement('text','id',array(...))。当我到达子类本身时,那就是当我实际添加这些可选元素时。现在

,我认为在子类中,我将能够简单地添加使用两种元素:

$this->addElement($this->getElement('id')); 

或者

$this->addElement($this->id); 

但事实并非如此。我收到一个异常,说我想添加元素(NULL)。

我可以得到想要的结果的唯一方法是将create元素专门分配给成员变量,然后再使用该变量名称。

例如在基本形式:

$this->id = $this->createElement('text', 'id', array(...)); 

然后在子类:

$this->addElement($this->id); 

在我看来,这应该产生一个变量名冲突。如果createElement没有命名我的元素'id',它是什么命名的?

编辑

我使用init()在两家母公司和子类,和孩子的init()的方法调用父的init()作为其首要任务。

回答

3

createElement不向表单添加元素,只是创建它。除非你将它添加到你的表单中,否则表单将不会知道它。这就是为什么$this->id
$this->getElement('id')不能在你的第一个例子中工作。

在第二个示例中,首先将新创建的元素添加到表单中(即$this->id = $this->createElement('text', 'id', array(...));),然后看起来您正在再次添加它(即$this->addElement($this->id);)。我相信不会有任何名字冲突,因为Zend_Form只会重新分配它。因此我认为$this->addElement($this->id);实际上并不需要。

希望这会有所帮助。

+0

感谢Marcin,您是对的 - 第二项任务不是必需的。当我回头看看当天早些时候的子表单时,他们也有可选的元素。 –

0

假设你正在使用Zend_Form :: init()而不是在子类中调用parent :: init(),你可能会重写父类的方法。这意味着您的基本元素都不会添加到子类窗体中。如果将parent :: init()添加到子类的init()中,它将继承父元素到子类窗体。然后,您可以根据需要为子类添加和删除元素。

public function init() 
{ 
    parent::init(); 
    /** Additional code here **/ 
} 
+0

谢谢user828841。我按照建议使用init()。应该在我原来的问题中指出这一点。现在已经更新了这个问题... –

+0

如果你调用了parent :: init(),你不需要使用$ this-> addElement($ this-> getElement('id')); $ this-> getElement('id)意味着元素已经添加到表单中,因此您不需要冗余 –

3

一切都按预期工作。没有名称冲突,因为当您使用$ 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文件定义元素的示例)。

+0

我认为赋值给'$ this-> id'将执行__set方法,该方法将执行addElement方法来添加元素。 – user594791

+0

你是绝对正确的,我会纠正我的答案。我有时会忘记这些恶魔般的PHP巫师;) – faken

+0

嗨Faken,谢谢你的出色答案。我将这些分数授予Marcin,因为他更准确,但是您的答案有一些很好的信息 - 是的,我只想在父表单中配置元素配置方法的更多细节... –