使用 factory for fieldset 创建表单——如何连接两者?

Form creation using factory for fieldset – how to connect the two?

我想使用工厂创建的字段集在 Zend Framework 2 中创建一个表单,但我在将字段集与表单连接时遇到问题。

字段集是这样创建的:

<?php    
// File: module/FormElements/src/Form/PersonalDataFieldset.php

namespace FormElements\Form;

use Zend\Form\Factory;

class PersonalDataFieldset extends Factory
{
    public function __construct()
    {
        $factory = new Factory();
        $form = $factory->createForm(array(
            'fieldsets' => array(
                array(
                    'spec' => array(
                        'name' => 'data',
                        'options' => array(
                            'label' => 'Fieldset Test',
                        ),
                        'elements' => array(
                            array(
                                'spec' => array(
                                    'name' => 'fname',
                                    'type' => 'text',
                                ),
                            ),
                            array(
                                'spec' => array(
                                    'name' => 'lname',
                                    'type' => 'text',
                                ),
                            ),
                            array(
                                'spec' => array(
                                    'name' => 'email',
                                    'type' => 'email',
                                ),
                            ),
                        ),
                    ),
                ),
            ),
        ));
    }
}

形式:

<?php
// File: module/FormElements/src/Form/PersonalDataForm.php

namespace FormElements\Form;

use Zend\Form\Form;

class PersonalDataForm extends Form
{
    public function __construct()
    {
        parent::__construct();

        // Field not contained in the fieldset - this works
        $this->add(array(
            'name'=> 'some-name',
            'type' => 'text',
            'options' => array(
                'label' => 'Test Label',
            ),
        ));

        // Here I am trying to add the fieldset – this does not work
        $this->add(array(
            'name' => 'some-other-name',
            'type' => 'FormElements\Form\PersonalDataFieldset',
        ));
    }
}

以及应该连接两者的控制器:

<?php
// File: module/FormElements/src/Controller/FormElementsController.php

namespace FormElements\Controller;

use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;

use FormElements\Form\PersonalDataForm;

class FormElementsController extends AbstractActionController
{
    public function indexAction()
    {
        $form = new PersonalDataForm();

        return new ViewModel(array(
            'form' => $form
        ));
    }
}

根据我的尝试,结果在空视图或异常之间有所不同。

例如,使用上面发布的代码,我得到 Plugin of type FormElements\Form\PersonalDataFieldset is invalid; must implement Zend\Form\ElementInterface
我当然可以实现接口,因为异常告诉我这样做,但我想了解我在做什么,但我不知道为什么需要这个接口?

我会避免在你的控制器中调用 $form = new PersonalDataForm();

我会在工厂中注入该依赖项,该工厂应该可以访问 "FormElementManager"

FormElementManager 是一个 AbstractPluginManager,可以在其中存储所有与表单相关的服务,包括元素、字段集和完整表单(因为它们都扩展 Zend\Form\Element)

通过从插件管理器调用表单服务(并确保将该插件管理器注入任何后续表单工厂),您将不会 运行 出现这些 "Invalid Plugin" 错误。

"Invalid Plugin" 异常通常意味着两种情况之一。您没有在插件管理器中注册您的元素,或者您没有在需要的地方正确注入插件管理器。

将您的字段和字段集添加方法从 __construct() 移动到 init() 方法,并使用 FormElementManager 抓取您的表单。它的工作方式与自定义元素的工作方式相同 zf2 docs

编辑 1:我修复了 link,似乎 # 符号已正确编码

编辑 2:这里引用了 ZF2 文档中的部分内容:

...Example code for custom element...

And now comes the first catch.

If you are creating your form class by extending Zend\Form\Form, you must not add the custom element in the __construct-or (as we have done in the previous example where we used the custom element’s FQCN), but rather in the init() method:

namespace Application\Form;

use Zend\Form\Form;

class MyForm extends Form
{
    public function init()
    {
        $this->add(array(
            'name' => 'phone',
            'type' => 'Phone',
        ));
    }
 }

The second catch is that you must not directly instantiate your form class, but rather get an instance of it through the Zend\Form\FormElementManager:

namespace Application\Controller;

use Zend\Mvc\Controller\AbstractActionController;

class IndexController extends AbstractActionController
{
    public function indexAction()
    {
        $sl = $this->getServiceLocator();
        $form = $sl->get('FormElementManager')->get('\Application\Form\MyForm');
        return array('form' => $form);
    }
}

The biggest gain of this is that you can easily override any built-in Zend Framework form elements if they do not fit your needs. For instance, if you want to create your own Email element instead of the standard one, you can simply create your element and add it to the form element config with the same key as the element you want to replace ...