2

我有一个表单 ( Zend\Form\Form),其中包含一些嵌套的字段集 ( Zend\Form\Fieldset)。构造与表单集合教程中的构造非常相似。

Storage\Form\MyForm
|_'Storage\Form\Fieldset\FooFieldset'
  |_'Storage\Form\Fieldset\BarFieldset'
|_'Storage\Form\Fieldset\BazFieldset'
...

MyForm

class MyForm {
    public function __construct()
    {
        ...
        $this->add(
            [
                'type' => 'Storage\Form\Fieldset\FooFieldset',
                'options' => [
                    'use_as_base_fieldset' => true
                ]
            ]
        );
    }
}

FooFieldset

class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
    public function __construct()
    {
        parent::__construct('foo');
        $this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
    }
}

它可以工作,但是 fieldset 类中有两个依赖项。我想注射它们。为了做到这一点,我创建了一个FooFieldsetFactory并扩展了/module/MyModule/config/module.config.php

'service_manager' => [
    'factories' => [
        'Storage\Form\Fieldset\FooFieldset' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
    ],
],

工厂只是被忽略了。我猜,服务定位器首先尝试按命名空间查找类,只有在没有找到的情况下,才会查看invokablesand factories。好的。然后我创建了一个别名:

'service_manager' => [
    'factories' => [
        'Storage\Form\Fieldset\FooFieldset' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
    ],
],
'aliases' => [
    'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\FooFieldset',
],

...并尝试使用它而不是Storage\Form\Fieldset\FooFieldset在我的表单类中。但现在我得到一个例外:

Zend\Form\FormElementManager::get 无法获取或创建 Storage\Form\Fieldset\Foo 的实例

我也直接尝试过:

'service_manager' => [
    'factories' => [
        'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
    ],
],

没有效果,同样的错误。

这也不起作用(同样的错误):

'form_elements' => [
    'factories' => [
        'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
    ],
],

因此,为字段集引用服务似乎不起作用。还是我做错了什么?

如何为表单字段集使用服务?


更新

通过一些调试,我发现我的Foo字段集工厂无法找到,因为它尚未添加factoriesZend\Form\FormElementManager. 这是中的地方Zend\Form\Factory

在此处输入图像描述

所以我的配置

'form_elements' => [
    'factories' => [
        'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
    ],
],

被忽略。如何解决这个问题?


更新附加信息,我如何创建我的Form对象。

/module/Foo/config/module.config.php

return [
    'controllers' => [
        'factories' => [
            'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
        ]
    ],
    'service_manager' => [
        'factories' => [
            'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
        ],
    ],
];

/module/Foo/src/Foo/Form/Factory/MyFormFactory.php

namespace Foo\Form\Factory;

use ...;

class MyFormFactory implements FactoryInterface
{

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $form = new MyForm();
        $form->setAttribute('method', 'post')
            ->setHydrator(new ClassMethods())
            ->setInputFilter(new InputFilter());
        return $form;
    }
}

/module/Foo/src/Foo/Controller/Factory/MyControllerFactory.php

namespace Foo\Controller\Factory;

use ...;

class MyControllerFactory implements FactoryInterface
{

    public function createService(ServiceLocatorInterface $serviceLocator)
    {
        $fooPrototype = new Foo();
        $realServiceLocator = $serviceLocator->getServiceLocator();
        // $myForm = $realServiceLocator->get('Foo\Form\MyForm'); <-- This doesn't work correctly for this case. The FormElementManager should be used instead.
        $formElementManager = $realServiceLocator->get('FormElementManager');                        
        $myForm = $formElementManager->get('Foo\Form\MyForm');
        return new MyController($myForm, $fooPrototype);
    }
}
4

1 回答 1

6

这个问题是因为您在 forms __construct()方法中添加表单元素,而不是init() 按照文档中的建议

您可以使用工厂而不是可调用对象来处理元素/字段集/表单中的依赖关系。

现在是第一个捕获。

如果您通过扩展来创建表单类,Zend\Form\Form则不能在__construct-or 中添加自定义元素(就像我们在前面使用自定义元素的 FQCN 的示例中所做的那样),而是在init()方法中添加:

原因是新表单的工厂(用于使用 创建新元素)add()必须在调用表单的构造函数注入应用程序的表单元素管理器此表单元素管理器实例包含对您注册的自定义表单元素的所有引用在form_elements配置键下。

通过调用add()表单__construct ,表单工厂将延迟加载表单元素管理器的新实例;它将能够创建所有默认表单元素,但不会了解您的自定义表单元素。

于 2016-03-10T23:57:31.723 回答