Symfony Circular Reference Exception for Doctrine onFlush Event Listener Service

I created a service for the Doctrine onFlush event listener. In this listener, I would like to reference the common function that I have in another service to check the path of the object's shortcut. This other service uses the entity manager to do this, so the service definition for this other service is implemented by the doctrine entity administrator as a constructor argument. But if I include this other service in my main onFlush event listener, I get an annoying circular link error.

I could force this entity_helper service to accept the Entity Manager in the set setEntityManager($entityManager) . But that means that whenever I use this entity_helper service entity_helper , I should always go through the EntityManager. Maybe everything is in order, but is this the only solution here? Is there something wrong with my logic / understanding for a start? (I'm new to Symfony, so I'm often mistaken).

Figure A: Invalid Error

 Fatal error: Uncaught exception 'Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException' with message 'Circular reference detected for service "doctrine.dbal.cms_connection", path: "doctrine.dbal.cms_connection".' in /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php:456 Stack trace: #0 /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php(604): Symfony\Component\DependencyInjection\Dumper\PhpDumper->addServiceInlinedDefinitionsSetup('doctrine.dbal.c...', Object(Symfony\Component\DependencyInjection\Definition)) #1 /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php(630): Symfony\Component\DependencyInjection\Dumper\PhpDumper->addService('doctrine.dbal.c...', Object(Symfony\Component\DependencyInjection\Definition)) #2 /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php(117): Symfony\Componen in /var/www/core/cms/vendor/symfony/symfony/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php on line 456 

Services.yml

 # This is the helper class for all entities gutensite_cms.entity_helper: class: Gutensite\CmsBundle\Service\EntityHelper # This causes the Circular Reference Error when this service is included in Event Listener arguments: [ "@doctrine.orm.cms_entity_manager" ] # Passing via a setter injection also causes the same error. #calls: # - [setEntityManager, ['@doctrine.orm.cms_entity_manager']] # An event listener for any entity that is Versionable gutensite_cms.listener.is_versionable: class: Gutensite\CmsBundle\EventListener\IsVersionableListener #only pass in the services we need arguments: [ "@gutensite_cms.entity_helper" ] tags: - { name: doctrine.event_listener, event: onFlush } 

Gutensite \ CmsBundle \ Service \ EntityHelper

 namespace Gutensite\CmsBundle\Service; use Doctrine\ORM\EntityManager; class EntityHelper { /** * @var $em EntityManager */ private $em; public function __construct(EntityManager $entityManager) { $this->em = $entityManager; } /** * Get the bundle shortcut path for an entity based on it namespace. * * As an example, if your entity is Gutensite\CmsBundle\Entity\View\ViewVersion the function will return * GutensiteCmsBundle:View\ViewVersion * * @param $entity * @return string */ public function getEntityBundleShortcut($entity) { // wrap get_class() in the entityManager metadata function to avoid returning cached proxy class $path = explode('\Entity\\', $this->em->getClassMetadata(get_class($entity))->getName()); return str_replace('\\', '', $path[0]).':'.$path[1]; } } 

Gutensite \ CmsBundle \ EventListener \ IsVersionableListener

 namespace Gutensite\CmsBundle\EventListener; use Doctrine\ORM\Event\OnFlushEventArgs; use Gutensite\CmsBundle\Service\EntityHelper; /** * Class IsVersionableListener * @package Gutensite\CmsBundle\EventListener */ class IsVersionableListener { /* private $entityHelper; public function __construct(EntityHelper $entityHelper) { $this->entityHelper = $entityHelper; } */ public function onFlush(OnFlushEventArgs $eventArgs) { // This never is excecuted because of the error print('ON FLUSH EVENT EXECUTED'); exit; $em = $eventArgs->getEntityManager(); $uow = $em->getUnitOfWork(); $updatedEntities = $uow->getScheduledEntityUpdates(); foreach($updatedEntities AS $entity) { // This is generic listener for all entities that have an isVersionable method (eg ViewVersion) // TODO: at the moment, we only want to do the following code for the viewVersion entity if (method_exists($entity, 'isVersionable') && $entity->isVersionable()) { // Get the Correct Repo for this entity $entityShortcut = $this->entityHelper->getEntityBundleShortcut($entity); $repo = $em->getRepository($entityShortcut); // If the repo for this entity has an onFlush method, use it. // This allows us to keep the functionality in the entity repo if(method_exists($repo, 'onFlush')) { $repo->onFlush($em, $entity); } } } } } 
+6
source share
1 answer

The main solution to this (as I pointed out) is to remove the EntityManager constructor or setter input from the service definition (and class of service). Instead, you should pass the EntityManager to the function it needs. This prevents circular binding.

I chose this instead of creating setEntityManager because it seems awkward to set this on the EntityHelper service before calling the function. It seems better to just pass it directly to the functions that it needs.

Here are the changes:

Services.yml

 # This is the helper class for all entities gutensite_cms.entity_helper: class: Gutensite\CmsBundle\Service\EntityHelper # Do NOT pass in EntityManager via constructor or injector, because it causes a Circular Reference Error when this service is included in Event Listener # An event listener for any entity that is Versionable gutensite_cms.listener.is_versionable: class: Gutensite\CmsBundle\EventListener\IsVersionableListener #only pass in the services we need arguments: [ "@gutensite_cms.entity_helper" ] tags: - { name: doctrine.event_listener, event: onFlush } 

Gutensite \ CmsBundle \ Service \ EntityHelper

 namespace Gutensite\CmsBundle\Service; use Doctrine\ORM\EntityManager; class EntityHelper { /** * Get the bundle shortcut path for an entity based on it namespace. * * As an example, if your entity is Gutensite\CmsBundle\Entity\View\ViewVersion the function will return * GutensiteCmsBundle:View\ViewVersion * * @param $entity * @return string */ public function getEntityBundleShortcut(EventManager $eventManager, $entity) { // wrap get_class() in the entityManager metadata function to avoid returning cached proxy class $path = explode('\Entity\\', $eventManager->getClassMetadata(get_class($entity))->getName()); return str_replace('\\', '', $path[0]).':'.$path[1]; } } 

Gutensite \ CmsBundle \ EventListener \ IsVersionableListener

 namespace Gutensite\CmsBundle\EventListener; use Doctrine\ORM\Event\OnFlushEventArgs; use Gutensite\CmsBundle\Service\EntityHelper; /** * Class IsVersionableListener * @package Gutensite\CmsBundle\EventListener */ class IsVersionableListener { /* private $entityHelper; public function __construct(EntityHelper $entityHelper) { $this->entityHelper = $entityHelper; } */ public function onFlush(OnFlushEventArgs $eventArgs) { $em = $eventArgs->getEntityManager(); $uow = $em->getUnitOfWork(); $updatedEntities = $uow->getScheduledEntityUpdates(); foreach($updatedEntities AS $entity) { // This is generic listener for all entities that have an isVersionable method (eg ViewVersion) // TODO: at the moment, we only want to do the following code for the viewVersion entity if (method_exists($entity, 'isVersionable') && $entity->isVersionable()) { // Get the Correct Repo for this entity $entityShortcut = $this->entityHelper->getEntityBundleShortcut($em, $entity); $repo = $em->getRepository($entityShortcut); // If the repo for this entity has an onFlush method, use it. // This allows us to keep the functionality in the entity repo if(method_exists($repo, 'onFlush')) { $repo->onFlush($em, $entity); } } } } } 
+4
source

Source: https://habr.com/ru/post/974572/


All Articles