Zend ServiceManager使用setter注入 [英] Zend ServiceManager using setter injection

查看:95
本文介绍了Zend ServiceManager使用setter注入的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆