symfony 6在父->子控制器之间的依赖注入

dm7nw8vv  于 2023-10-24  发布在  其他
关注(0)|答案(1)|浏览(96)

我有一个基本的控制器类,它有一些所有子控制器都将使用的实用程序方法。到目前为止,它有3个依赖项,但将来可能会有更多。因此,我现在有一个问题,IMO,每当我想向子控制器添加依赖项时,都会有过多的DI指令。

abstract class BaseController extends AbstractController
{
    public function __construct(
        protected readonly SerializerInterface $serializer,
        protected readonly ValidatorInterface  $validator,
        private readonly ResponseGenerator     $responseGenerator,
    ) {
    }
    ...

}

class ChildController extends BaseController
{
    // All the parent class injections are required in all child classes.
    public function __construct(
        SerializerInterface             $serializer,
        ValidatorInterface              $validator,
        ResponseGenerator               $responseGenerator,
        private readonly SomeRepository $someRepository,
        ... insert any other child controller-specific dependencies here.
    ) {
        parent::__construct($serializer, $validator, $responseGenerator);
    }
    ...
}

我尝试在基本控制器中使用$this->container->get('serializer'),但这不起作用,因为AbstractController::$container是通过注入定义的,但没有构造函数,所以调用parent::__construct()是不可能的。此外,它不会给予validator,所以即使它起作用,也只能解决部分问题。
我试着寻找一个我可以使用的属性,例如。

abstract class BaseController extends AbstractController
{
    #[Inject]
    protected readonly SerializerInterface $serializer;

    #[Inject]
    protected readonly ValidatorInterface $validator;

但是没有找到类似的东西(PHP-DI有,但Symfony没有)。
有没有办法以某种方式摆脱子控制器中的重复依赖关系?

pdtvr36n

pdtvr36n1#

你需要的是service subscribers
Symfony中的控制器在扩展AbstractController时是服务订阅者,这意味着它们注入了一个小容器,其中包含一些常见的服务,如twig,序列化器,表单生成器等。
如果你想让你的子控制器使用一些“公共”服务,你可以通过覆盖父控制器中的getSubscribedServices()来扩展列表。或者如果你的控制器没有扩展Symfony提供的默认值,你只需要实现你自己的:
如果你的控制器是一个服务(我猜已经是了),Symfony将使用setter注入来注入控制器中的容器。
代码如下所示:

<?php

use Symfony\Contracts\Service\ServiceSubscriberInterface;

class ParentController implement ServiceSubscriberInterface {
    protected ContainerInterface $container;
    public function setContainer(ContainerInterface) { $this->container = $container; } 

    public static function getSubscribedServices() {
         // This is static, so Symfony can "see" the needed services without instanciating the controller.
         // define some common services here, an example is inside the Symfony AbstractController
    }
}

class ChildController extends ParentController {
    // use custom DI for children.

    public function indexAction {
        // you can fetch services with $this->container->get(...)
    }

}

相关问题