使用多个时自动装配特定的 DBAL 连接

问题描述 投票:0回答:6

我正在使用 Doctrine 2,其中有多个 DBAL 连接。我在 ORM 中也有多个 EntityManager。

我需要能够以某种方式将特定的 DBAL 连接自动连接到其他 Symfony 3 服务中。

我可以使用 EntityManagerDecorator 自动装配任何 EntityManager,但不知道如何对连接执行相同的操作。我可以从 EntityManager 获得连接,但我不认为这是正确的方法。

symfony doctrine dbal
6个回答
10
投票

您可以为学说连接指定包装类,不需要代理类:

#config.yml
doctrine:
    dbal:
        connections:
            default:
                wrapper_class: AppBundle\Connections\ConnectionDefault
                ...
            second:
                wrapper_class: AppBundle\Connections\ConnectionSecond
                ...

连接应延长

Doctrine\DBAL\Connection

<?php

namespace AppBundle\Connection;

use Doctrine\DBAL\Connection;

class ConnectionDefault extends Connection
{

}

class ConnectionSecond extends Connection
{

}

并创建服务别名:

#services.yml
services:
    ...
    AppBundle\Connections\ConnectionDefault: '@doctrine.dbal.default_connection'
    AppBundle\Connections\ConnectionSecond: '@doctrine.dbal.second_connection'

然后您可以通过键入提示将所需的连接注入到服务中:

class MyService {
    public function __construct(ConnectionDefault $connection) {...}
}

class MyOtherService {
    public function __construct(ConnectionSecond $connection) {...}
}

4
投票

我遇到了同样的问题,并更准确地测试了它的工作原理和原因。

使用代理进行许多 DBAL 连接

编辑: 我做了一些代理抽象类。现在我的每个连接类都继承自该代理。效果很好:)

<?php

#src/AppBundle/Connections/ConnectionProxy.php

namespace AppBundle\Connections;

use Doctrine\DBAL\Connection;

abstract class ConnectionProxy
{
    private $connection;

    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
    }

    public function __call($method, $arguments)
    {
        if (is_callable(array($this->connection, $method))) {
            return call_user_func_array(array($this->connection, $method), $arguments);
        } else {
            return new \Exception("Call to undefined method '{$method}'");
        }
    }
}

我的连接默认类别:

<?php

#src/AppBundle/Connections/ConnectionDefault.php

namespace AppBundle\Connections;

class ConnectionDefault extends ConnectionProxy
{

}

第二个连接:

<?php

namespace AppBundle\Connections;

class ConnectionSecond extends ConnectionProxy
{

}

然后我已手动添加到我的服务文件中,用于我的所有连接(2 个连接):

AppBundle\Connections\ConnectionDefault:
    public: true
    class: AppBundle\Connections\ConnectionDefault
    arguments: ['@doctrine.dbal.default_connection']

AppBundle\Connections\ConnectionSecond:
    public: true
    class: AppBundle\Connections\ConnectionSecond
    arguments: ['@doctrine.dbal.second_connection']

然后,当我使用它们的类型时,我的连接会自动连接

class SaveEvent
{
    /** @var  Connection */
    private $connection;

    public function __construct(ConnectionDefault $connection)
    {
        $this->connection = $connection;
    }
    .....

为每项服务注入连接

最简单的选项 - 但需要单独创建每个服务并注入连接名称 - 这意味着在服务文件(app/config/services.yml)中手动连接参数**,例如

AppBundle\Classes\SaveEvent:
    public: true
    arguments:
      - '@doctrine.dbal.[connection_name]_connection'

其中connection_name是您的连接名称。 在下面的示例中,我们在 config.yml 中有两个连接,该值可以是“default”或“database2”:

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
              driver: pdo_sqlite
              charset: UTF8
              path: '%database_path%'
            database2:
              driver: pdo_sqlite
              charset: UTF8
              path: '%database_path%'

仅适用于一个 DBAL 连接

当我们只有一个连接时,DBAL 连接的自动装配工作正常。如果我只保留默认连接(从 config.yml 中删除连接数据库 2)并在 app/config/services.yml 中添加一些要自动连接的路径:

AppBundle\Classes\:
    resource: '../../src/AppBundle/Classes'
    public: true

如果我在我的类中使用类型类 Doctrine\DBAL\Connection ,这意味着我想要注入默认连接(@doctrine.dbal.default_connection),因为我只有一个连接。

namespace AppBundle\Classes;

use Doctrine\DBAL\Connection;

class SaveEvent
{
    /** @var  Connection */
    private $connection;

    public function __construct(Connection $connection)
    {
        $this->connection = $connection;
    }

// …
}

回答

//已编辑 SimPod,您问题的答案是 使用代理为许多 DBAL 连接工作 为每个服务注入连接,如上所述。

我知道您已经解决了这个问题,但我的回答可以帮助其他人。


4
投票

更简单的解决方案可以是:

#services.yml
services:
    _defaults:
        bind:
            $dbSecond: '@doctrine.dbal.second_connection'

在控制器或服务中使用:

public function my(Request $request, Connection $dbSecond)

2
投票

每个 DBAL 连接始终可以在具有以下标识符的服务容器中访问:

doctrine.dbal.[name]_connection

其中

[name]
是连接名称

https://github.com/doctrine/DoctrineBundle/blob/master/Resources/doc/configuration.rst#doctrine-dbal-configuration


0
投票

3.4 版本中有一个新功能,使该过程变得更加容易。 请参阅:Symfony 3.3 - 实体管理器注入到具有多个数据库的服务中?


0
投票

在 Symfony 的最新版本(目前为版本 7)中,有更清晰的内置方法可以实现此目的。

这两者都需要您在 Doctrine 配置文件中配置连接如此处所示

方法一:自动装配连接

来自 Doctrine Bundle 的 Symfony 文档

您可以通过使用以下语法对服务参数进行类型提示来自动装配不同的连接:Doctrine\DBAL\Connection $Connection。例如,要注入名为 buy_logs 的连接,请使用以下命令:

// src/Controller/SomeController.php
use Doctrine\DBAL\Connection;

class SomeController
{
    public function __construct(Connection $purchaseLogsConnection)
    {
        $this->connection = $purchaseLogsConnection;
    }
}

方法二:注入ManagerRegistry类

再次来自 Symfony 文档

在控制器中,您可以使用 getConnection() 方法和连接名称来访问它:

// src/Controller/SomeController.php
use Doctrine\Persistence\ManagerRegistry;

class SomeController
{
    public function someMethod(ManagerRegistry $doctrine): void
    {
        $connection = $doctrine->getConnection('customer');
        $result = $connection->fetchAllAssociative('SELECT name FROM customer');

        // ...
    }
}

最后一个方法,与前一个方法一样,也可以在服务中使用,而不仅仅是在控制器中。

© www.soinside.com 2019 - 2024. All rights reserved.