symfony 包中的服务依赖于应用程序中的服务

问题描述 投票:0回答:1

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
中?或者捆绑包是否无法使用应用程序中的服务?

php symfony dependency-injection autowired symfony-bundle
1个回答
0
投票

问题在于 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();
        }
    }
© www.soinside.com 2019 - 2024. All rights reserved.