Manual Control
To manually manage domain events, you can use
DomainEventAwareEntityManagerInterface
in place of the regular
EntityManagerInterface
. It adds several methods to the Entity Manager that you
can use to manage domain event dispatching.
Manual Dispatching
You can disable automatic dispatching on flush()
by calling
setAutoDispatchDomainEvents(false)
.
use Rekalogika\DomainEvent\DomainEventAwareEntityManagerInterface;
/** @var DomainEventAwareEntityManagerInterface $entityManager */
$entityManager->setAutoDispatchDomainEvents(false);
// ...
$entityManager->dispatchPreFlushDomainEvents();
$entityManager->flush();
$entityManager->dispatchPostFlushDomainEvents();
Immediate dispatching is dispatched outside DomainEventAwareEntityManager
, and
therefore unaffected by setAutoDispatchDomainEvents()
.
Clearing the Events
If the domain event queues are not empty at the end of the request,
DomainEventEntityManager
will throw UndispatchedEventsException
. To prevent
that from happening, if you disable auto-dispatch, you need to make sure that
you dispatch both pre-flush and post-flush events as above. Alternatively, you
can clear the events if you don't want them dispatched:
use Rekalogika\DomainEvent\DomainEventAwareEntityManagerInterface;
/** @var DomainEventAwareEntityManagerInterface $entityManager */
$entityManager->setAutoDispatchDomainEvents(false);
// ...
$entityManager->flush();
$entityManager->clearDomainEvents();
In the event of an uncaught error, the framework will automatically
clear undispatched events using the kernel.exception
and console.error
events, so in such cases, you don't have to handle that manually. But if you
catch an exception that previously caused pending events not to be dispatched,
you need to manually clear the events.
Getting the Events From the Queue and Dispatching Them Elsewhere
You can get the undispatched events in the queue by calling popDomainEvents()
.
use Rekalogika\DomainEvent\DomainEventAwareEntityManagerInterface;
/** @var DomainEventAwareEntityManagerInterface $entityManager */
$events = $entityManager->popDomainEvents();
As it suggests, popDomainEvents()
also removes the events from the queue.
Then, you can dispatch them in another place, for example, in another process, or at the end of a batch process.
use Rekalogika\DomainEvent\DomainEventAwareEntityManagerInterface;
/** @var DomainEventAwareEntityManagerInterface $entityManager */
$entityManager->recordDomainEvent($events);
$entityManager->dispatchPreFlushDomainEvents();
$entityManager->flush();
$entityManager->dispatchPostFlushDomainEvents();
You might find the DomainEventStore
object useful. You can use it to store the
events in transit. It handles EquatableDomainEventInterface
and will
automatically discard duplicate events.
use Rekalogika\DomainEvent\DomainEventAwareEntityManagerInterface;
use Rekalogika\DomainEvent\Model\DomainEventStore;
/** @var DomainEventAwareEntityManagerInterface $entityManager */
$domainEventStore = new DomainEventStore();
// a batch process
foreach (...) {
// ...
$domainEventStore->add($entityManager->popDomainEvents());
}
// ...
// now at the end of the batch process
$entityManager->recordDomainEvent($domainEventStore);
$entityManager->dispatchPreFlushDomainEvents();
$entityManager->flush();
$entityManager->dispatchPostFlushDomainEvents();
Multiple Entity Managers
When working with multiple entity managers, usually the ManagerRegistry
is
used to get the correct entity manager. This method still works with domain
events without any change.
However, if you need the domain-event-specific methods, you can use
DomainEventAwareManagerRegistry
in place of ManagerRegistry
. It adds several
methods to the registry that you can use to manage domain event dispatching:
getDomainEventAwareManager()
getDomainEventAwareManagers()
getDomainEventAwareManagerForClass()
These are basically the same as their counterparts in ManagerRegistry
, only
return DomainEventAwareObjectManager
instead of ObjectManager
.