Symfony 4 setter 注入不能在有或没有自动装配的情况下工作
Symfony 4 setter injection not working in bundle with or without autowire
我以为我完全理解 Symfony 的自动装配行为,但肯定有一些我遗漏的东西,我希望有人可以填补空白。
开头的三个问题:
- 主应用程序与捆绑包中的 Symfony 自动装配行为有区别吗?
- 如果您要求 Symfony 自动装配捆绑服务,它会完全忽略捆绑
services.yaml
文件中的服务定义吗?
- Symfony 4 中的 setter 注入功能是否存在已知问题?
我在使用 setter 注入的包中有一个服务定义,但它似乎完全被 Symfony 忽略了,当我要求 Symfony 自动装配我的包服务时,甚至当我要求 Symfony 时从自动装配中排除服务。
我的应用程序正在使用 Symfony v4.1.3
。
我已将我的 Bundle 包含在我的应用程序 bundles.php
文件中。
<?php
return [
//... core bundles,
Acme\Symfony\AcmeCustomBundle\AcmeCustomBundle::class => ['all' => true]
];
在 default
Symfony 应用程序 services.yaml
文件中,我要求 Symfony 使用以下内容自动装配我的捆绑服务:
Acme\Symfony\AcmeCustomBundle\:
resource: '../vendor/acme-symfony/custom-bundle/*'
exclude: '../vendor/acme-symfony/custom-bundle/{Model,Tests}'
在位于 ../vendor/acme-symfony/custom-bundle/Resources/config/services.yaml
的捆绑包 services.yaml
文件中,我有以下内容:
parameters:
services:
Acme\Symfony\AcmeCustomBundle\Search\ConfigurationReader:
calls:
- method: setIndex
arguments:
$index: '%elasticsearch.index%'
- method: setSchema
arguments:
$schema: '%elasticsearch.schema%'
参数在我的包扩展 class(扩展可配置扩展)中设置,我已经验证参数确实存在并且正在使用以下方法设置:
$container->setParameter('elasticsearch.index', $mergedConfigs['elasticsearch']['index']);
$container->setParameter('elasticsearch.schema', $mergedConfigs['elasticsearch']['schema']);
现在回到问题。 Symfony 没有执行 setter 注入,即使我告诉 Symfony 不要通过执行以下操作自动装配上述服务:
Acme\Symfony\AcmeCustomBundle\:
resource: '../vendor/acme-symfony/custom-bundle/*'
exclude: '../vendor/acme-symfony/custom-bundle/{Model,Tests,Search}'
不过,当我
时,我确实让 Symfony 配置了我的服务
- 关闭了上述服务的自动装配
- 使用了服务创建的工厂方法
这样回答了我上面的第二个问题,但我不是100%确定。尽管如此,我宁愿不必使用工厂 class 来解决 Symfony 可能存在的问题,或者我不了解 setter 注入/自动装配的真正工作方式。
有人能看出我遗漏了什么吗?
首先,要共享的包中的自动装配不是最佳实践的一部分。您必须明确定义要共享的捆绑包的服务,并在 xml 中进行。
现在,话虽如此,autowire 所做的是在 class 的构造函数中连接服务,尝试自动解析它们。它不执行 setter 注入。
您需要做的是配置一个自动配置入口。在您的捆绑包扩展 class 中,您可以:
$container->registerForAutoconfiguration(ConfigurationReader::class)
->addMethodCall('setIndex', ['%elasticsearch.index%'])
->addMethodCall('setSchema', ['%elasticsearch.schema%']);
现在,这实际上是要与接口或抽象 classes 一起使用,而不是与具体实现一起使用。但是如果你想自动配置你的服务,你可以做什么。
我的建议是,如果您要重用这个包,请在 xml 中明确定义服务。自动装配适用于您的业务逻辑和服务。
如果需要,您可以自动装配其他方法(例如 Setters),只需在您的服务中使用 @required 注释即可:
/**
* @required
*/
public function setFoo(FooInterface $foo)
{
$this->foo = $foo;
}
我以为我完全理解 Symfony 的自动装配行为,但肯定有一些我遗漏的东西,我希望有人可以填补空白。
开头的三个问题:
- 主应用程序与捆绑包中的 Symfony 自动装配行为有区别吗?
- 如果您要求 Symfony 自动装配捆绑服务,它会完全忽略捆绑
services.yaml
文件中的服务定义吗? - Symfony 4 中的 setter 注入功能是否存在已知问题?
我在使用 setter 注入的包中有一个服务定义,但它似乎完全被 Symfony 忽略了,当我要求 Symfony 自动装配我的包服务时,甚至当我要求 Symfony 时从自动装配中排除服务。
我的应用程序正在使用 Symfony v4.1.3
。
我已将我的 Bundle 包含在我的应用程序 bundles.php
文件中。
<?php
return [
//... core bundles,
Acme\Symfony\AcmeCustomBundle\AcmeCustomBundle::class => ['all' => true]
];
在 default
Symfony 应用程序 services.yaml
文件中,我要求 Symfony 使用以下内容自动装配我的捆绑服务:
Acme\Symfony\AcmeCustomBundle\:
resource: '../vendor/acme-symfony/custom-bundle/*'
exclude: '../vendor/acme-symfony/custom-bundle/{Model,Tests}'
在位于 ../vendor/acme-symfony/custom-bundle/Resources/config/services.yaml
的捆绑包 services.yaml
文件中,我有以下内容:
parameters:
services:
Acme\Symfony\AcmeCustomBundle\Search\ConfigurationReader:
calls:
- method: setIndex
arguments:
$index: '%elasticsearch.index%'
- method: setSchema
arguments:
$schema: '%elasticsearch.schema%'
参数在我的包扩展 class(扩展可配置扩展)中设置,我已经验证参数确实存在并且正在使用以下方法设置:
$container->setParameter('elasticsearch.index', $mergedConfigs['elasticsearch']['index']);
$container->setParameter('elasticsearch.schema', $mergedConfigs['elasticsearch']['schema']);
现在回到问题。 Symfony 没有执行 setter 注入,即使我告诉 Symfony 不要通过执行以下操作自动装配上述服务:
Acme\Symfony\AcmeCustomBundle\:
resource: '../vendor/acme-symfony/custom-bundle/*'
exclude: '../vendor/acme-symfony/custom-bundle/{Model,Tests,Search}'
不过,当我
时,我确实让 Symfony 配置了我的服务- 关闭了上述服务的自动装配
- 使用了服务创建的工厂方法
这样回答了我上面的第二个问题,但我不是100%确定。尽管如此,我宁愿不必使用工厂 class 来解决 Symfony 可能存在的问题,或者我不了解 setter 注入/自动装配的真正工作方式。
有人能看出我遗漏了什么吗?
首先,要共享的包中的自动装配不是最佳实践的一部分。您必须明确定义要共享的捆绑包的服务,并在 xml 中进行。
现在,话虽如此,autowire 所做的是在 class 的构造函数中连接服务,尝试自动解析它们。它不执行 setter 注入。
您需要做的是配置一个自动配置入口。在您的捆绑包扩展 class 中,您可以:
$container->registerForAutoconfiguration(ConfigurationReader::class)
->addMethodCall('setIndex', ['%elasticsearch.index%'])
->addMethodCall('setSchema', ['%elasticsearch.schema%']);
现在,这实际上是要与接口或抽象 classes 一起使用,而不是与具体实现一起使用。但是如果你想自动配置你的服务,你可以做什么。
我的建议是,如果您要重用这个包,请在 xml 中明确定义服务。自动装配适用于您的业务逻辑和服务。
如果需要,您可以自动装配其他方法(例如 Setters),只需在您的服务中使用 @required 注释即可:
/**
* @required
*/
public function setFoo(FooInterface $foo)
{
$this->foo = $foo;
}