3

我为一个特殊的、复杂的目的创建了一个新的表单元素类(带有用于打开“搜索向导”弹出窗口的附加按钮的文本输入字段)。

为了正确渲染这个元素,我还创建了一个表单视图助手。一切正常,到目前为止一切正常。

但是,如果我尝试使用 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 助手来添加来自任何模块的自定义元素。我不认为这是推荐的程序。

是否有另一种解决方案,或者甚至不推荐我的完整方法?提前致谢!

4

5 回答 5

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',
    )
)
于 2012-11-22T08:17:08.153 回答
3

以下是我所做的,感觉是保持事物分开和整洁的正确水平。

鉴于:

  • 一个新元素:MyModule\Form\MyElement,它扩展了 Zend\Form\Element
  • MyElement 的新视图助手类:MyModule\Form\View\Helper\FormMyElement 扩展 Zend\Form\View\Helper\AbstractHelper

以下是通过将以下内容添加到 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 方法将您的自定义帮助程序注册为自定义元素的正确帮助程序。如果您不想为您的助手创建短名称,您可以删除可调用部分并将 FQCN 放在 addClass 调用中,但我喜欢使用短名称。

这是迄今为止我发现的最好的方法。理想情况下,您不必接管 FormElement 的构造,只需修改传递给它的配置。这种方法的缺点是,如果您有多个定义自定义表单元素的模块,如果它们都尝试重新定义 FormElement 工厂,它们将会发生冲突。您不能以这种方式在多个模块中指定添加。因此,如果有人发现可以设置的更好的配置,只需传递给 FormElement::addClass() 方法,请告诉我。

顺便说一句,我发现这个页面没有解决等式的视图助手方面,但讨论了注册新的表单元素类以及如何覆盖内置类: http: //framework.zend.com/manual/当前/en/modules/zend.form.advanced-use-of-forms.html

于 2015-04-11T18:19:52.517 回答
3

FormElement以任何方式获取视图助手并addType覆盖使用的视图助手。即在视图中,就在您呈现表单之前:

<?php $this->plugin('FormElement')->addType('text', 'formcustom'); ?> 

这将通过键名覆盖使用视图助手的FormRow助手中使用的视图助手:FormCollection

在你的配置中

'view_helpers' => array(
    'invokables' => array(
        'formcustom' => 'Application\Form\View\Helper\FormCustom',
    )
),

当被问到这个问题时,该方法可能不存在。但现在是。

于 2015-01-16T22:08:19.867 回答
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);
        }
    }

}

---- 应用模块.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;
            }
        ),
    ),
//.........
于 2015-01-20T17:48:36.170 回答
0

似乎我们都遇到了 Zend 的表单问题。我认为它可以更好地与整个 MVC 结构集成。

我认为你的方法是合理的。我可能会想到做的是以下

  1. 给你的元素一个名为 helper 的变量,就像在 ZF1 中一样。
  2. 创建自定义表单元素渲染器,该渲染器还将检查表单元素的渲染器属性以决定如何渲染它。

您可以重新使用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 组件进行渲染期间使其视图助手可用。

于 2012-09-11T20:35:22.467 回答