Symfony2 / Doctrine2:管理侦听器内多个实体管理器的问题

时间:2012-03-02 09:45:17

标签: php symfony doctrine-orm

我正在关注那个食谱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"

使用上述策略injectingfoobar 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文件,它定义了实体管理器和名称空间来使用。

class:myVendor \ myFooBarBundle \ View \ myFooBarEntity

命名空间:myVendor \ myFooBarBundle \ Entity 布尔(假)

如果我看一下entity内的myVendor\myFooBarBundle\View\myFooBarEntity字,我只找到@ORM\Entity作为实体定义,还@ORM\OneToMany( targetEntity=.....)表示与另一个实体的关系。

我希望有人可以提供帮助,因为它让我发疯。非常感谢!!

4 个答案:

答案 0 :(得分:2)

我找到了解决方案:

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 :(得分:1)

我想我看到了你的问题:

您正在尝试使用不受您正在使用的entityManager管理的Entites。

原因是,在您的第一个示例中,您正在处理服务doctrine.orm.foobar_entity_manager,但不了解myVendor\myFooBarBundle\Entity entites。

在第二个中,您尝试使用:$eventArgs->getEntityManager('foobar')访问不同的entityManagers,但这不起作用。 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的实例。

答案 2 :(得分:1)

不要将Registry设置为参数,而是设置RegistryInterface(使用Symfony \ Bridge \ Doctrine \ RegistryInterface)

答案 3 :(得分:0)

最后一个例子在改变后开始为我工作 使用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');

            ....
        }
    }
}