Injecting EntityManager-dependend service into Lis

2019-04-11 00:04发布

问题:

I am trying to inject one of my services into an EntityListener in order to call some application specific behaviour when an entity gets updated.

My Logger service, used to store events in a LogEntry entity in my database:

class Logger
{
    /**
     * @var EntityManager $manager The doctrine2 manager
     */
   protected $manager;
   //...
}

The listener:

class EntityListener
{
    public function __construct(Logger $logger)
    {
        $this->logger = $logger;
         // ...
    }
}

And the service definitions in my service.yml:

listener:
    class: Namespace\EntityListener
    arguments: [@logger]
    tags:
        - { name: doctrine.event_listener, event: preUpdate }

logger:
    class: Namespace\Logger
    arguments: [@doctrine.orm.entity_manager]

Unfortunately it results in a ServiceCircularReferenceException:

Circular reference detected for service "doctrine.orm.default_entity_manager", path: "doctrine.orm.default_entity_manager -> doctrine.dbal.default_connection -> listener -> logger".

The problem obviously is that I inject the doctrine into the my service while it is also automatically injected into my listener. How do I proceed? I found a very similar question but the accepted answer is to inject the container which is obviously not favourable.

Any suggestions on how to solve my issue would be appreciated.


Small side note: I would like to avoid a solution depending on lazy services if possible.

回答1:

First of all I switched from an EventListener to an EventSubscriber. From the docs:

Doctrine defines two types of objects that can listen to Doctrine events: listeners and subscribers. Both are very similar, but listeners are a bit more straightforward.

It turns out one can access the ObjectManager via the passed $args-parameter like so:

/** @var Doctrine\Common\Persistence\ObjectManager $manager */
$manager = $args->getObjectManager();

So either use it directly in the callback:

public function postUpdate(LifecycleEventArgs $args)
{
    $manager = $args->getObjectManager();
    // ...

...or set it to an object field:

/** @var ObjectManager $manager */
private $manager;

public function postUpdate(LifecycleEventArgs $args)
{
    $this->manager = $args->getObjectManager();
    // ...


回答2:

After struggling with the same problem, I found out that using lazy loading solved my issue.

listener:
    class: AppBundle\EventListener\OrderDoctrineListener
    tags:
        - { name: doctrine.event_listener, event: postPersist, lazy: true }