Multiple Entity Managers With Symfony

I wanted to use different database connections when accessing content. My main use case was to have a read-only user (e.g. reading from a read-replica) and a user with write permissions to do inserts.

This is something that both Symfony and Doctrine have supported for some time.

Doctrine config (doctrine.yaml)

doctrine:
    dbal:
        default_connection: default
        connections:
            default:
                # configure these for your database server
                url: '%env(resolve:DATABASE_URL_READ)%'
                driver: 'pdo_mysql'
                server_version: '5.7'
                charset: utf8mb4
            db_write:
                # configure these for your database server
                url: '%env(resolve:DATABASE_URL_WRITE)%'
                driver: 'pdo_mysql'
                server_version: '5.7'
                charset: utf8mb4

    orm:
        auto_generate_proxy_classes: true
        default_entity_manager: default

        entity_managers:
            default:
                connection: default
                naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
                mappings:
                    App:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/Entity'
                        prefix: 'App\Entity'
                        alias: App

            db_write:
                connection: db_write
                naming_strategy: doctrine.orm.naming_strategy.underscore_number_aware
                mappings:
                    App:
                        is_bundle: false
                        type: annotation
                        dir: '%kernel.project_dir%/src/Entity'
                        prefix: 'App\Entity'
                        alias: App


This configuration is very similar to the one shown in the Symfony Docs. The main difference is that I want all my entities to be used by both connections.

The Repositories

I recently started creating my repositories like this (which is the recommended approach):

<?php

class EventRepository extends ServiceEntityRepository
{
    public function __construct(ManagerRegistry $registry)
    {
        parent::__construct($registry, Event::class);
    }
}

By using the ServiceEntityRepository it is auto-magically autowired in my dependencies.

Unfortunately, as I wanted to use the same entities with different entity managers, this approach would not work. (see: Issue with multiple entity managers)

The approach that did work, was to extend EntityRepository:

<?php

class EventRepository extends EntityRepository
{

}

Manage Dependencies

By no longer extending ServiceEntityRepository in the repository it means I now have to configure it manually.

Fortunately that is pretty straight-forward:


    ### Read DB Access
    App\Event\Manager\Read\GetEvent:
        class: App\Event\Manager\Read\GetEvent
        arguments:
            - "@=service('doctrine.orm.default_entity_manager').getRepository('App:Event')"

    ### Write DB Access
    App\Event\Manager\Write\UpdateEvent:
        class: App\Event\Manager\Write\UpdateEvent
        arguments:
            - "@=service('doctrine.orm.db_write_entity_manager').getRepository('App:Event')"

The only additional step I had to do to get this configuration to work, was to install the symfony/expression-language package.