Home » Php » php – Doctrine in Symfony 2: Listening for events from a particular Entity

php – Doctrine in Symfony 2: Listening for events from a particular Entity

Posted by: admin July 12, 2020 Leave a comment

Questions:

I have a Doctrine Entity (News) which I listen for the event prePersist. For that I use an event listener with the method prePersist.

My services.yml looks like this:

listener.entity.news:
    class: A\BBundle\Listeners\Entity\NewsListener
    tags:
        - { name: doctrine.event_listener, event: prePersist }

This is fine and everything works. But the documentation states that when a persist() is called, a prePersist event is spawned. Then as my config states NewsListener will catch it and execute some code. Inside the method where I catch the event I should check if the event comes from the News entity. Here is where I wonder, is it possible to tell Symfony to listen for prePersist events for a particular Entity and then pass it to my listener?

Currently (as I understand it), whenever doctrine spawns a prePersist event ALL listeners are notified. Isn’t it better to say which listeners should listen which event spawners, even if that should be optional, rather than notifying all and letting them filter the ones they need?

I hope I asked my question correctly.

How to&Answers:

is it possible to tell Symfony to listen for prePersist events for a
particular Entity and then pass it to my listener?

No, it’s not possible. Your listener will fire for every entity that is persisted. It’s up to you to do an instanceof check in the event listener to ensure that your code only runs for a specific entity.

Answer:

This seems to be supported since Doctrine 2.4:

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/events.html#entity-listeners

Answer:

This is possible since Doctrine 2.4 with the Entity listener feature.

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\EntityListeners({"AppBundle\EntityListener\PostListener"})
 */
class Post
{
}

namespace AppBundle\EntityListener;

use Doctrine\ORM\Mapping as ORM;

class PostListener
{
    public function preUpdate() {  }

    // or

    /** @ORM\PreUpdate */
    public function someOtherName() {  }
}

What if I want to inject a dependency into the listener? Is this possible?

Yes, this is possible starting with DoctrineBundle 1.3. You just need to register the entity listener as a service & tag it with the doctrine.orm.entity_listener tag.

class PostListener
{
    public function __construct(SomeDependency $someDependency) {  }
}

services:
    app.post_listener:
        class: AppBundle\EntityListener\PostListener
        arguments: ["@app.some_dependency"]
        tags:
            - { name: doctrine.orm.entity_listener }

Alternative method

Since DoctrineBundle 1.5 you can register entity listeners via tags, but this method is yet to be documented.
This method doesn’t require the listener to be mapped with the EntityListeners annotation.

namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class Post
{
}

namespace AppBundle\EntityListener;

class PostListener
{
    public function __construct(SomeDependency $someDependency) {  }

    public function preUpdate() {  }

    public function someOtherName() {  }
}

services:
    app.post_listener:
        class: AppBundle\EntityListener\PostListener
        arguments: ["@app.some_dependency"]
        tags:
            - { name: doctrine.orm.entity_listener, entity: AppBundle\Entity\Post, event: preUpdate }
            # or
            - { name: doctrine.orm.entity_listener, entity: AppBundle\Entity\Post, event: preUpdate, method: someOtherName }

Answer:

Depending on what you do in your listener, you could use lifecycle callbacks in the News entity, and implement the prePersist hook.

http://docs.doctrine-project.org/projects/doctrine-orm/en/2.0.x/reference/events.html#lifecycle-callbacks

This way, the listener would be called only for the instance currently beeing persisted.