【问题标题】:How to use Zend_Form->createElement()如何使用 Zend_Form->createElement()
【发布时间】:2011-09-28 11:01:09
【问题描述】:

我有一个基本用户表单,我为每个用例子类化,即注册、编辑等。

一些表单元素对所有用例都是通用的,为此我将表单用作元素工厂,例如$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()作为它的第一个任务。

【问题讨论】:

    标签: zend-framework zend-form


    【解决方案1】:

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

    【讨论】:

    • 我认为分配给$this->id 将执行 __set 方法,该方法又将执行 addElement 方法来添加元素。
    • 你说的完全正确,我会更正我的答案。我有时会忘记这些可怕的 PHP 魔法;)
    • 您好 Faken,感谢您的出色回答。我将积分授予 Marcin,因为他更准确,但是您的答案有一些很好的信息 - 是的,我将不胜感激您仅在父表单中的元素配置方法的详细信息......
    • 感谢 Faken,太棒了。
    【解决方案2】:

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

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

    希望这会有所帮助。

    【讨论】:

    • 谢谢 Marcin,你是对的 - 第二个作业不是必需的。当我回去查看当天早些时候的子表单时,它们也有可选元素。
    【解决方案3】:

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

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

    【讨论】:

    • 感谢 user828841。我按照建议使用 init() 。应该在我原来的问题中指出这一点。现在已经更新了问题...
    • 如果你调用 parent::init() 你不需要使用 $this->addElement($this->getElement('id')); $this->getElement('id) 表示该元素已添加到表单中,因此您不需要冗余
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-13
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-09
    相关资源
    最近更新 更多