PHPackages                             rekalogika/domain-event - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. rekalogika/domain-event

ActiveSymfony-bundle[Database &amp; ORM](/categories/database)

rekalogika/domain-event
=======================

Domain Event Implementation for Symfony and Doctrine

2.7.0(1mo ago)48.4k11MITPHP

Since Sep 1Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/rekalogika/domain-event)[ Packagist](https://packagist.org/packages/rekalogika/domain-event)[ Docs](https://rekalogika.dev/domain-event)[ GitHub Sponsors](https://github.com/priyadi)[ RSS](/packages/rekalogika-domain-event/feed)WikiDiscussions main Synced 3d ago

READMEChangelogDependencies (22)Versions (34)Used By (1)

rekalogika/domain-event
=======================

[](#rekalogikadomain-event)

An implementation of domain event pattern for Symfony &amp; Doctrine.

Full documentation is available at [rekalogika.dev/domain-event](https://rekalogika.dev/domain-event).

What is a Domain Event?
-----------------------

[](#what-is-a-domain-event)

A domain event is simply a regular event like you would normally use with Symfony's EventDispatcher. The difference is that a domain event represents something that has happened in your domain. It has a name that is meaningful to the underlying business that the domain represents. A domain event is usually dispatched by your entities, as opposed to being dispatched from your controllers or other services.

Why Use Domain Events?
----------------------

[](#why-use-domain-events)

A domain event represents a business event that has happened. It is a good way to model the business requirements that say "when something happens, do this".

A domain event is raised by the part of your code where the event is actually happening. Different part of your application might call the same method on an entity. In some cases, the method is called indirectly, and the caller has no idea that it is being called. By using domain events, the event will be dispatched in all the cases. No need to make sure to dispatch the event from all the different places where the method is called.

The application layer (controllers, services) can tell an entity to do something, but it cannot reliably know if the action is actually performed, or if an additional action is performed. A controller or a service can ask `$bookshelf->removeBook($book)`, but only the `$bookshelf` knows if the book was actually removed. And if the event actually happened, the entity can tell the world about it by recording a `BookRemoved` event.

Some problems might tempt you to inject a service into your entity. With domain events, you can avoid that. You can make your entity dispatch an event, and set up a listener to react to that event. The relevant services can then correctly act on your entity, instead of the other way around.

Synopsis
--------

[](#synopsis)

```
//
// The event
//

final readonly class PostPublished
{
    public function __construct(public string $postId) {}
}

//
// The entity
//

use Rekalogika\Contracts\DomainEvent\DomainEventEmitterInterface;
use Rekalogika\Contracts\DomainEvent\DomainEventEmitterTrait;

class Post implements DomainEventEmitterInterface
{
    use DomainEventEmitterTrait;

    // ...

    public function setStatus(string $status): void
    {
        $originalStatus = $this->status;
        $this->status = $status;

        // records the published event if the new status is published and it
        // is different from the original status

        if ($status === 'published' && $originalStatus !== $status) {
            $this->recordEvent(new PostPublished($this->id));
        }
    }

    // ...
}

//
// The listener
//

use Psr\Log\LoggerInterface;
use Rekalogika\Contracts\DomainEvent\Attribute\AsPostFlushDomainEventListener;

class PostEventListener
{
    public function __construct(private LoggerInterface $logger) {}

    // will be called after the post is published and the entity manager is
    // flushed

    #[AsPostFlushDomainEventListener]
    public function onPostPublished(PostPublished $event) {
        $postId = $event->postId;

        $this->logger->info("Post $postId has been published.");
    }
}

//
// The caller
//

use Doctrine\ORM\EntityManagerInterface;

/** @var Post $post */
/** @var EntityManagerInterface $entityManager */

$post->setStatus('published');
$entityManager->flush();

// the event will be dispatched after the flush above, afterwards the listener
// above will be called, sending a message to the logger
```

Features
--------

[](#features)

- Works out of the box. No configuration is required for basic features.
- Simple, unopinionated architecture. Uses plain event objects, and doesn't require much from your domain entities.
- Uses standard Symfony's EventDispatcher, with the same dispatching semantics &amp; listener registrations.
- Transaction support.
- Works with multiple entity managers.
- Multiple events considered identical are dispatched only once.
- Four listening strategies: immediate, pre-flush, post-flush, and event bus.
- Uses Symfony Messenger as the event bus implementation.
- Utilizes the transactional outbox pattern when publishing events to the event bus to guarantee consistency and delivery.
- Utilizes Symfony Scheduler to relay undelivered events to the event bus.
- Does not require you to change how you work with entities.
- Should work everywhere without any change: in controllers, message handlers, command line, etc.
- Separated contracts &amp; framework. Useful for enforcing architectural boundaries. Your domain doesn't have to depend on the framework.
- Symfony Profiler integration. Debug your events in the profiler's events panel.

To Do
-----

[](#to-do)

- Support for Doctrine MongoDB ODM.
- Support event inheritance.
- Deprecate `__remove()` and use a method tagged with an attribute instead.

Installation
------------

[](#installation)

Ensure that Symfony Flex is enabled (it is enabled by default). Open a command console, enter your project directory and execute:

```
composer require rekalogika/domain-event
```

Documentation
-------------

[](#documentation)

[rekalogika.dev/domain-event](https://rekalogika.dev/domain-event)

License
-------

[](#license)

MIT

Contributing
------------

[](#contributing)

The `rekalogika/domain-event` repository is a read-only repo split from the main repo. Issues and pull requests should be submitted to the [rekalogika/domain-event-src](https://github.com/rekalogika/domain-event-src)monorepo.

###  Health Score

50

—

FairBetter than 95% of packages

Maintenance89

Actively maintained with recent releases

Popularity31

Limited adoption so far

Community12

Small or concentrated contributor base

Maturity55

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~30 days

Recently: every ~168 days

Total

33

Last Release

57d ago

Major Versions

1.2.5 → 2.0.02024-03-06

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/1102197?v=4)[Priyadi Iman Nurcahyo](/maintainers/priyadi)[@priyadi](https://github.com/priyadi)

---

Top Contributors

[![priyadi](https://avatars.githubusercontent.com/u/1102197?v=4)](https://github.com/priyadi "priyadi (111 commits)")

---

Tags

doctrinedomaindomain-eventeventevent-dispatcherevent-listenerphpsymfonysymfony-bundleeventsymfonydoctrineevent dispatcherdomainevent listenerdomain-event

### Embed Badge

![Health badge](/badges/rekalogika-domain-event/health.svg)

```
[![Health](https://phpackages.com/badges/rekalogika-domain-event/health.svg)](https://phpackages.com/packages/rekalogika-domain-event)
```

###  Alternatives

[easycorp/easyadmin-bundle

Admin generator for Symfony applications

4.3k17.9M388](/packages/easycorp-easyadmin-bundle)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.4M204](/packages/sulu-sulu)[open-dxp/opendxp

Content &amp; Product Management Framework (CMS/PIM)

9421.6k61](/packages/open-dxp-opendxp)[sylius/sylius

E-Commerce platform for PHP, based on Symfony framework.

8.5k5.9M737](/packages/sylius-sylius)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.6M576](/packages/shopware-core)[rcsofttech/audit-trail-bundle

Enterprise-grade, high-performance Symfony audit trail bundle. Automatically track Doctrine entity changes with split-phase architecture, multiple transports (HTTP, Queue, Doctrine), and sensitive data masking.

1189.8k](/packages/rcsofttech-audit-trail-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
