No es raro tener múltiples bases de datos para un solo proyecto. Normalmente, cuando se usan dos bases de datos, las entidades pueden organizarse en directorios específicos que se declaran en tu configuración. En este caso, el sistema utilizará la conexión configurada para el directorio de la entidad. Puedes ver un ejemplo de múltiples conexiones aquí Symfony 4 / Sonata: gestionando una interfaz de administración multi-servidor
Supongamos que queremos apuntar a una base de datos de solo lectura (una réplica) cada vez que utilicemos una entidad. Habría varias maneras de proceder.
Comencemos por configurar múltiples configuraciones.
DATABASE_MASTER=mysql://login:password@db_master.host:3306/db_master?serverVersion=mariadb-10.10.2
DATABASE_SLAVE=mysql://login:password@db_slave.host:3306/db_slave?serverVersion=mariadb-10.10.2
doctrine:
dbal:
default_connection: db_master
types:
json: Sonata\Doctrine\Types\JsonType
connections:
db_master:
url: '%env(resolve:DATABASE_MASTER)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
db_slave:
url: '%env(resolve:DATABASE_SLAVE)%'
driver: 'pdo_mysql'
server_version: '5.7'
charset: utf8
default_table_options:
charset: utf8mb4
collate: utf8mb4_unicode_ci
orm:
auto_generate_proxy_classes: true
default_entity_manager: default
entity_managers:
default:
connection: db_master
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: true
mappings:
ApplicationSonataMediaBundle: ~
SonataMediaBundle: ~
Main:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity\'
alias: Main
slave:
connection: db_slave
naming_strategy: doctrine.orm.naming_strategy.underscore
auto_mapping: false
mappings:
delef:
is_bundle: false
type: annotation
dir: '%kernel.project_dir%/src/Entity'
prefix: 'App\Entity'
alias: delef
Para apuntar a una conexión específica, podríamos modificar nuestro
código y apuntar a nuestra conexión para cada solicitud de
Doctrine.
Aquí ya hay dos métodos para apuntar a nuestro
servidor esclavo para cada solicitud:
<?php
namespace App\Repository;
use App\Entity\Whatever;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\EntityRepository;
use Psr\Container\ContainerInterface;
class WhateverRepository extends ServiceEntityRepository
{
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
public function selectSlave()
{
return $this->container->get('doctrine')
->getManager('slave')
->createQueryBuilder('w')
->andWhere('w.exampleField = :val')
->setParameter('val', $value)
->orderBy('w.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult();
}
}
O de nuevo:
<?php
namespace App\Repository;
use App\Entity\Whatever;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\EntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
class WhateverRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
$this->registry = $registry;
}
public function selectSlave()
{
return $this->registry->
->getManager('slave')
->createQueryBuilder('w')
->andWhere('w.exampleField = :val')
->setParameter('val', $value)
->orderBy('w.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult();
}
}
Pero esto implica modificar todos nuestros métodos uno por uno para
apuntar a nuestra conexión.
Un método más global consiste
en definir nuestra conexión en nuestro constructor para todo
nuestro repositorio.
<?php
namespace App\Repository;
use App\Entity\Whatever;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\ORM\EntityRepository;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityRepository;
class WhateverRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
$this->registry = $registry;
$manager = $registry->getManager('slave');
parent::__construct($registry, Whatever::class);
EntityRepository::__construct(
$manager,
$manager->getClassMetadata(Whatever::class)
);
}
public function selectSlave()
{
return $this->createQueryBuilder('w')
->andWhere('w.exampleField = :val')
->setParameter('val', $value)
->orderBy('w.id', 'ASC')
->setMaxResults(10)
->getQuery()
->getResult();
}
}
Al final, puedes elegir entre los diferentes métodos
disponibles según las necesidades de tu aplicación.