Zend ServiceManager使用setter注入 [英] Zend ServiceManager using setter injection
问题描述
在symfony中,我可以通过call
选项( https ://symfony.com/doc/current/service_container/calls.html )
in symfony i can use the setter injection for services via call
option (https://symfony.com/doc/current/service_container/calls.html)
symfony文档中的示例:
The example from the symfony documentation:
class MessageGenerator
{
private $logger;
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
// ...
}
service.yml
service.yml
services:
App\Service\MessageGenerator:
# ...
calls:
- method: setLogger
arguments:
- '@logger'
我的zend项目需要这种行为.我想将InputFilter
注入我的FormFieldSet
.
I need this behaviour for my zend project. i want to inject a InputFilter
into my FormFieldSet
.
我在zend文档中没有找到任何关于此的内容.我可以使用类似的方法还是在zend中针对我的问题找到更好的解决方案?
I didn't find anything about this in the zend documentation. Can i use something like this or exist a better solution for my problem in zend?
推荐答案
基于这个问题以及您之前关于Forms,Fieldsets和InputFilters的问题,我认为您想实现与以下用例相似的东西.
Based on this question and your previous question about Forms, Fieldsets and InputFilters, I'm thinking you want to achieve something similar to the following use case.
>
用例
您有一个
You have a
- 位置实体
- 地址实体
- 位置对地址具有一个一对一"(必填,单向)
要管理位置,您需要:
- LocationForm(-工厂)
- LocationFormInputFilter(-Factory)
- LocationFieldset(-Factory)
- LocationFieldsetInputFilter(-Factory)
- AddressFieldset(-Factory)
- AddressFieldsetInputFilter(-Factory)
要在ZF3中进行配置,您必须添加以下内容
To configure this in ZF3, you'll have to do add the following
'form_elements' => [
'factories' => [
AddressFieldset::class => AddressFieldsetFactory::class,
LocationForm::class => LocationFormFactory::class,
LocationFieldset::class => LocationFieldsetFactory::class,
],
],
'input_filters' => [
'factories' => [
AddressFieldsetInputFilter::class => AddressFieldsetInputFilterFactory::class,
LocationFormInputFilter::class => LocationFormInputFilterFactory::class,
LocationFieldsetInputFilter::class => LocationFieldsetInputFilterFactory::class,
],
],
表格和字段集
在LocationForm
中,添加您的LocationFieldset
以及表单需要的其他内容,例如CSRF和提交"按钮.
Forms & Fieldsets
In the LocationForm
, add your LocationFieldset
and what else your Form needs, such as CSRF and submit button.
class LocationForm extends AbstractForm
{
public function init()
{
$this->add([
'name' => 'location',
'type' => LocationFieldset::class,
'options' => [
'use_as_base_fieldset' => true,
],
]);
//Call parent initializer. Adds CSRF & submit button
parent::init();
}
}
(注意:我的AbstractForm
还有更多功能,我建议您看看
(Note: my AbstractForm
does a bit more, I would suggest you have a look here, such as remove empty (child fieldsets/collections) Inputs so data is not attempted to be created in the DB)
在LocationFieldset
中,为位置添加添加的输入,例如名称和AddressFieldset
:
In the LocationFieldset
, give add Inputs for the Location, such as a name, and the AddressFieldset
:
class LocationFieldset extends AbstractFieldset
{
public function init()
{
parent::init();
$this->add([
'name' => 'name',
'required' => true,
'type' => Text::class,
'options' => [
'label' => _('Name'),
],
]);
$this->add([
'type' => AddressFieldset::class,
'name' => 'address',
'required' => true,
'options' => [
'use_as_base_fieldset' => false,
'label' => _('Address'),
],
]);
}
}
在AddressFieldset
中,只需为地址实体添加输入. (与上面相同,没有字段集类型输入)
In the AddressFieldset
just add Inputs for the Address Entity. (Same as above, without the Fieldset type Input)
要验证表单,您可以使其非常简单:
To validate the Form, you can keep it very simple:
class LocationFormInputFilter extends AbstractFormInputFilter
{
/** @var LocationFieldsetInputFilter */
protected $locationFieldsetInputFilter;
public function __construct(LocationFieldsetInputFilter $filter)
{
$this->locationFieldsetInputFilter = $filter;
parent::__construct();
}
public function init()
{
$this->add($this->locationFieldsetInputFilter, 'location');
parent::init();
}
}
(AbstractFormInputFilter
添加了CSRF验证器)
(The AbstractFormInputFilter
adds CSRF validator)
请注意,我们只是简单地->add()
LocationFieldsetInputFilter,但是我们给它起了一个名字(第二个参数).此名称将在以后的完整结构中使用,因此保持简单和正确无误非常重要.最简单的方法是给它一个与应该验证的Fieldset对象一对一匹配的名称.
Notice that we simply ->add()
the LocationFieldsetInputFilter, but we give it a name (2nd parameter). This name is used later in the complete structure, so it's important to both keep it simple and keep it correct. Simplest is to give it a name that one on one matches the object of the Fieldset it's supposed to validate.
接下来,LocationFieldsetInputFilter
:
class LocationFieldsetInputFilter extends AbstractFieldsetInputFilter
{
/**
* @var AddressFieldsetInputFilter
*/
protected $addressFieldsetInputFilter;
public function __construct(AddressFieldsetInputFilter $addressFieldsetInputFilter)
{
$this->addressFieldsetInputFilter = $addressFieldsetInputFilter;
parent::__construct();
}
public function init()
{
parent::init();
$this->add($this->addressFieldsetInputFilter, 'address'); // Again, name is important
$this->add(
[
'name' => 'name',
'required' => true,
'filters' => [
['name' => StringTrim::class],
['name' => StripTags::class],
[
'name' => ToNull::class,
'options' => [
'type' => ToNull::TYPE_STRING,
],
],
],
'validators' => [
[
'name' => StringLength::class,
'options' => [
'min' => 3,
'max' => 255,
],
],
],
]
);
}
}
工厂
现在,您必须将它们绑定在一起,这就是我认为关于Setter注入的问题所在.这发生在工厂中.
Factories
Now, you must bind them together, which is where your question about Setter injection comes from I think. This happens in the Factory.
A *FormFactory
将执行以下操作:
A *FormFactory
would do the following:
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$inputFilterPluginManager = $container->get('InputFilterManager');
$inputFilter = $inputFilterPluginManager->get(LocationFormInputFilter::class);
/** @var LocationForm $form */
$form = new LocationForm();
$form->setInputFilter($inputFilter); // The setter injection you're after
return $form;
}
*FieldsetFactory
将执行以下操作(对Location-和AddressFieldsets执行相同的操作):
A *FieldsetFactory
would do the following (do the same for Location- and AddressFieldsets):
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** @var LocationFieldset $fieldset */
// name matters! Match the object to keep it simple. Name is used from Form to match the InputFilter (with same name!)
$fieldset = new LocationFieldset('location');
// Zend Reflection Hydrator, could easily be something else, such as DoctrineObject hydrator.
$fieldset->setHydrator(new Reflection());
$fieldset->setObject(new Location());
return $fieldset;
}
A *FormInputFilterFactory
将执行以下操作:
A *FormInputFilterFactory
would do the following:
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$inputFilterPluginManager = $container->get('InputFilterManager');
/** @var LocationFieldsetInputFilter $locationFieldsetInputFilter */
$locationFieldsetInputFilter = $inputFilterPluginManager->get(LocationFieldsetInputFilter::class);
// Create Form InputFilter
$locationFormInputFilter = new LocationFormInputFilter(
$locationFieldsetInputFilter
);
return $locationFormInputFilter;
}
A *FieldsetInputFilterFactory
将执行以下操作:
A *FieldsetInputFilterFactory
would do the following:
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
/** @var AddressFieldsetInputFilter $addressFieldsetInputFilter */
$addressFieldsetInputFilter = $this->getInputFilterManager()->get(AddressFieldsetInputFilter::class);
$addressFieldsetInputFilter->setRequired(true);
return new LocationFieldsetInputFilter(
$addressFieldsetInputFilter
);
}
注意:
- 我已添加此处
- 如果您的InputFilter(例如AddressFieldsetInputFilter)没有子InputFilter,则可以跳过获取该子项并立即返回新的InputFilter.
我认为我已经完整地介绍了所有内容.如果对此有任何疑问,请发表评论.
I think I covered it all for a complete picture. If you have any questions about this, please comment.
这篇关于Zend ServiceManager使用setter注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!