Symfony2 / Doctrine2: проблемы управления несколькими диспетчерами сущностей внутри слушателя

Я следую этому рецепту http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/cookbook/blending-orm-and-mongodb-odm.html#event-subscriber и когда i получить доступ к подписчику события, я не могу ввести надлежащего entity manager , тот, который назван $this->dm инициализированным в конструкторе.

Как я понимаю, менеджер $em = $eventArgs->getEntityManager(); используемый загружаемой сущностью, может быть извлечен через $em = $eventArgs->getEntityManager(); то мне нужен другой, который я inject следующим образом:

     Сервисы:
         postload.listener:
         class: myVendor \ myFooBarBundle \ Listener \ myEntityListener
         теги:
             - {name: doctrine.event_listener, event: postLoad}
         аргументы:
             - "@ doctrine.orm.foobar_entity_manager"

Это мои руководители:

 //orm.yml
         ORM:
         entity_managers:
             по умолчанию:
                 соединение: по умолчанию
                 отображения:
                     myVendormyFooBarBundle:
                         prefix: "myVendor \ myFooBarBundle \ Entity"
                         Тип: аннотация
                         is_bundle: true
                         dir: "Entity"
             Foobar:
                 соединение: foobar
                 отображения:
                     myVendormyFooBarBundle:
                         prefix: "myVendor \ myFooBarBundle \ View"
                         Тип: аннотация
                         is_bundle: true
                         dir: "View"

При foobar entity manager используя вышеприведенную стратегию, я получаю следующую ошибку:

 Circular reference detected for service "postload.listener", path: "routing.loader -> routing.db.loader -> doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> postload.listener -> doctrine.orm.fooba_entity_manager -> doctrine.dbal.foobar_connection". 

Это myVendor\myFooBarBundle\Listener\myEntityListener :

     class myFooBarEntityListener
     {

         public function __construct (\ Doctrine \ ORM \ EntityManager $ em)
         {
             $ this-> em = $ em;
         }

         публичная функция postLoad (LifecycleEventArgs $ eventArgs)
         {
             $ myEntity = $ eventArgs-> getEntity ();

             if ($ myEntity instanceof \ myVendor \ myFooBarBundle \ Entity \ myEntity)
             {
                 $ em = $ eventArgs-> getEntityManager ();
                 $ fooBarReflProp = $ em-> getClassMetadata ('myVendor \ myFooBarBundle \ Entity \ myEntity') -> reflClass-> getProperty ('FooBarEntity');
                 $ fooBarReflProp-> setAccessible (true);
                 $ fooBarEntity = $ this-> em-> getRepository ('myVendor \ myFooBarBundle \ View \ myFooBarEntity') -> findOneBy (массив ('id' => $ myEntity-> getFooBarEntityId ()));
                 $ fooBarReflProp-> setValue ($ myEntity, $ fooBarEntity);
             }
         }
     }

Также, чтобы избежать circular reference error я попытался not вводить foobar entity manager LifecycleEventArgs $eventArgs foobar entity manager и получить его через LifecycleEventArgs $eventArgs :

     class myFooBarEntityListener
     {

         публичная функция postLoad (LifecycleEventArgs $ eventArgs)
         {
             $ myEntity = $ eventArgs-> getEntity ();

             if ($ myEntity instanceof \ myVendor \ myFooBarBundle \ Entity \ myEntity)
             {
                 $ em = $ eventArgs-> getEntityManager ();
                 $ fooBarReflProp = $ em-> getClassMetadata ('myVendor \ myFooBarBundle \ Entity \ myEntity') -> reflClass-> getProperty ('FooBarEntity');
                 $ fooBarReflProp-> setAccessible (true);
                 // УВЕДОМЛЕНИЕ КАК ЗДЕСЬ Я ДОЛЖЕН ПОЛУЧИТЬ МЕНЕДЖЕР ПОЛЬЗОВАТЕЛЯ ЧЕРЕЗ $ eventArgs
                 $ fooBarEntity = $ eventArgs-> getEntityManager ('foobar') -> getRepository ('myVendor \ myFooBarBundle \ View \ myFooBarEntity') -> findOneBy (массив ('id' => $ myEntity-> getFooBarEntityId ()));
                 $ fooBarReflProp-> setValue ($ myEntity, $ fooBarEntity);
             }
         }
     }

Эта последняя реализация через меня вызывает следующую ошибку:

An exception has been thrown during the rendering of a template ("Class myVendor\myFooBarBundle\View\myFooBarEntity is not a valid entity or mapped super class.") in "SonataAdminBundle:CRUD:base_list.html.twig" at line 28.

Вышеприведенная ошибка вызвана $fooBarEntity = $eventArgs->getEntityManager('foobar')->getRepository( 'myVendor\myFooBarBundle\View\myFooBarEntity' )->findOneBy( array( 'id' => $myEntity->getFooBarEntityId() ) ); потому что когда я помещаю echo 'hello'; die (); перед этой строкой ошибка не выбрасывается, но когда она помещается сразу после строки, возникает ошибка, и hello не отображается. Ошибка заставляет меня думать, что, хотя я явно получаю соединение foobar через $eventArgs->getEntityManager('foobar') он все равно дает мне connection/entity manager по default .

Чтобы дважды проверить myVendor\myFooBarBundle\View\myFooBarEntity синтаксис, я пошел в octrine\ORM\Mapping\Driver\DriverChain и разместил следующий код:

     if (strpos ($ className, 'myFooBarEntity'))
     {
         echo 'Class:'. $ className. "\ n \ n";
         foreach ($ this -> _ drivers как $ namespace => $ driver)
         {
             echo 'namespace:'. $ namespace. "\ n";
             $ bool = strpos ($ className, $ namespace);
             var_dump ($ BOOL);
             echo "\ n \ n";
         }
     }
     умереть();

Этот код DriverChain дает мне следующее, поэтому я думаю, что соединение «foobar» никогда не используется, или у symfony есть какой-то интерпретатор ошибок, orm.yml файл orm.yml который определяет менеджеров сущностей плюс пространства имен для использования.

class: myVendor \ myFooBarBundle \ View \ myFooBarEntity

namespace: myVendor \ myFooBarBundle \ Entity bool (false)

Если я смотрю foor, слово entity внутри myVendor\myFooBarBundle\View\myFooBarEntity я просто нахожу @ORM\Entity для определения сущности, а также @ORM\OneToMany( targetEntity=.....) для отношения с другим объектом.

Надеюсь, кто-то может помочь, так как это сводит меня с ума. Большое спасибо!!

Я нашел решение:

 services: postload.listener: class: myVendor\myFooBarBundle\Listener\myEntityListener tags: - { name: doctrine.event_listener, event: postLoad } arguments: - @doctrine 

Мой слушатель:

 namespace myVendor\myFooBarBundle\Listener\myEntityListener; use Symfony\Bundle\DoctrineBundle\Registry; class myFooBarEntityListener { private $reg; public function __construct(Registry $reg) { //dont't put your entitymanager otherwise a loop appear during creation $this->reg = $reg; } public function postLoad( LifecycleEventArgs $eventArgs ) { $myEntity = $eventArgs->getEntity(); if( $myEntity instanceof \myVendor\myFooBarBundle\Entity\myEntity ) { $em = $this->reg->getEntityManager('not_default'); $userPointdbManager = $em->getRepository('FullerUserBundle:UserPointdb'); .... } } } 

Теперь вы можете использовать несколько менеджеров сущностей.

Я думаю, что вижу вашу проблему:

Вы пытаетесь работать с Entites, которые не управляются с помощью entityManager, с которым вы работаете.

Причина в том, что в первом примере вы работаете над сервисом doctrine.orm.foobar_entity_manager , который не знает о myVendor\myFooBarBundle\Entity .

Во втором вы пытаетесь получить доступ к другим сущностным менеджерам, используя: $eventArgs->getEntityManager('foobar') но это не сработает. EventArgs привязан только к одному элементу entityManager, и нет никакого аргумента (например, foobar) для доступа к другому.

Поэтому лучшее решение, которое я вижу здесь, – это действовать как в вашей первой идее, но впрыскивать как entityMangers:

 services: postload.listener: class: myVendor\myFooBarBundle\Listener\myEntityListener tags: - { name: doctrine.event_listener, event: postLoad } arguments: - "@doctrine.orm.default_entity_manager" - "@doctrine.orm.foobar_entity_manager" 

Если у вас есть обнаружение циклических зависимостей, попробуйте ввести службу doctrine , которая является экземпляром Symfony\Bridge\Doctrine\ManagerRegistry .

Последний пример начал работать для меня после изменения использования Symfony \ Bundle \ DoctrineBundle \ Registry; использовать Doctrine \ Bundle \ DoctrineBundle \ Registry ;.

Так должно быть:

 namespace myVendor \ myFooBarBundle \ Listener \ myEntityListener;

 использование Doctrine \ Bundle \ DoctrineBundle \ Registry

 class myFooBarEntityListener
 {

     private $ reg;

     public function __construct (Registry $ reg)
     {
         // не помещаем ваш entitymanager иначе цикл появляется во время создания
         $ this-> reg = $ reg;
     }

     публичная функция postLoad (LifecycleEventArgs $ eventArgs)
     {
         $ myEntity = $ eventArgs-> getEntity ();

         if ($ myEntity instanceof \ myVendor \ myFooBarBundle \ Entity \ myEntity)
         {

             $ em = $ this-> reg-> getEntityManager ('not_default');
             $ userPointdbManager = $ em-> getRepository ('FullerUserBundle: UserPointdb');

             ....
         }
     }
 }

Не устанавливайте параметр реестра как параметр, но RegistryInterface (используйте Symfony \ Bridge \ Doctrine \ RegistryInterface)