Symfony exception when registering new Doctrine ev

2019-09-03 03:52发布

问题:

I'm using Symfony 2.3 with Sonata Admin Bundle with DoctrineExtensions (which is enabled by StofDoctrineExtensionsBundle). I enabled, configured and successfully tested SoftDeleteable and Timestampable components.

Now, when I try adding another Doctrine event subscriber using Symfony tagged service, it seems as the softdeleteable listener is being disabled.

My service:

my.contact.listener.tag:
    class: My\ContactBundle\EventListener\TagListener
    tags:
        - { name: doctrine.event_subscriber, connection: default }
    calls:
        - [ setTagManager, [ @fpn_tag.tag_manager ] ]

Subscriber:

namespace My\ContactBundle\EventListener;


use Doctrine\Common\EventSubscriber;
use Doctrine\ORM\Event\LifecycleEventArgs;
use DoctrineExtensions\Taggable\Taggable;
use FPN\TagBundle\Entity\TagManager;

class TagListener implements EventSubscriber
{
    /**
     * @var TagManager
     */
    private $tagManager;

    /**
     * @param \FPN\TagBundle\Entity\TagManager $tagManager
     */
    public function setTagManager($tagManager)
    {
        $this->tagManager = $tagManager;
    }

    /**
     * Load tags for Taggable entities
     *
     * @param LifecycleEventArgs $args
     */
    public function postLoad(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Taggable) {
            $this->tagManager->loadTagging($entity);
        }
    }

    /**
     * Save tags for Taggable entities
     *
     * @param LifecycleEventArgs $args
     */
    public function preUpdate(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Taggable) {
            $this->tagManager->saveTagging($entity);
        }
    }

    /**
     * Save tags for Taggable entities
     *
     * @param LifecycleEventArgs $args
     */
    public function prePersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        if ($entity instanceof Taggable) {
            $this->tagManager->saveTagging($entity);
        }
    }

    public function getSubscribedEvents()
    {
        return array(
            'prePersist',
            'preUpdate',
            'postLoad',
        );
    }
}

In each request I get exception:

Listener "SoftDeleteableListener" was not added to the EventManager!

If I disable my subscriber, the problem is gone. How to enable my event subscriber and have softdeleteable too?

回答1:

I got the same problem as you do today.

The problem is that fpn_tag.tag_manager depends on doctrine.orm.default_entity_manager, but the TagListener is a dependency of doctrine.orm.default_entity_manager if you tag it with doctrine.event_subscriber. Thus creating a circular dependency. But this is not detected by the service container, instead it tries to add the events after the doctrine connection service is returned. See more details here.

There are two ways to fix this

  1. You can inject the service container into the TagListener, then load fpn_tag.tag_manager on demand.
  2. Create a listener on kernel.request event, then manually add the event subscriber to the entity manager.

A side note, I'd recommend against calling saveTagging inside preUpdate and prePersist events. Because saveTagging does a implicit flush, which is not safe to call in these events.