代码之家  ›  专栏  ›  技术社区  ›  rob

使用setter注入的Zend ServiceManager

  •  0
  • rob  · 技术社区  · 7 年前

    在symfony中,我可以通过 call https://symfony.com/doc/current/service_container/calls.html )

    symfony文档中的示例:

    class MessageGenerator
    {
        private $logger;
    
        public function setLogger(LoggerInterface $logger)
        {
            $this->logger = $logger;
        }
    
        // ...
    }
    

    服务.yml

    services:
        App\Service\MessageGenerator:
            # ...
            calls:
                - method: setLogger
                  arguments:
                      - '@logger'
    

    我的zend项目需要这种行为。我想注射 InputFilter FormFieldSet .

    我在zend文档中没有找到任何关于这个的信息。我能用这样的方法解决我在zend的问题吗?

    2 回复  |  直到 7 年前
        1
  •  2
  •   rkeet Aurimas    7 年前

    基于这个问题和您之前关于表单、字段集和输入过滤器的问题,我认为您希望实现类似于以下用例的功能。

    用例

    你有一个

    • 位置实体
    • 位置有一个到一个地址的one(必需的,单向的)

    要管理位置,您需要:

    • 位置形式(-工厂)
    • LocationFieldset(-Factory)
    • LocationFieldsetInputFilter(-Factory)
    • AddressFieldsetInputFilter(-Factory)

    要在ZF3中配置它,您必须添加以下内容

    '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和submit按钮。

    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 多做一点,我建议你看看 here ,例如删除空(子字段集/集合)输入,以便不尝试在数据库中创建数据)

    在 ,为位置提供add输入,例如名称和 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'),
                ],
            ]);
        }
    }
    

    在 地址字段集 只需为地址实体添加输入(同上,无字段集类型输入)

    输入过滤器

    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();
        }
    }
    

    (The) AbstractFormInputFilter 添加CSRF验证程序)

    ->add()

    接下来是 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,
                            ],
                        ],
                    ],
                ]
            );
        }
    }
    

    工厂

    现在,你必须把它们绑在一起,我想这就是你关于塞特注射的问题。这是在工厂里发生的。

    A. *FormFactory

    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;
    }
    

    A. *FieldsetFactory 将执行以下操作(对Location和addressfieldset执行相同的操作):

    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

    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 将执行以下操作:

    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设置为(非)必需的是我添加的内容 here

    我想我把这一切都说了一遍,以得到一个完整的画面。如果您对此有任何疑问,请发表评论。

        2
  •  1
  •   tasmaniski    7 年前

    你需要的是 初始值设定项 Zend Service Manager .

    初始值设定项可以是在创建服务时调用的类。 在该类中,您需要检查所创建的服务的类型,以及它是否是合适的类型,而不是注入您想要的任何类型。

    在配置下注册一个初始值设定项外接程序 密钥:

    'service_manager' => [
        'initializers' => [
           MyInitializer::class
        ],
    ]
    

    然后创建这个类

    class MyInitializer implements InitializerInterface
    {
        public function __invoke(ContainerInterface $container, $instance)
        {
            // you need to check should you inject or not
            if ($instance instanceof MessageGenerator) { 
                $instance->setLogger($container->get('logger'));
            }
        }
    }
    

    你需要注册 消息生成器 消息生成器 从SM,创建后调用MyInitializer。