TLDR:我正在创建一个 Symfony 6 捆绑包,它提供一项服务,该服务依赖于利用应用程序将提供的接口实现为服务。
我正在创建的捆绑包提供了一项名为
MyBundleService
的服务。它还提供了一个名为 MyBundleManagerInterface
的接口,预计任何使用应用程序都可以将其实现为服务。
如何将利用应用程序实现的服务自动注入到我的捆绑包提供的
MyBundleService
服务中?
这里用简化代码来说明:
首先是界面:
/** MyBundleManagerInterface.php **/
namespace MyCompany\MyBundle\Interface;
interface MyBundleManagerInterface
{
public function processRequest(\Symfony\Component\HttpFoundation\Request $request): void;
}
现在,假设应用程序将
MyBundleManagerInterface
实现为服务:
namespace App\Service;
use MyCompany\MyBundle\Interface\MyBundleManagerInterface;
class ManagerService implements MyBundleManagerInterface {
public function processRequest(\Symfony\Component\HttpFoundation\Request $request): void
{
//do something
}
}
我的包中的服务
MyBundleService
似乎无法获取MyBundleManagerInterface
实现,这是来自应用程序的服务ManagerService
。
/** MyBundleService.php **/
// the bundle has been configured to autowire all classes inside this namespace
namespace MyCompany\MyBundle\Service;
use MyCompany\MyBundle\Interface\MyBundleManagerInterface;
class MyBundleService
{
public function __construct(protected ?MyBundleManagerInterface $manager)
{
// the injected $manager seems to be NULL here
}
#[Required]
public function setManager(?MyBundleManagerInterface $manager)
{
// this Required-attributed method is called, yet the $manager parameter is NULL
$this->manager = $manager;
}
}
我错过了什么?有没有办法告诉 Symfony 依赖注入应用程序中的
ManagerService
可以注入到 MyBundleService
中?或者捆绑包是否无法使用应用程序中的服务?
问题在于 Symfony 不知道要实现哪个类,因为您可以多次实现该接口。 要知道要自动装配的类,您必须为接口设置别名。
# config/services.yaml
services:
MyCompany\MyBundle\Interface\MyBundleManagerInterface: '@App\Service\ManagerService'
https://symfony.com/doc/current/service_container/autowiring.html#working-with-interfaces
对于这个用例,我更喜欢使用标记服务。然后,您可以使用多个实现并避免需要更改 services.yaml 文件。
#[AutoconfigureTag('app.your.tag')]
interface MyBundleManagerInterface
{
public function doSomething(): void;
}
class MyBundleService
{
public function __construct(
#[TaggedIterator('app.your.tag')]
private readonly iterable $manager,
) {
}
public function run(): void
{
foreach ($ths->manager as $manager) {
$manager->doSomething();
}
}