Symfony 4中的动态数据库连接

时间:2019-03-19 13:03:59

标签: doctrine-orm doctrine symfony4 multi-tenant

我正在设置一个多租户Symfony 4应用程序,其中每个租户都有自己的数据库。

我在doctrine.yaml配置中建立了两个数据库连接。连接之一是基于env变量的静态连接。另一个应该具有基于凭据提供程序服务的动态URL。

doctrine:
    dbal:
        connections:
            default:
                url: "@=service('provider.db.credentials').getUrl()"

上面的表达式"@=service('provider.db.credentials').getUrl()"未被解析。

在将"@=service('provider.db.credentials').getUrl()"作为参数注入另一个服务时,getUrl()服务上的provider.db.credentials的结果也被注入。但是,当在连接配置中将其用于主义时,表达式不会被解析。

有人知道如何解决吗?

1 个答案:

答案 0 :(得分:1)

您试图依靠Symfony服务定义的ability来使用表达式定义服务的某些方面。但是,您需要记住,此功能是依赖注入组件的一部分,该组件能够(但不限于)将配置文件用于服务。更准确地说-配置加载程序提供了此功能,例如,您可以查看here来说明Yaml配置加载程序如何处理它。

另一方面,Doctrine捆绑包的配置由 Config 组件提供。 Dependency Injection组件使用与Config组件相同的文件格式的事实可能会给人一种印象,即这些情况是以相同的方式处理的,但实际上它们是完全不同的。

总而言之:Doctrine配置中的表达式无法按您期望的那样工作,因为Doctrine捆绑配置处理器不希望获得Expression Language表达式,并且不支持对其进行处理。

希望上面给出的解释能够回答您的问题-您可能希望获得一些有关如何实际解决问题的信息。

至少有两种方法可以执行此操作,但是选择正确的方法可能需要一些其他信息,这不在此问题的范围内。

  1. 在某种情况下,如果您知道在构建容器时选择哪个连接(您的代码假设是这种情况,但您可能不知道)-那么您应该使用compiler pass机制来更新Doctrine DBAL服务定义(这可能很棘手)。之所以如此重要,是因为配置是在容器构建过程的早期阶段加载的,并且没有提供扩展点。如有必要,您可以查看sources。无论如何,虽然可能,但我不建议您采用这种方式,并且很可能您将不需要它,因为(我想)您需要在运行时而不是在容器构建时选择连接。

  2. 可能更正确的方法是创建自己的DBAL Connection类包装,该包装将维护实际连接列表并根据应用程序的逻辑提供所需的连接。您可以以DBAL sharding功能的实现细节为例。使用wrapper_class配置的dbal键,可以通过Doctrine捆绑包配置直接定义包装器类