I've created a new form element class for a special, complex purpose (text input field with an add-on button to open a "search wizard" popup).
To render this element properly, I've also created a form view helper. Everything works and is fine so far.
However, if I try to render the form using the FormCollection view helper, the element is rendered as a basic input element. That's because the FormElement view helper, which the FormCollection helper relies on, uses a hard-coded series of if clauses to map the element's type to a specific form view helper. It can't map my element's class and thus falls back to FormInput
.
I.e. (taken from Zend/Form/View/Helper/FormElement.php, line 41-49):
if ($element instanceof Element\Button) {
$helper = $renderer->plugin('form_button');
return $helper($element);
}
if ($element instanceof Element\Captcha) {
$helper = $renderer->plugin('form_captcha');
return $helper($element);
}
...
$helper = $renderer->plugin('form_input');
return $helper($element);
and so on.
I've got a little stuck here because this architecture doesn't really promote extensibility.
The only solution that came to my mind (except rendering the form by hand) is to extend the FormElement view helper class and thus create my own CustomFormElement view helper. However, because of its complexity, I've put the custom element into an own module. So I'd have to write this CustomFormElement helper dynamically to add custom elements from any module. I don't think this is a recommended procedure.
Is there another solution or is maybe even my complete approach unrecommended? Thanks in advance!
Seems like we're both running into Form issues with Zend. I think that it could be better integrated with the whole MVC structure.
I think that your approach is sound. What I might think of doing is the following
You could re-use the ViewHelperProviderInterface
or create your own interface:
class CustomElement implements ViewHelperProviderInterface
{
public function getViewHelperConfig()
{
return array('type' => '\My\View\Helper');
}
}
or
class CustomElement implements FormHelperProviderInterface
{
public function getFormHelperConfig()
{
return '\My\View\Helper';
// or
return new My\View\Helper();
}
}
Then in your FormElement
class you can do the following:
if ('week' == $type) {
$helper = $renderer->plugin('form_week');
return $helper($element);
}
if ($element instanceof THEINTERFACE) {
return $renderer->plugin($element->getFormHelperConfig());
}
$helper = $renderer->plugin('form_input');
return $helper($element);
This is probably what you had in mind anyway.
You'd probably be better off creating your own interface since the first one already has some sort of meaning behind it and it might confuse someone.
Aside from that, each module would then ONLY have to provide a helper_map
key in the module configuration to have it's view helpers available during rendering with the MVC components.