【问题标题】:Dynamic database connection in Symfony 4Symfony 4 中的动态数据库连接
【发布时间】:2019-03-19 13:03:59
【问题描述】:

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

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

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

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

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

有人知道如何解决这个问题吗?

【问题讨论】:

    标签: doctrine-orm doctrine symfony4 multi-tenant


    【解决方案1】:

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

    另一方面,您尝试使用的 Doctrine 捆绑配置由 Config 组件提供。 Dependency Injection 组件使用与 Config 组件相同的文件格式这一事实可能会让人觉得这些情况的处理方式相同,但实际上它们完全不同。

    总结一下:Doctrine 配置中的表达式无法按预期工作,因为 Doctrine 捆绑配置处理器不期望获得表达式语言表达式并且不支持处理它们。

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

    至少有两种可能的方法,但选择正确的方法可能需要一些额外的信息,这超出了本问题的范围。

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

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

    【讨论】:

    • 在这种情况下,分片似乎是正确的方法。具体来说,我有一个目录数据库连接。数据库凭据提供程序使用它来获取给定租户的数据库凭据(其名称作为标头传递给我的 API)。这里最大的挑战是如何将学说分片机制集成到 Symfony 中。
    • 分片配置作为 DBAL 配置的一部分直接提供到 Doctrine 包中,请查看 shards 配置 section
    • 我想我现在了解分片系统了。尽管似乎必须在 YAML 中定义分片。但在我的情况下,有一个目录数据库,其中包含每个租户/分片的数据库凭据。
    • 分片在你的情况下不是一个合适的方法,我已经提到了它,因为它与你需要自己编写的代码非常相似。您可以参考它作为示例,但它不会直接对您有用
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-09
    • 1970-01-01
    • 2016-11-11
    • 2016-01-16
    • 1970-01-01
    相关资源
    最近更新 更多