我有一个表单(Zend\Form\Form
),其中包含一些嵌套的字段集(Zend\Form\Fieldset
)。构造非常类似于Form Collections tutorial。
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',
],
],
工厂被忽略了。我想,服务定位器首先尝试按命名空间查找类,但只有在找不到任何内容时,才能查看invokables
和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
字段集工厂无法找到,因为它尚未添加到Zend\Form\FormElementManager
的factories
列表中。以下是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);
}
}
答案 0 :(得分:5)
此问题是因为您要在表单__construct()
方法而不是init()
as suggested in the documentation中添加表单元素。
您可以使用工厂而不是invokable来处理元素/ fieldsets / forms中的依赖项。
现在是第一个问题。
如果要通过扩展
Zend\Form\Form
来创建表单类,则不能在__construct
中添加自定义元素 - 或者(正如我们在上一个使用自定义元素的FQCN的示例中所做的那样) ),而是在init()
方法中:
原因是新表单的工厂(用于使用add()
创建新元素)必须具有应用程序的表单元素管理器injected after the form's constructor has been called此表单元素管理器实例包含在form_elements
配置键下注册的自定义表单元素的所有引用。
通过add()
the form factory will lazy load a new instance of the form element manager形式致电__construct
;它将能够创建所有默认表单元素,但不会了解您的自定义表单元素。