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.
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'
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.
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
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?
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)