Symfony 2:依赖注入和特征

Posted

技术标签:

【中文标题】Symfony 2:依赖注入和特征【英文标题】:Symfony 2: dependency injection and traits 【发布时间】:2012-07-13 15:25:40 【问题描述】:

我正在尝试找到一种方法来使用 Symfony 2 Dependency Injection component 和新的 php 5.4 traits。

长话短说(实际上不是那么短),我的项目已经解耦了 View 类,它们都有自己的特定构造函数。每个视图可以使用零个或多个视图助手,它们被定义为特征:

trait TranslatorHelper

    /**
     * @var Translator
     */
    protected $translator;

    /**
     * @param Translator $translator
     */
    protected function setTranslator(Translator $translator)
    
        $this->translator = $translator;
    

    /**
     * @param string $text
     * @return string
     */
    public function translate($text)
    
        return $this->translator->translate($text);
    

-

class UserEditView extends AbstractView

    use TranslatorHelper;

    public function __construct(User $user, UserEditForm $form)
    
        // ...
    

我想在我的控制器renderView() 中有一个方法,它在渲染视图之前根据视图类使用的所有特征执行setter 注入:

class Controller

    public function renderView(View $view)
    
        // Check what traits are used by $view, and inject their dependencies
        // ...


        // Then render the View
        return $view->render();
    

您知道如何使用DependencyInjection 组件执行此操作吗?

主要问题显然是视图不会由 DI 容器创建,但可以在应用程序流中的任何位置创建。只有在它们被渲染之前才需要注入依赖。

最后一点:我不依赖于 Symfony 组件。其他 DI 容器上的任何线索也将不胜感激。

【问题讨论】:

您可以尝试使用 AOP 进行 DI:github.com/schmittjoh/JMSAopBundle/blob/master/Resources/doc/…,通过属性和参数的注释自动注入服务。 问题是我想让视图助手(例如TranslatorHelper)保持通用,所以理想情况下它们不应该包含容器中依赖项的项目特定ID。 【参考方案1】:

Symfony 3.3 引入了自动装配服务的概念。 您所要做的就是在您的 trait 中创建一个 setter 函数并添加 @required 注释。

private $entityManager;

/**
 * @required
 * @param EntityManagerInterface $entityManager
 */
public function setEntityManager(EntityManagerInterface $entityManager)

    $this->entityManager = $entityManager;

参考:https://symfony.com/doc/current/service_container/autowiring.html#autowiring-other-methods-e-g-setters

【讨论】:

【参考方案2】:

我认为特质不应该用于以这种方式进行 DI。在类似的场景中我会做的是在实现特征的视图类中使用构造函数注入(甚至设置器也可以,如果可能的话,即使是强悍的构造函数也更好)。

如果您认为类实现的特征是在应用程序执行之前静态定义的,那么您实际上不需要检查特征来执行动态注入。在运行之前你会知道你需要什么服务,只要把 trait 看作是与某个具体方法的接口。

【讨论】:

我明白你的意思,但是我担心的是我想让 View 构造函数清除任何特定于 Helper 的依赖项(我希望控制器显式使用 View 构造函数来仅传递所需的变量视图本身,而不必担心助手)。另外,我可能会有数百个 View 类,都使用相同的 ~3 视图助手。所以我希望能够根据 Trait 名称进行注入。例如,我想在我的配置中定义所有使用 TranslatorHelper 特征的类都将使用 translator 容器键指向的 Translator。 在这种情况下,您可以做的是使用 DI 标记:定义一个标记和一个编译器通道,该通道寄存器为每个帮助器特征执行正确的设置器依赖项。 Symfony 文档最近发布了一些关于高级 DIC 使用的文档(例如编译器通道和标签)。它不是基于特征自动注入(我认为唯一的方法是使用非常慢的反射),但它非常整洁。

以上是关于Symfony 2:依赖注入和特征的主要内容,如果未能解决你的问题,请参考以下文章

树枝扩展中的 Symfony 依赖注入

Symfony依赖注入将类型的所有类作为参数注入

云客Drupal8源码分析之服务容器及Symfony依赖注入组件

Symfony2功能测试用例不包括自定义依赖注入配置参数

使用自定义 Doctrine 2 hydrator 进行依赖注入

译深入研究 Laravel 的依赖注入容器