Symfony2 / Doctrine2: проблемы управления менеджером нескольких сущностей внутри слушателя - PullRequest
2 голосов
/ 02 марта 2012

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

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

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

Это мои менеджеры:

//orm.yml
        orm:
        entity_managers:
            default:
                connection: default
                mappings:
                    myVendormyFooBarBundle:
                        prefix: "myVendor\myFooBarBundle\Entity"
                        type: annotation
                        is_bundle: true
                        dir: "Entity"
            foobar:
                connection: foobar
                mappings:
                    myVendormyFooBarBundle:
                        prefix: "myVendor\myFooBarBundle\View"
                        type: annotation
                        is_bundle: true
                        dir: "View"

Когда injecting 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;
        }

        public function 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( array( 'id' => $myEntity->getFooBarEntityId() ) );
                $fooBarReflProp->setValue( $myEntity, $fooBarEntity );
            }
        }
    }

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

    class myFooBarEntityListener
    {

        public function 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 );
                //NOTICE HOW HERE I SHOULD GET THE PROPER ENTITY MANAGER THROUGH $eventArgs
                $fooBarEntity = $eventArgs->getEntityManager('foobar')->getRepository( 'myVendor\myFooBarBundle\View\myFooBarEntity' )->findOneBy( array( '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'), оно все равно дает мне default connection/entity manager.

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

    if( strpos( $className, 'myFooBarEntity' ) )
    {
        echo 'Class: '.$className."\n\n";
        foreach ($this->_drivers as $namespace => $driver)
        {
            echo 'namespace: '.$namespace."\n";
            $bool = strpos($className, $namespace);
            var_dump($bool);
            echo "\n\n";
        }
    }
    die();

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

класс: myVendor \ myFooBarBundle \ View \ myFooBarEntity

пространство имен: myVendor \ myFooBarBundle \ Entity BOOL (ложь)

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

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

Ответы [ 4 ]

2 голосов
/ 21 июня 2012

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

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');

            ....
        }
    }
}

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

1 голос
/ 04 марта 2014

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

1 голос
/ 03 марта 2012

Мне кажется, я вижу вашу проблему:

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

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

Во втором вы пытаетесь получить доступ к различным EntityManager, используя: $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.

0 голосов
/ 06 января 2014

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

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

namespace myVendor\myFooBarBundle\Listener\myEntityListener;

use Doctrine\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');

            ....
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...