Cómo trabajar con múltiples gestores de entidad y conexiones

Puedes utilizar múltiples gestores de entidad de Doctrine o conexiones en una aplicación Symfony2. Esto es necesario si estás utilizando diferentes bases de datos e incluso proveedores con conjuntos de entidades totalmente diferentes. En otras palabras, un gestor de entidad que se conecta a una base de datos deberá administrar algunas entidades, mientras que otro gestor de entidad conectado a otra base de datos puede manejar el resto.

Nota

Usar varios gestores de entidad es bastante fácil, pero más avanzado y generalmente no se requiere. Asegúrate de que realmente necesitas varios gestores de entidad antes de añadir complejidad a ese nivel.

El siguiente código de configuración muestra cómo puedes configurar dos gestores de entidad:

  • YAML
    doctrine:
        dbal:
            default_connection:   default
            connections:
                default:
                    driver:   "%database_driver%"
                    host:     "%database_host%"
                    port:     "%database_port%"
                    dbname:   "%database_name%"
                    user:     "%database_user%"
                    password: "%database_password%"
                    charset:  UTF8
                customer:
                    driver:   "%database_driver2%"
                    host:     "%database_host2%"
                    port:     "%database_port2%"
                    dbname:   "%database_name2%"
                    user:     "%database_user2%"
                    password: "%database_password2%"
                    charset:  UTF8
    
        orm:
            default_entity_manager:   default
            entity_managers:
                default:
                    connection:       default
                    mappings:
                        AcmeDemoBundle: ~
                        AcmeStoreBundle: ~
                customer:
                    connection:       customer
                    mappings:
                        AcmeCustomerBundle: ~
    
  • XML
    <?xml version="1.0" encoding="UTF-8"?>
    
    <srv:container xmlns="http://symfony.com/schema/dic/doctrine"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:srv="http://symfony.com/schema/dic/services"
        xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd
                            http://symfony.com/schema/dic/doctrine http://symfony.com/schema/dic/doctrine/doctrine-1.0.xsd">
    
        <config>
            <dbal default-connection="default">
                <connection name="default"
                    driver="%database_driver%"
                    host="%database_host%"
                    port="%database_port%"
                    dbname="%database_name%"
                    user="%database_user%"
                    password="%database_password%"
                    charset="UTF8"
                />
    
                <connection name="customer"
                    driver="%database_driver2%"
                    host="%database_host2%"
                    port="%database_port2%"
                    dbname="%database_name2%"
                    user="%database_user2%"
                    password="%database_password2%"
                    charset="UTF8"
                />
            </dbal>
    
            <orm default-entity-manager="default">
                <entity-manager name="default" connection="default">
                    <mapping name="AcmeDemoBundle" />
                    <mapping name="AcmeStoreBundle" />
                </entity-manager>
    
                <entity-manager name="customer" connection="customer">
                    <mapping name="AcmeCustomerBundle" />
                </entity-manager>
            </orm>
        </config>
    </srv:container>
    
  • PHP
    $container->loadFromExtension('doctrine', array(
        'dbal' => array(
            'default_connection' => 'default',
            'connections' => array(
                'default' => array(
                    'driver'   => '%database_driver%',
                    'host'     => '%database_host%',
                    'port'     => '%database_port%',
                    'dbname'   => '%database_name%',
                    'user'     => '%database_user%',
                    'password' => '%database_password%',
                    'charset'  => 'UTF8',
                ),
                'customer' => array(
                    'driver'   => '%database_driver2%',
                    'host'     => '%database_host2%',
                    'port'     => '%database_port2%',
                    'dbname'   => '%database_name2%',
                    'user'     => '%database_user2%',
                    'password' => '%database_password2%',
                    'charset'  => 'UTF8',
                ),
            ),
        ),
    
        'orm' => array(
            'default_entity_manager' => 'default',
            'entity_managers' => array(
                'default' => array(
                    'connection' => 'default',
                    'mappings'   => array(
                        'AcmeDemoBundle'  => null,
                        'AcmeStoreBundle' => null,
                    ),
                ),
                'customer' => array(
                    'connection' => 'customer',
                    'mappings'   => array(
                        'AcmeCustomerBundle' => null,
                    ),
                ),
            ),
        ),
    ));
    

En este caso, hemos definido dos gestores de entidad y los llamamos default y customer. El gestor de entidad default administra cualquier entidad en los paquetes AcmeDemoBundle y AcmeStoreBundle, mientras que el gestor de entidad customer gestiona cualquiera en el paquete AcmeCustomerBundle. También definiste dos conexiones, una para cada gestor de entidad.

Nota

Cuando trabajas con múltiples conexiones y gestores de entidad, debes ser explícito sobre cual configuración deseas. Si omites el nombre de la conexión o gestor de entidad, se usa el predeterminado (es decir, default).

Cuando trabajes con múltiples conexiones para crear tu base de datos:

# Juega sólo con la conexión «default»
$ php app/console doctrine:database:create

# Juega sólo con la conexión «customer»
$ php app/console doctrine:database:create --connection=customer

Cuándo trabajas múltiple gestores de entidad para actualizar tu esquema:

# Juega sólo con asociaciones «default»
$ php app/console doctrine:schema:update --force

# Juega sólo con asociaciones «customer»
$ php app/console doctrine:schema:update --force --em=customer

Si omites el nombre del gestor de la entidad al consultar por él, se devuelve el gestor de entidad predeterminado (es decir, default):

class UserController extends Controller
{
    public function indexAction()
    {
        // ambos devuelven el gestor de entidad "predefinido"
        $em = $this->get('doctrine')->getManager();
        $em = $this->get('doctrine')->getManager('default');

        $customerEm =  $this->get('doctrine')->getManager('customer');
    }
}

Ahora puedes utilizar Doctrine tal como lo hiciste antes — con el gestor de entidad default para persistir y recuperar las entidades que gestiona y el gestor de entidad customer para persistir y recuperar sus entidades.

Lo mismo aplica para llamadas al repositorio:

class UserController extends Controller
{
    public function indexAction()
    {
        // Recupera un repositorio gestionado por el em 'predefinido'
        $products = $this->get('doctrine')
                         ->getRepository('AcmeStoreBundle:Product')
                         ->findAll()
        ;

        // La manera explícita para tratar con el em 'predefinido'
        $products = $this->get('doctrine')
                         ->getRepository('AcmeStoreBundle:Product',
                               'default')
                         ->findAll();

        // Recupera un repositorio gestionado por el em 'customer'
        $customers = $this->get('doctrine')
                          ->getRepository('AcmeCustomerBundle:Customer',
                                'customer')
                          ->findAll()
        ;
    }
}
Bifúrcame en GitHub