Issues

ZF-12021: Custom decorators in Zend_Form_Element constructor produces "Plugin by name 'Mylabel' was not found in the registry; used paths: Zend_Form_Decorator_: Zend/Form/Decorator/ " error

Description


class Application_Form_MyForm extends Zend_Form
{
    public function init()
    {
        $this->addElementPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');
        $element = new Zend_Form_Element_Text('email', array(
            'label' => 'Email',
            'decorators' => array(
                'ViewHelper',
                'Mylabel',
            ),
        ));
        $this->addElement($element);
    }
}

fails with the following error: {{Plugin by name 'Mylabel' was not found in the registry; used paths: Zend_Form_Decorator_: Zend/Form/Decorator/}}

The following does work:


class Application_Form_MyForm extends Zend_Form
{
    public function init()
    {
        $this->addElementPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');
        $element = new Zend_Form_Element_Text('email', array(
            'label' => 'Email',
            'decorators' => array(
                'ViewHelper',
            ),
        ));
        $element->addDecorator('Mylabel');
        $this->addElement($element);
    }
}

It is not obvious from http://framework.zend.com/manual/en/… that the first example is not supported.

We should either fix the code to support this usage, or spell out in the documentation that custom decorators are not supported in Zend_Form_Element constructors.

Comments

This is untrue.

You can pass a key "prefixPath" with an array of prefix paths to be added, which if you use the notation given in your issue, you would have to pass to every element rather than the form.

I'm closing this as not an issue, though you may want to consider opening a documentation issue to clear this up.

Why should it work? You configured form, but then created separate element. How configuration from one object should appear in unrelated other?

Your second example works only because your decorator lazy loaded on access. And that access occurs after element added to form, where decorator prefixes are injected into element instance.

You must either provide decorator prefixes to element constructor or create it from form instance, see Zend_Form::addElement() and Zend_From::createElement()

Ryan,

Thanks for your prompt response.

You are correct, the following code works:


class Application_Form_MyForm extends Zend_Form
{
    public function init()
    {
        $element = new Zend_Form_Element_Text('email', array(
            'label' => 'Email',
            'prefixPath' => array(
                'decorator' => array(
                    'prefix'    => 'My_Decorator', 
                    'path'      => 'My/Decorator/', 
                 ),
             ),
            'decorators' => array(
                'ViewHelper',
                'Mylabel',
            ),
        ));
        $this->addElement($element);
    }
}

Aleksey 'Xerkus' Khudyakov states:

Why should it work? You configured form, but then created separate element. How configuration from one object should appear in unrelated other?

I think it's reasonable to assume that by calling


$this->addElementPrefixPath('My_Decorator', 'My/Decorator/', 'decorator');

that this would apply to all future calls to {{addElement()}}, regardless of how the object was created that was passed to it.

It is not obvious (at least to me) that this is not the case.

I've reviewed the documentation, and don't find this requirement mentioned anywhere. Should it be updated?

{quote}that this would apply to all future calls to addElement(), regardless of how the object was created that was passed to it.{quote}

Exactly. But check exception's stack trace: it thrown BEFORE $this->addElement($element); call. It should be something like Element::__construct() -> addDefaultDecorators() -> getDecorators() -> _loadDecorator(). Do not remember exact api.