【问题标题】:How to access dependency injection container in Symfony 4 without actual injection?如何在没有实际注入的情况下访问 Symfony 4 中的依赖注入容器?
【发布时间】:2019-05-22 18:54:13
【问题描述】:

我有一个用 Symfony 4 编写的项目(如果需要,可以更新到最新版本)。其中我有类似的情况:

有一个控制器向外部系统发送请求。它遍历数据库中的记录并为每一行发送一个请求。为此,有一个连接到外部系统的MagicApiConnector 类,并且对于每个请求都有一个XxxRequest 类(如FooRequestBarRequest 等)。

所以,像这样的一般:

foreach ( $allRows as $row ) {
    $request = new FooRequest($row['a'], $row['b']);
    $connector->send($request);
}

现在为了完成所有的参数填充魔法,请求需要访问一个在 Symfony 的 DI 中定义的服务。控制器本身既不知道也不关心这个服务,但请求需要它。

我的请求类如何访问此服务?我不想将它设置为控制器的依赖项 - 我可以,但这似乎有点尴尬,因为控制器真的不关心它,只会通过它。这是请求的实现细节,我觉得它不应该给请求的用户带来这个样板要求的负担。

话说回来,有时您需要以更大的利益的名义做出牺牲,所以也许这就是其中一种情况?感觉自己是在“逆水行舟”,没有掌握一些思想观念。


补充:好的,完整的血腥细节,没有简化。

这一切都发生在两个自制系统的背景下。我们称它们为 OldApp 和 NewApp。两者都是 API,NewApp 正在调用 OldApp。 API 是简单的 REST/JSON 风格。 OldApp 不是基于 Symfony 构建的(大多数情况下甚至不使用框架),NewApp 是。我的问题是关于 NewApp。

OldApp API 的身份验证有三种不同的风格,如果需要,将来可能会变得更多(它还没有死!)不同的 API 调用使用不同的身份验证方法;有时甚至可以使用不同的方法使用相同的 API 调用(取决于调用它的人)。所有这些身份验证方法也是自制的。一个使用 POST 字段,另一个使用自定义 HTTP 标头,第三个不记得了。

现在,NewApp 被分发给许多用户的 Android 应用程序调用。 Android 应用实际上同时使用了 NewApp 和 OldApp。当它调用 NewApp 时,它会传递额外的 HTTP 标头以及 OldApp 的身份验证数据(方法 1)。因此,NewApp 可以为 OldApp 冒充 Android 应用用户。此外,NewApp 还需要使用 OldApp 的一个用户自己无法调用的特殊命令(权限问题)。因此,它对该命令使用不同的身份验证机制(方法 2)。该命令的参数存储在本地配置(环境变量)中。

在我之前,一位同事创建了APIConnectorAPICommand 的方案,您可以在其中将连接器作为依赖项并根据需要创建命令实例。连接器实际执行 HTTP 请求;命令告诉它要发送哪些 POST 字段和哪些标头。我希望保留这个方案。

但是现在不同的身份验证机制如何适应这一点?每个命令都应该能够将它需要的东西传递给连接器;并且这些机制应该可用于多个命令。但是一个需要访问传入的请求,另一个需要访问配置参数。两者都不是通过 DI 实例化的。如何优雅地做到这一点?

【问题讨论】:

    标签: symfony dependency-injection


    【解决方案1】:

    这听起来像是工厂的工作。

    function action(MyRequestFactory $requestFactory)
    {
        foreach ( $allRows as $row ) {
            $request = $requestFactory->createFoo($row['a'], $row['b']);
            $connector->send($request);
        }
    

    工厂本身作为服务并作为正常 Symfony 设计的一部分注入到控制器中。无论需要什么额外的服务,都将被注入工厂。反过来,工厂可以在创建请求时提供各个请求可能碰巧需要的任何服务。

    【讨论】:

    • 嗯,但可能有几十个不同的请求......这是否意味着为每个请求建立一个单独的工厂?还是一个拥有几十种方法的大师工厂?也许 DI 本身可以充当工厂?我可以要求它创建一个新的服务实例吗?实际上,这将把它变成一个服务定位器。
    • 你当然不想要几十个工厂。但是service locator 可能确实是要走的路。这部分取决于您的请求所需的这个相当神秘的参数填充服务的作用。这个question/answer 可能相关也可能不相关。
    • 你可以configure your services to be non-shared。这意味着每次从容器或定位器中提取服务时,您都会获得不同的实例。
    • 我试图简化它......事实上,请求使用不同的方法对 API 进行身份验证。有些会使用当前请求标头中的数据。其他人会使用一些环境变量。其他人可能会做其他事情。我希望对调用者隐藏这个细节。我......我想我可以让MagicApiConnector(它本身就是一个适当的依赖)来做额外的魔法......但它有点像是违反了单一责任原则。现在有两个类必须了解底层身份验证机制...
    • 出于某种原因,我总是后悔尝试回答 foo/bar 类型的问题。我试图解决您问题的标题以及您问题中的代码。但是由于您最新的 cmets,我不知道您实际上要完成什么。关于身份验证?考虑以您想要完成的实际示例开始一个问题。
    猜你喜欢
    • 2018-07-12
    • 1970-01-01
    • 2019-01-05
    • 1970-01-01
    • 2020-12-08
    • 2012-11-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多