Как можно разделить Entity Manager в Doctrine для обработки различных запросов?

Как можно организовать разделение запросов на чтение и запись в базу данных, использовав разные EntityManager для этих операций, не прибегая к рефакторингу методов, выполняющих данные действия? Возможно ли это реализовать на уровне конфигурации Doctrine?
  • 22 сентября 2024 г. 9:43
Ответы на вопрос 2
Да, разделение EntityManager в Doctrine для обработки различных запросов можно реализовать, используя паттерн "Command Query Responsibility Segregation" (CQRS) или же простую архитектуру, где операции чтения и записи обрабатываются разными EntityManager. Для этого можно настроить подключения и конфигурацию Doctrine в вашем приложении таким образом, чтобы они использовали разные EntityManager для чтения и записи.

Вот базовые шаги, как это сделать:

### 1. Настройка нескольких EntityManager

В файле конфигурации Doctrine вы можете определить два разных EntityManager. Например:

```yaml
# doctrine.yaml

doctrine:
    dbal:
        default_connection: default

    connections:
        default:
            driver: 'pdo_mysql'
            host: '%env(DB_HOST)%'
            dbname: '%env(DB_NAME)%'
            user: '%env(DB_USER)%'
            password: '%env(DB_PASSWORD)%'
            port: 3306

        read:
            driver: 'pdo_mysql'
            host: '%env(DB_READ_HOST)%'
            dbname: '%env(DB_READ_NAME)%'
            user: '%env(DB_READ_USER)%'
            password: '%env(DB_READ_PASSWORD)%'
            port: 3306

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

        read:
            connection: read
            mappings:
                App\Entity:
                    is_bundle: false
                    type: annotation
                    dir: '%kernel.project_dir%/src/Entity'
                    prefix: 'App\Entity'
                    alias: App
```

### 2. Использование различных EntityManager

Теперь вы можете использовать разные EntityManager в зависимости от того, выполняете ли вы операцию чтения или записи. Например:

```php
use Doctrine\ORM\EntityManagerInterface;

class SomeService
{
    private $entityManager;
    private $readEntityManager;

    public function __construct(EntityManagerInterface $entityManager, EntityManagerInterface $readEntityManager)
    {
        $this->entityManager = $entityManager;
        $this->readEntityManager = $readEntityManager;
    }

    public function saveEntity($entity)
    {
        // Используем EntityManager для записи
        $this->entityManager->persist($entity);
        $this->entityManager->flush();
    }

    public function getEntity($id)
    {
        // Используем EntityManager для чтения
        return $this->readEntityManager->find(Entity::class, $id);
    }
}
```

### 3. Альтернативный подход с помощью Proxy

Еще один вариант — создать прокси-слой для управлением чтением и записью. Например:

```php
class EntityManagerFactory
{
    private $writeEntityManager;
    private $readEntityManager;

    public function __construct(EntityManagerInterface $writeEntityManager, EntityManagerInterface $readEntityManager)
    {
        $this->writeEntityManager = $writeEntityManager;
        $this->readEntityManager = $readEntityManager;
    }

    public function getEntityManager($isRead = true): EntityManagerInterface
    {
        return $isRead ? $this->readEntityManager : $this->writeEntityManager;
    }
}
```

После этого можно использовать `EntityManagerFactory` для получения подходящего EntityManager в зависимости от запроса.

### Заключение

Важно отметить, что такой подход поможет разделить логику чтения и записи, что повысит масштабируемость вашего приложения. Однако необходимо будет аккуратно управлять состоянием данных и кэшированием, так как при использовании разных EntityManager могут возникнуть ситуации, когда данные, записанные в одну EntityManager, не будут видны в другой, если они не были сброшены или обновлены.
Попробуйте вариант из этой статьи. Там Symfony 4, но сама идея не должна была измениться. 

https://pavlakis.dev/posts/multiple-entity-manager...

К сожалению, всё, что раньше работало через autowiring, придётся конфигурировать вручную.

А вот статья из доки Symfony на эту тему. Здесь можно просто посмотреть, не было ли каких-то изменений
https://symfony.com/doc/current/doctrine/multiple_...
Похожие вопросы