在symfony中,我可以通过call选项(容器/calls.html)为服务使用setter注入。
symfony文档中的示例:
class MessageGenerator
{
private $logger;
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
// ...
}service.yml
services:
App\Service\MessageGenerator:
# ...
calls:
- method: setLogger
arguments:
- '@logger'我的zend项目需要这种行为。我想把一个InputFilter注入我的FormFieldSet。
我在zend文档中没有找到关于这个的任何东西。我可以使用这样的东西或者存在一个更好的解决我在zend的问题的方法吗?
发布于 2018-11-15 08:55:37
基于这个问题和前面关于表单、Fieldset和InputFilters的问题,我认为您希望实现类似于下面的用例。
用例
你有一个
要求
要管理位置,您需要:
配置
要在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做得更多,我建议您看看这里,例如删除空(子字段集/集合)输入,这样就不会尝试在DB中创建数据)
在LocationFieldset中,为位置(如名称)和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中,只需为Address实体添加输入。(与上面相同,没有Fieldset类型输入)
InputFilters
要验证表单,您可以保持它非常简单:
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验证器)
注意,我们只是简单地->add() LocationFieldsetInputFilter,但是我们给它一个名称(第二个参数)。这个名称稍后会在完整的结构中使用,所以保持它的简单和正确是很重要的。最简单的方法是给它一个名字,使其一对一地匹配它应该验证的Fieldset的对象。
接下来,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注入的问题的来源。这种情况发生在工厂里。
*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;
}*FieldsetFactory将执行以下操作(对Location-和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;
}*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;
}*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
);
}Note
我想我把它全报道了一张完整的照片。如果你对此有任何疑问,请评论。
发布于 2018-11-15 12:24:23
您需要的是初始化器、来自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'));
}
}
}您还需要在中注册MessageGenerator。这样,当您尝试从SM检索MessageGenerator时,在创建MyInitializer之后调用。
https://stackoverflow.com/questions/53299020
复制相似问题