问题
I'm using Doctrine 2 where I have multiple connections for DBAL. I have also multiple EntityManagers in ORM.
I need to be able to somehow autowire specific DBAL connection into other Symfony 3 services.
I can autowire any EntitiyManager using EntityManagerDecorator but don't know how to do the same with connection. I'm able to get the connection from EntityManager but I don't think it's the way to go.
回答1:
You can specify wrapper class for doctrine connections, no proxy class needed:
#config.yml
doctrine:
dbal:
connections:
default:
wrapper_class: AppBundle\Connections\ConnectionDefault
...
second:
wrapper_class: AppBundle\Connections\ConnectionSecond
...
Connections should extend Doctrine\DBAL\Connection
:
<?php
namespace AppBundle\Connection;
use Doctrine\DBAL\Connection;
class ConnectionDefault extends Connection
{
}
class ConnectionSecond extends Connection
{
}
and create service aliases:
#services.yml
services:
...
AppBundle\Connections\ConnectionDefault: '@doctrine.dbal.default_connection'
AppBundle\Connections\ConnectionSecond: '@doctrine.dbal.second_connection'
回答2:
I had the same issue and tested it more precisely what works and why.
WORK FOR MANY DBAL CONNECTIONS USING PROXY
EDIT: I have done some proxy abstract class. Now each my connection class inherited from this proxy. It works fine :)
<?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}'");
}
}
}
My connection default class:
<?php
#src/AppBundle/Connections/ConnectionDefault.php
namespace AppBundle\Connections;
class ConnectionDefault extends ConnectionProxy
{
}
second connection:
<?php
namespace AppBundle\Connections;
class ConnectionSecond extends ConnectionProxy
{
}
Then I have added manually to my services file, for all my connections(2 connections) :
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']
Then my connections are automatically autowiring when I use their types
class SaveEvent
{
/** @var Connection */
private $connection;
public function __construct(ConnectionDefault $connection)
{
$this->connection = $connection;
}
.....
INJECT CONNECTIONS FOR EACH SERVICE
The simplest option - but require create each service separately and inject connection name - it means manually wiring Arguments** in your services file(app/config/services.yml) e.g.
AppBundle\Classes\SaveEvent:
public: true
arguments:
- '@doctrine.dbal.[connection_name]_connection'
where connection_name is your connection name. In below example we have two connections in config.yml and this value could be “default” or “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%'
WORK FOR ONLY ONE DBAL CONNECTION
Autowiring for DBAL Connections works fine when we have only one connection. If I leave only default connection(remove connection database 2 from config.yml) and add some path to be autowired in app/config/services.yml:
AppBundle\Classes\:
resource: '../../src/AppBundle/Classes'
public: true
and if I use as type class Doctrine\DBAL\Connection in my Class, it means that I want inject default connection(@doctrine.dbal.default_connection) because I have the only one connection.
namespace AppBundle\Classes;
use Doctrine\DBAL\Connection;
class SaveEvent
{
/** @var Connection */
private $connection;
public function __construct(Connection $connection)
{
$this->connection = $connection;
}
// …
}
ANSWER
// Edited SimPod, the answer to your question is WORK FOR MANY DBAL CONNECTIONS USING PROXY or INJECT CONNECTIONS FOR EACH SERVICE as I described above.
I'm aware that you have managed with that issue but my answer can help the others.
回答3:
Each DBAL connection is always accessible in service container with the following identifier:
doctrine.dbal.[name]_connection
where [name]
is the connection name
https://github.com/doctrine/DoctrineBundle/blob/master/Resources/doc/configuration.rst#doctrine-dbal-configuration
回答4:
there is a new functionality in version 3.4 which gives the process much easier. See : Symfony 3.3 - Entity Manager injection into services with multiple database?
回答5:
A simpler solution can be:
#services.yml
services:
_defaults:
bind:
$dbSecond: '@doctrine.dbal.second_connection'
Use in controller or services:
public function my(Request $request, Connection $dbSecond)
来源:https://stackoverflow.com/questions/46235336/autowire-specific-dbal-connection-when-using-multiple-of-them