Skip to content
  • About
    • What is Symfony?
    • Community
    • News
    • Contributing
    • Support
  • Documentation
    • Symfony Docs
    • Symfony Book
    • Screencasts
    • Symfony Bundles
    • Symfony Cloud
    • Training
  • Services
    • Platform.sh for Symfony Best platform to deploy Symfony apps
    • SymfonyInsight Automatic quality checks for your apps
    • Symfony Certification Prove your knowledge and boost your career
    • SensioLabs Professional services to help you with Symfony
    • Blackfire Profile and monitor performance of your apps
  • Other
  • Blog
  • Download
sponsored by SensioLabs
  1. Home
  2. Documentation
  3. Doctrine
  4. Doctrine Event Listeners and Subscribers
  • Documentation
  • Book
  • Reference
  • Bundles
  • Cloud

Table of Contents

  • Configuring the Listener/Subscriber
  • Creating the Listener Class
  • Creating the Subscriber Class
  • Lazy loading for Event Listeners

Doctrine Event Listeners and Subscribers

Edit this page

Warning: You are browsing the documentation for Symfony 4.0, which is no longer maintained.

Read the updated version of this page for Symfony 6.3 (the current stable version).

Doctrine Event Listeners and Subscribers

Doctrine packages have a rich event system that fires events when almost anything happens inside the system. For you, this means that you can create arbitrary services and tell Doctrine to notify those objects whenever a certain action (e.g. prePersist()) happens within Doctrine. This could be useful, for example, to create an independent search index whenever an object in your database is saved.

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. For more, see The Event System on Doctrine's website.

The Doctrine website also explains all existing events that can be listened to.

Configuring the Listener/Subscriber

To register a service to act as an event listener or subscriber you just have to tag it with the appropriate name. Depending on your use-case, you can hook a listener into every DBAL connection and ORM entity manager or just into one specific DBAL connection and all the entity managers that use this connection.

1
2
3
4
5
6
7
8
9
10
11
12
services:
    # ...

    App\EventListener\SearchIndexer:
        tags:
            - { name: doctrine.event_listener, event: postPersist }
    App\EventListener\SearchIndexer2:
        tags:
            - { name: doctrine.event_listener, event: postPersist, connection: default }
    App\EventListener\SearchIndexerSubscriber:
        tags:
            - { name: doctrine.event_subscriber, connection: default }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:doctrine="http://symfony.com/schema/dic/doctrine">
    <services>
        <!-- ... -->

        <service id="App\EventListener\SearchIndexer">
            <tag name="doctrine.event_listener" event="postPersist" />
        </service>
        <service id="App\EventListener\SearchIndexer2">
            <tag name="doctrine.event_listener" event="postPersist" connection="default" />
        </service>
        <service id="App\EventListener\SearchIndexerSubscriber">
            <tag name="doctrine.event_subscriber" connection="default" />
        </service>
    </services>
</container>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
use App\EventListener\SearchIndexer;
use App\EventListener\SearchIndexer2;
use App\EventListener\SearchIndexerSubscriber;

$container->autowire(SearchIndexer::class)
    ->addTag('doctrine.event_listener', array('event' => 'postPersist'))
;
$container->autowire(SearchIndexer2::class)
    ->addTag('doctrine.event_listener', array(
        'event' => 'postPersist',
        'connection' => 'default',
    ))
;
$container->autowire(SearchIndexerSubscriber::class)
    ->addTag('doctrine.event_subscriber', array('connection' => 'default'))
;

Creating the Listener Class

In the previous example, a SearchIndexer service was configured as a Doctrine listener on the event postPersist. The class behind that service must have a postPersist() method, which will be called when the event is dispatched:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// src/EventListener/SearchIndexer.php
namespace App\EventListener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use App\Entity\Product;

class SearchIndexer
{
    public function postPersist(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        // only act on some "Product" entity
        if (!$entity instanceof Product) {
            return;
        }

        $entityManager = $args->getEntityManager();
        // ... do something with the Product
    }
}

In each event, you have access to a LifecycleEventArgs object, which gives you access to both the entity object of the event and the entity manager itself.

One important thing to notice is that a listener will be listening for all entities in your application. So, if you're interested in only handling a specific type of entity (e.g. a Product entity but not a BlogPost entity), you should check for the entity's class type in your method (as shown above).

Tip

In Doctrine 2.4, a feature called Entity Listeners was introduced. It is a lifecycle listener class used for an entity. You can read about it in the Doctrine Documentation.

Creating the Subscriber Class

A Doctrine event subscriber must implement the Doctrine\Common\EventSubscriber interface and have an event method for each event it subscribes to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// src/EventListener/SearchIndexerSubscriber.php
namespace App\EventListener;

use Doctrine\Common\EventSubscriber;
// for Doctrine < 2.4: use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\Common\Persistence\Event\LifecycleEventArgs;
use App\Entity\Product;

class SearchIndexerSubscriber implements EventSubscriber
{
    public function getSubscribedEvents()
    {
        return array(
            'postPersist',
            'postUpdate',
        );
    }

    public function postUpdate(LifecycleEventArgs $args)
    {
        $this->index($args);
    }

    public function postPersist(LifecycleEventArgs $args)
    {
        $this->index($args);
    }

    public function index(LifecycleEventArgs $args)
    {
        $entity = $args->getEntity();

        // perhaps you only want to act on some "Product" entity
        if ($entity instanceof Product) {
            $entityManager = $args->getEntityManager();
            // ... do something with the Product
        }
    }
}

Tip

Doctrine event subscribers cannot return a flexible array of methods to call for the events like the Symfony event subscriber can. Doctrine event subscribers must return a simple array of the event names they subscribe to. Doctrine will then expect methods on the subscriber with the same name as each subscribed event, just as when using an event listener.

For a full reference, see chapter The Event System in the Doctrine documentation.

Lazy loading for Event Listeners

One subtle difference between listeners and subscribers is that Symfony can load entity listeners lazily. This means that your listener class will only be fetched from the service container (and thus be instantiated) once the event it is linked to actually fires.

Lazy loading might give you a slight performance improvement when your listener runs for events that rarely fire. Also, it can help you when you run into circular dependency issues that may occur when your listener service in turn depends on the DBAL connection.

To mark a listener service as lazily loaded, just add the lazy attribute to the tag like so:

1
2
3
4
services:
    App\EventListener\SearchIndexer:
        tags:
            - { name: doctrine.event_listener, event: postPersist, lazy: true }
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:doctrine="http://symfony.com/schema/dic/doctrine">

    <services>
        <service id="App\EventListener\SearchIndexer" autowire="true">
            <tag name="doctrine.event_listener" event="postPersist" lazy="true" />
        </service>
    </services>
</container>
1
2
3
4
5
6
use App\EventListener\SearchIndexer;

$container
    ->autowire(SearchIndexer::class)
    ->addTag('doctrine.event_listener', array('event' => 'postPersist', 'lazy' => 'true'))
;

Note

Marking an event listener as lazy has nothing to do with lazy service definitions which are described in their own article

This work, including the code samples, is licensed under a Creative Commons BY-SA 3.0 license.
TOC
    Version
    We stand with Ukraine.
    Version:
    Online exam, become Symfony certified today

    Online exam, become Symfony certified today

    Check Code Performance in Dev, Test, Staging & Production

    Check Code Performance in Dev, Test, Staging & Production

    Symfony footer

    ↓ Our footer now uses the colors of the Ukrainian flag because Symfony stands with the people of Ukraine.

    Avatar of Myke79, a Symfony contributor

    Thanks Myke79 for being a Symfony contributor

    1 commit • 2 lines changed

    View all contributors that help us make Symfony

    Become a Symfony contributor

    Be an active part of the community and contribute ideas, code and bug fixes. Both experts and newcomers are welcome.

    Learn how to contribute

    Symfony™ is a trademark of Symfony SAS. All rights reserved.

    • What is Symfony?

      • Symfony at a Glance
      • Symfony Components
      • Case Studies
      • Symfony Releases
      • Security Policy
      • Logo & Screenshots
      • Trademark & Licenses
      • symfony1 Legacy
    • Learn Symfony

      • Symfony Docs
      • Symfony Book
      • Reference
      • Bundles
      • Best Practices
      • Training
      • eLearning Platform
      • Certification
    • Screencasts

      • Learn Symfony
      • Learn PHP
      • Learn JavaScript
      • Learn Drupal
      • Learn RESTful APIs
    • Community

      • SymfonyConnect
      • Support
      • How to be Involved
      • Code of Conduct
      • Events & Meetups
      • Projects using Symfony
      • Downloads Stats
      • Contributors
      • Backers
    • Blog

      • Events & Meetups
      • A week of symfony
      • Case studies
      • Cloud
      • Community
      • Conferences
      • Diversity
      • Documentation
      • Living on the edge
      • Releases
      • Security Advisories
      • SymfonyInsight
      • Twig
      • SensioLabs
    • Services

      • SensioLabs services
      • Train developers
      • Manage your project quality
      • Improve your project performance
      • Host Symfony projects

      Deployed on

    Follow Symfony

    Search by Meilisearch