Zend framework2 如何在Zend Framework 2中为表单字段集使用服务?
我有一个表单(),其中有一些嵌套的字段集()。其结构与建筑中的结构非常相似Zend framework2 如何在Zend Framework 2中为表单字段集使用服务?,zend-framework2,zend-form,service-locator,zend-framework-mvc,servicemanager,Zend Framework2,Zend Form,Service Locator,Zend Framework Mvc,Servicemanager,我有一个表单(),其中有一些嵌套的字段集()。其结构与建筑中的结构非常相似 MyForm class MyForm { public function __construct() { ... $this->add( [ 'type' => 'Storage\Form\Fieldset\FooFieldset', 'options' => [
MyForm
class MyForm {
public function __construct()
{
...
$this->add(
[
'type' => 'Storage\Form\Fieldset\FooFieldset',
'options' => [
'use_as_base_fieldset' => true
]
]
);
}
}
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct('foo');
$this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
}
}
return [
'controllers' => [
'factories' => [
'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
]
],
'service_manager' => [
'factories' => [
'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
],
],
];
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;
}
}
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);
}
}
FooFieldset
class MyForm {
public function __construct()
{
...
$this->add(
[
'type' => 'Storage\Form\Fieldset\FooFieldset',
'options' => [
'use_as_base_fieldset' => true
]
]
);
}
}
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct('foo');
$this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
}
}
return [
'controllers' => [
'factories' => [
'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
]
],
'service_manager' => [
'factories' => [
'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
],
],
];
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;
}
}
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);
}
}
它可以工作,但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',
],
],
没有效果,同样的错误
这也不起作用(同样的错误):
因此,为字段集引用服务似乎不起作用。还是我做错了什么
如何为表单字段集使用服务?
更新 通过一些调试,我发现无法找到我的
Foo
字段集工厂,因为它尚未添加到。这是一个地方:
所以我的配置
'form_elements' => [
'factories' => [
'Storage\Form\Fieldset\Foo' => 'Storage\Form\Fieldset\Factory\FooFieldsetFactory',
],
],
被忽略了。如何解决这个问题
更新其他信息,我如何创建我的
表单
对象
/module/Foo/config/module.config.php
class MyForm {
public function __construct()
{
...
$this->add(
[
'type' => 'Storage\Form\Fieldset\FooFieldset',
'options' => [
'use_as_base_fieldset' => true
]
]
);
}
}
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct('foo');
$this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
}
}
return [
'controllers' => [
'factories' => [
'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
]
],
'service_manager' => [
'factories' => [
'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
],
],
];
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;
}
}
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);
}
}
/module/Foo/src/Foo/Form/Factory/MyFormFactory.php
class MyForm {
public function __construct()
{
...
$this->add(
[
'type' => 'Storage\Form\Fieldset\FooFieldset',
'options' => [
'use_as_base_fieldset' => true
]
]
);
}
}
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct('foo');
$this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
}
}
return [
'controllers' => [
'factories' => [
'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
]
],
'service_manager' => [
'factories' => [
'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
],
],
];
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;
}
}
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);
}
}
/module/Foo/src/Foo/Controller/Factory/MyControllerFactory.php
class MyForm {
public function __construct()
{
...
$this->add(
[
'type' => 'Storage\Form\Fieldset\FooFieldset',
'options' => [
'use_as_base_fieldset' => true
]
]
);
}
}
class FooFieldset extends Fieldset implements InputFilterProviderInterface
{
public function __construct()
{
parent::__construct('foo');
$this->setHydrator(new ClassMethodsHydrator())->setObject(new Foo()); // dependencies!
}
}
return [
'controllers' => [
'factories' => [
'Foo\Controller\My' => 'Foo\Controller\Factory\MyControllerFactory'
]
],
'service_manager' => [
'factories' => [
'Foo\Form\MyForm' => 'Foo\Form\Factory\MyFormFactory',
],
],
];
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;
}
}
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);
}
}
名称空间Foo\Controller\Factory;
使用。。。;
类MyControllerFactory实现FactoryInterface
{
公共函数createService(serviceLocator接口$serviceLocator)
{
$fooPrototype=newfoo();
$realServiceLocator=$serviceLocator->getServiceLocator();
//$myForm=$realServiceLocator->get('Foo\Form\myForm');此问题是因为您正在表单\uuu construct()
方法中添加表单元素,而不是init()
为了处理元素/字段集/表单中的依赖关系,可以使用工厂而不是可调用工厂
现在是第一个陷阱
如果您是通过扩展Zend\form\form
来创建表单类,则不能在\uuu构造中添加自定义元素,或者(正如我们在前面的示例中使用自定义元素的FQCN所做的那样),而是在init()
方法中添加自定义元素:
原因是新表单的工厂(用于使用add()
)创建新元素)必须具有应用程序的表单元素管理器此表单元素管理器实例包含对在form\u elements
配置键下注册的自定义表单元素的所有引用
通过在表单\uu construct
中调用add()
,它将能够创建所有默认表单元素,但不了解自定义表单元素。非常感谢您的详细回答!我将初始化逻辑从构造函数移到了init()中
。但它不起作用。对于表单
来说,元素就是找不到,例如:没有名为[foo]的元素在表单
中找到。对于字段集
s:与以前相同的错误:Zend\form\FormElementManager::get无法获取或创建Order\form\FieldSet\Foo的实例
。我还分析了init()
中FormElementManager
的状态。因为init()
是在构造函数之后调用的,我希望在MyFieldset->factory->formElementManager->factories
中找到我的自定义字段集工厂。但是该属性只包含标准的Zend工厂。@automatix是否使用$formElementManager->get('Order\form\fieldset\Foo
)创建表单表单#init()
和我的FooFieldsetFactory
中的字段终于被检索到了!非常感谢您的帮助!@automatix您是如何解决“没有元素的名称…”的问题的?我是$Form->get('employee')
这给了我一个例外。我的EmployeeFieldSet在构造函数中执行:父::_构造('employee');
在init函数中,我执行所有这些添加
调用。在我表单的构造函数中,我执行以下操作:父::_构造('create_employee');
和在init()中方法我添加EmployeeFieldSet
。在config.module.php中,我有form\u元素,但不会调用它