我为一个特殊的,复杂的目的创建了一个新的表单元素类(带有附加按钮的文本输入字段,用于打开“搜索向导”弹出窗口)。
为了正确渲染这个元素,我还创建了一个表单视图助手。到目前为止,一切正常并且很好。
但是,如果我尝试使用FormCollection视图助手渲染表单,则该元素将呈现为基本输入元素。这是因为FormCollection助手依赖的FormElement视图助手使用硬编码的if子句系列将元素的类型映射到特定的表单视图助手。它无法映射我的元素类,因此可以回退到FormInput
。
即。 (取自Zend / Form / View / Helper / FormElement.php,第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);
等等。
我有点卡在这里,因为这种架构并没有真正提升可扩展性。
我想到的唯一解决方案(除了手工渲染表单)是扩展FormElement视图助手类,从而创建我自己的CustomFormElement视图助手。但是,由于其复杂性,我将自定义元素放入自己的模块中。所以我必须动态编写这个CustomFormElement助手来添加来自任何模块的自定义元素。我不认为这是推荐的程序。
是否有其他解决方案,或者甚至是我的完整方法未经推荐?提前谢谢!
答案 0 :(得分:7)
我认为最简单的方法是扩展Zend\Form\View\Helper\FormElement
,在render()
方法中处理字段类型,并将FormElement注册为应用程序/模块的默认FormElement。假设您有自己想要呈现的自定义TestField:
namespace Application\Form\View\Helper;
use \Zend\Form\ElementInterface;
use \Zend\Form\View\Helper\FormElement
use \Application\Form\Element\TestField;
class MyFormElement extends FormElement
{
public function render(ElementInterface $element)
{
$renderer = $this->getView();
if (!method_exists($renderer, 'plugin')) {
// Bail early if renderer is not pluggable
return '';
}
//your custom fields go here...
if ($element instanceof TestField) {
$helper = $renderer->plugin('\Application\Form\View\Helper\FormTestField');
return $helper($element);
}
return parent::render($element);
}
}
在Application / config / module.config.php中:
'view_helpers' => array(
'invokables' => array(
'form_element' => 'Application\Form\View\Helper\MyFormElement',
)
)
答案 1 :(得分:3)
尽可能地使用FormElement
视图帮助程序,addType
覆盖使用的视图帮助程序。即在视图中,就在呈现表单之前:
<?php $this->plugin('FormElement')->addType('text', 'formcustom'); ?>
这将使用您的视图助手按键名覆盖FormRow
,FormCollection
助手中使用的视图助手:
在您的配置中
'view_helpers' => array(
'invokables' => array(
'formcustom' => 'Application\Form\View\Helper\FormCustom',
)
),
当问到这个问题时,方法可能不存在。但现在是。
答案 2 :(得分:3)
以下是我所做的事情,感觉就像保持事物分离和整洁的正确程度一样。
假设:
以下是如何通过将以下内容添加到module.config.php来注册用于呈现元素的视图助手:
'view_helpers' => array(
'invokables'=> array(
'formMyElement' => 'MyModule\Form\View\Helper\FormMyElement',
),
'factories' => array(
'formElement' => function($sm) {
$helper = new \Zend\Form\View\Helper\FormElement();
$helper->addClass('MyModule\Form\MyElement', 'formMyElement');
return $helper;
}
),
),
关键是你为FormElement提供了一个新的工厂方法,它仍然创建相同的标准类(不需要覆盖它),但也调用addClass方法将自定义助手注册为自定义的正确帮助器元件。如果您不想为助手创建短名称,可以删除invokables部分并将FQCN放入addClass调用中,但我喜欢使用短名称。
这是我迄今为止发现的最佳方法。理想情况下,您不必接管FormElement的构造,只需修改传递给它的配置即可。这种方法的缺点是,如果你有多个定义自定义表单元素的模块,如果它们都试图重新定义FormElement工厂,它们将发生冲突。您不能以这种方式在多个模块中指定添加项。因此,如果有人发现可以设置的更好的配置,只是简单地传递给FormElement :: addClass()方法,请告诉我。
顺便说一句,我发现这个页面并没有解决方程式的助手方面,而是讨论了注册新的表单元素类以及如何覆盖内置类:http://framework.zend.com/manual/current/en/modules/zend.form.advanced-use-of-forms.html答案 3 :(得分:2)
----自定义表单元素-----
namespace App\Form\View\Helper;
use Zend\Form\View\Helper\FormElement as ZendFormElement;
/**
* Description of FormElement
*/
class FormElement
extends ZendFormElement
{
public function addTypes(array $types)
{
foreach ($types as $type => $plugin) {
$this->addType($type, $plugin);
}
}
}
---- application module.config.php --------------
//..........
'view_helpers' => array(
'invokables' => array(
'formRTE' => 'App\Form\View\Helper\FormRTE',
),
'factories' => array(
'formElement' => function($sm) {
$helper = new App\Form\View\Helper\FormElement();
$helper->addTypes(array(
'rte' => 'formRTE',
));
return $helper;
}
),
),
//.........
答案 4 :(得分:0)
好像我们都遇到了Zend的Form问题。我认为它可以更好地与整个MVC结构集成。
我认为你的方法很合理。我可能想到的是以下
您可以重复使用ViewHelperProviderInterface
或创建自己的界面:
class CustomElement implements ViewHelperProviderInterface
{
public function getViewHelperConfig()
{
return array('type' => '\My\View\Helper');
}
}
或
class CustomElement implements FormHelperProviderInterface
{
public function getFormHelperConfig()
{
return '\My\View\Helper';
// or
return new My\View\Helper();
}
}
然后在FormElement
课程中,您可以执行以下操作:
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);
这可能是你想到的。
你可能最好创建自己的界面,因为第一个界面已经有了某种意义,它可能会使某些人感到困惑。
除此之外,每个模块只需要在模块配置中提供helper_map
密钥,以便在使用MVC组件进行渲染时使用它的视图助手。