Reputation: 953
i'm following that recipe http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/cookbook/blending-orm-and-mongodb-odm.html#event-subscriber
and when i get to the event subscriber i'm not able to inject the proper entity manager
, the one named $this->dm
initialized in the constructor.
As i understand, the entity manager used by the entity which is being loaded can be retrieved through $em = $eventArgs->getEntityManager();
then i need another one which i inject
in the following manner:
services: postload.listener: class: myVendor\myFooBarBundle\Listener\myEntityListener tags: - { name: doctrine.event_listener, event: postLoad } arguments: - "@doctrine.orm.foobar_entity_manager"
Those are my entity managers:
//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"
When injecting
the foobar entity manager
using the above strategy i get the following error:
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".
That's myVendor\myFooBarBundle\Listener\myEntityListener
class:
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 ); } } }
Also to avoid the circular reference error
i've tried not
to inject the foobar entity manager
and get it through 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 ); } } }
That last implementation throughs me the following error:
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.
The above error is caused by $fooBarEntity = $eventArgs->getEntityManager('foobar')->getRepository( 'myVendor\myFooBarBundle\View\myFooBarEntity' )->findOneBy( array( 'id' => $myEntity->getFooBarEntityId() ) );
because when i place echo 'hello';die(); just before that line the error is not thrown but when placed just after the line the error is thrown and hello
is not shown. The error makes me think that although i'm explicitly getting the foobar
connection through $eventArgs->getEntityManager('foobar')
it is still giving me the default
connection/entity manager
.
In order to double check myVendor\myFooBarBundle\View\myFooBarEntity
syntax i went to octrine\ORM\Mapping\Driver\DriverChain
and placed the following code:
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();
That DriverChain code gives me the following, that's why i think 'foobar' connection is never used or symfony has some kind of bug interpreting orm.yml
file which defines the entity managers plus namespaces to use.
class: myVendor\myFooBarBundle\View\myFooBarEntity
namespace: myVendor\myFooBarBundle\Entity bool(false)
If i look foor the entity
word inside myVendor\myFooBarBundle\View\myFooBarEntity
i just find @ORM\Entity
for the entity definition and also @ORM\OneToMany( targetEntity=.....)
for the relation with another entity.
I hope someone can help, as it's driving me crazy. Thanks a lot!!
Upvotes: 2
Views: 4513
Reputation: 16775
Do not set Registry as parameter, but RegistryInterface (use Symfony\Bridge\Doctrine\RegistryInterface)
Upvotes: 1
Reputation: 3410
The last example started to work for me after changing use Symfony\Bundle\DoctrineBundle\Registry; to use Doctrine\Bundle\DoctrineBundle\Registry;.
So it should be:
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'); .... } } }
Upvotes: 0
Reputation: 31
I found a solution:
services:
postload.listener:
class: myVendor\myFooBarBundle\Listener\myEntityListener
tags:
- { name: doctrine.event_listener, event: postLoad }
arguments:
- @doctrine
My listener:
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');
....
}
}
}
You can use several entity managers now.
Upvotes: 3
Reputation: 8915
I think I see your problem:
You're trying to work on Entites that are not managed by the entityManager you're working with.
The reason is that in your first example, you ony work on the service doctrine.orm.foobar_entity_manager
, that is not aware of myVendor\myFooBarBundle\Entity
entites.
In second one you try to access different entityManagers using: $eventArgs->getEntityManager('foobar')
but this won't work. EventArgs is attached to only ONE entityManager, and there is no argument (like 'foobar') to access another one.
So the best solution I see here is to act like in your first idea, but injecting both 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"
If you have cyclic dependencies detection, try to inject the doctrine
service, which is an instance of Symfony\Bridge\Doctrine\ManagerRegistry
.
Upvotes: 1