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

I think the simplest way is to extend Zend\Form\View\Helper\FormElement, handle your field types in your render() method and register your FormElement as default FormElement for your application/module. Assuming that you have your custom TestField that you would like to render:

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);
    }
}

And in Application/config/module.config.php:

'view_helpers' => array(
    'invokables' => array(
         'form_element' => 'Application\Form\View\Helper\MyFormElement',
    )
)
于 2012-11-22T08:17:08.153 に答える
3

Get your hands on the FormElement view helper any way you can and addType to overwrite the view helper used. i.e. in view, just before you render your form:

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

This will overwrite the view helper used in the FormRow,FormCollection helpers using your view helper by the key name:

in your config

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

When this question was asked the method may not have been there. But it is now.

于 2015-01-16T22:08:19.867 に答える
3

The following is what I've done and feels like the right level of keeping things separate and neat.

Given:

  • A new element: MyModule\Form\MyElement which extends Zend\Form\Element
  • A new view helper class for MyElement: MyModule\Form\View\Helper\FormMyElement which extends Zend\Form\View\Helper\AbstractHelper

Here's how you register your view helper to be used to render your element by adding the following to 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;
        }
    ),
),

The key is that you are providing a new factory method for FormElement that still creates the same, standard class (no need to override it), but also calls the addClass method to register your custom helper as the proper helper for your custom element. If you don't want to make the short-name for your helper, you can drop the invokables section and put the FQCN in the addClass call, but I like having the short name available.

This is the best method I've found so far. Ideally, you wouldn't have to take over the construction of the FormElement and could just modify a config that gets passed to it. The downside of this approach is that if you have multiple modules that define custom form elements they are going to clash if they all try to re-define the FormElement factory. You can't specify additions in multiple modules this way. So, if someone finds a better config that can be set that simply gets passed to the FormElement::addClass() method, please let me know.

BTW, I found this page which doesn't address the view helper side of the equation, but talks about registering new form element classes and how to over-ride the built in classes: http://framework.zend.com/manual/current/en/modules/zend.form.advanced-use-of-forms.html

于 2015-04-11T18:19:52.517 に答える
2

----custom form element-----

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;
            }
        ),
    ),
//.........
于 2015-01-20T17:48:36.170 に答える
0

Zendでフォームの問題が発生しているようです。MVC構造全体とより適切に統合できると思います。

あなたのアプローチは健全だと思います。私が考えていることは次のとおりです

  1. Give your elements a variable named helper like in ZF1.
  2. Create the custom form element renderer that will ALSO check the renderer attribute of a form element to decide on how to render it.

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.

于 2012-09-11T20:35:22.467 に答える