atournayre/entities-events-bundle
Install the Bundle
composer require atournayre/entities-events-bundle
Register in config/bundles.php:
Atournayre\Bundle\EntitiesEventsBundle\AtournayreEntitiesEventsBundle::class => ['all' => true],
Generate Listeners Run the console command to scaffold Doctrine event listeners:
php bin/console atournayre:entities-events:generate-listeners
This creates listeners for prePersist, preUpdate, preRemove, and postFlush events.
Annotate Your Entity
Implement HasEventsInterface and use EventsTrait:
use Atournayre\Bundle\EntitiesEventsBundle\Contracts\HasEventsInterface;
use Atournayre\Bundle\EntitiesEventsBundle\Traits\EventsTrait;
class User implements HasEventsInterface
{
use EventsTrait;
public function __construct()
{
$this->eventCollection = new EventCollection(); // Auto-injected via trait
}
}
First Event Dispatch
Create a custom event (e.g., UserRegisteredEvent) and dispatch it:
$this->addEvent(new UserRegisteredEvent($this));
Entity Creation
prePersist listener to trigger events before saving.UserCreatedEvent when a new User is persisted.Entity Updates
preUpdate listener to detect changes (e.g., via UnitOfWork).UserProfileUpdatedEvent when email or name changes.Entity Deletion
preRemove listener to trigger cleanup (e.g., soft deletes, notifications).UserDeletedEvent before deletion.Post-Save Actions
postFlush listener for async tasks (e.g., sending emails, logging).OrderProcessedEvent after Order is saved.Doctrine Lifecycle Events
Leverage Doctrine’s LifecycleEventArgs in listeners to access the EntityManager and UnitOfWork:
#[AsEventListener(event: 'prePersist')]
public function onPrePersist(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
if ($entity instanceof HasEventsInterface) {
$entity->dispatchEvents(); // Trigger all queued events
}
}
Event Collection Management
Use EventCollection to batch events (e.g., for bulk operations):
$user->addEvent(new UserEvent($user, 'action', ['data']));
$user->dispatchEvents(); // Dispatch all at once
Conditional Event Dispatch Filter events based on entity state or business logic:
if ($entity->isActive()) {
$entity->addEvent(new UserActivatedEvent($entity));
}
Symfony Messenger Bridge
Combine with Symfony\Component\Messenger for async event handling:
#[AsEventListener]
public function handleEvent(UserEvent $event): void
{
$bus->dispatch(new AsyncUserEvent($event->getEntity()));
}
Listener Registration
generate-listeners or misconfiguring bundles.php.config/packages/atournayre_entities_events.yaml after generation.Event Ordering
prePersist).EventCollection to batch events and dispatch them in a controlled sequence.Circular Dependencies
UnitOfWork to check if the entity is already managed:
if (!$entityManager->contains($entity)) {
return;
}
Performance
postFlush for batch processing.Log Events Add a debug listener to log dispatched events:
#[AsEventListener]
public function logEvent(object $event): void
{
$this->logger->debug(sprintf(
'Event "%s" dispatched for entity %s',
get_class($event),
$event instanceof Event ? $event->getEntity() : 'unknown'
));
}
Check Event Collection
Verify events are added to EventCollection before dispatch:
$this->assertCount(1, $user->getEventCollection());
Doctrine Event Priority Override listener priority in attributes:
#[AsEventListener(priority: 255)] // Highest priority
public function highPriorityListener(UserEvent $event): void {}
Custom Event Types
Extend Event to include metadata:
class UserEvent extends Event
{
public function __construct(
public readonly User $user,
public string $action,
public array $metadata = []
) {}
}
Dynamic Event Dispatch Use reflection to auto-dispatch events based on entity methods:
if (method_exists($entity, 'on' . class_basename($event))) {
$entity->{'on' . class_basename($event)}($event);
}
Event Subscribers Group related listeners into a subscriber:
#[AsEventListener]
class UserEventSubscriber
{
#[OnKernelEvent('user.created')]
public function onUserCreated(UserCreatedEvent $event): void {}
#[OnKernelEvent('user.updated')]
public function onUserUpdated(UserUpdatedEvent $event): void {}
}
Doctrine Event Subscribers
Extend Doctrine\Common\EventSubscriber for low-level control:
class EntityEventSubscriber implements EventSubscriber
{
public function getSubscribedEvents(): array
{
return [
LifecycleEvents::prePersist,
LifecycleEvents::preUpdate,
];
}
public function prePersist(LifecycleEventArgs $args): void
{
$entity = $args->getObject();
if ($entity instanceof HasEventsInterface) {
$entity->dispatchEvents();
}
}
}
How can I help you explore Laravel packages today?