Uploaded image for project: 'eZ Publish / Platform'
  1. eZ Publish / Platform
  2. EZP-30683

Using Entity Manager with many databases

    XMLWordPrintable

Details

    • Icon: Bug Bug
    • Resolution: Unresolved
    • Icon: High High
    • None
    • 2.5.1
    • Database related
    • None

    Description

      When we are in multi SiteAccess configuration we can have a different database per SiteAccesses.
      We can manage different Repositories => that is working fine.

      But as soon as we want to inject Doctrine ORM Entities we are in a complex situation.
      Indeed, the EntityManager is only setup with the “default” connection, and there is no “other” EntityManager automatically generated.

      I first thought that would be easy to inject, or even to create a new factory but I failed. In fact, we can’t use the AutoMapping for more than one Connection.

      I think my use case is valid:

      • I want to install a Bundle that is using Doctrine Entities and the bundle must be able to rely on an Entity Manager that could be different per Connection.

      I might have missed something but I think that it will be complex to manage actually, I think the concept of sharing the same mapping for 2 Managers in 2 different databases might be conceptually weird for Doctrine.

      I did not test to create a compiler pass to create/duplicate everything manually, I would like to have your input first.

      This is a MUST have for eZ and for bundle developments that are using simple Doctrine ORM.

      Let me know.

      Best,

      EDIT, as Andre R. asked me more details here:

      I guess we should find a solution to this for 2.5 up, is it something we can handle? We might need to overload Entity manager definition  to force it to use the SA aware DBAL connection service, where I’ don’t know as we don’t use ORM in kernel. Maybe a ORM-tools package or similar we can rely on.
      
      @plopix Could you add code examples in the Issue so we can follow it easier in order to be able to priorticie this?
      
      1. How you you ask for the Entity manager, and how are you supposed to (from ORM side) to ask for one on another connection?
      2. In case you know, how would you expect this to be solved?
      3. Maybe add some pseudo code on how you expect this to work _(given you provided example in 1. how it works today, so it’s possible to see the diff)_
      

      So to give you more:

      Using the EntityManager is just really easy using the Symfony Autowiring concept, here is an example:
      https://github.com/Novactive/NovaeZMailingBundle/blob/master/bundle/Controller/Admin/CampaignController.php#L48

      => as explained we get the "default" one.

      I thought I would be able to fix that, as I thought we had 1 Entity Manager setup per Connection but that is not the case.
      Here the way I thought about it:

      First, we trick the default service to use a factory

          Doctrine\ORM\EntityManagerInterface:
              lazy: true
              factory: 'Novactive\Bundle\eZMailingBundle\Core\SiteAccessAwareEntityManagerFactory:get'
      

      Then we return the correct one depending on the SiteAccess.

          /**
           * @var Registry
           */
          private $registry;
      
          /**
           * @var RepositoryConfigurationProvider
           */
          private $repositoryConfigurationProvider;
      
          public function __construct(
              Registry $registry,
              RepositoryConfigurationProvider $repositoryConfigurationProvider
      
          ) {
              $this->registry                        = $registry;
              $this->repositoryConfigurationProvider = $repositoryConfigurationProvider;
          }
      
          private function getConnectionName(): string
          {
              $config = $this->repositoryConfigurationProvider->getRepositoryConfig();
      
              return $config['storage']['connection'];
          }
      
          public function get(): EntityManagerInterface
          {
              $connectionName = $this->getConnectionName();
      
              return $this->registry->getManager($connectionName);
          }
      

      Theory is good I guess BUT this is not working as the EntityManager for the second Connection is not created.

      So I tried to do it:

      doctrine:
          dbal:
              connections:
                  default:
                      driver: '%database_driver%'
                      host: '%database_host%'
                      port: '%database_port%'
                      dbname: '%database_name%'
                      user: '%database_user%'
                      password: '%database_password%'
                      charset: '%database_charset%'
                  default2:
                      driver: '%database_driver%'
                      host: '%database_host%'
                      port: '%database_port%'
                      dbname: '%database_name%2'
                      user: '%database_user%'
                      password: '%database_password%'
                      charset: '%database_charset%'
          orm:
              auto_generate_proxy_classes: '%kernel.debug%'
              entity_managers:
                  default:
                      connection: default
                      naming_strategy: doctrine.orm.naming_strategy.underscore
                      auto_mapping: true
                  default2:
                      connection: default2
                      naming_strategy: doctrine.orm.naming_strategy.underscore
                      auto_mapping: true
      

      But then it is not working as we get:

      You cannot enable "auto_mapping" on more than one manager at the same time (found in "default" and default2").

      So I tried with:

          orm:
              auto_generate_proxy_classes: '%kernel.debug%'
              entity_managers:
                  default:
                      connection: default
                      naming_strategy: doctrine.orm.naming_strategy.underscore
                      mappings:
                          NovaeZMailingBundle: ~
                  default2:
                      connection: default2
                      naming_strategy: doctrine.orm.naming_strategy.underscore
                      mappings:
                          NovaeZMailingBundle: ~
      

      It is better but not working, somehow, somewhere in Doctrine there is something and the first database is used...
      Even if this is better, I guess we would need a Compiler Pass to automatically set the "Mapping" option as we cannot ask the user to do that.

      So I am stuck here, I think we will struggle with Doctrine deep stuff, I don't know who we could ask.
      Magic is probably here: https://github.com/doctrine/DoctrineBundle/blob/1.12.x/DependencyInjection/DoctrineExtension.php#L342

      Thank you

      Attachments

        Activity

          People

            Unassigned Unassigned
            2bfcc1b1-0b8e-4fb5-9c24-c434957abb69@accounts.ibexa.co Sébastien Morel
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

              Created:
              Updated: