Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Entities Events Bundle Laravel Package

atournayre/entities-events-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require atournayre/entities-events-bundle
    

    Register in config/bundles.php:

    Atournayre\Bundle\EntitiesEventsBundle\AtournayreEntitiesEventsBundle::class => ['all' => true],
    
  2. 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.

  3. 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
        }
    }
    
  4. First Event Dispatch Create a custom event (e.g., UserRegisteredEvent) and dispatch it:

    $this->addEvent(new UserRegisteredEvent($this));
    

Implementation Patterns

Workflow: Event-Driven Entity Lifecycle

  1. Entity Creation

    • Use prePersist listener to trigger events before saving.
    • Example: Dispatch UserCreatedEvent when a new User is persisted.
  2. Entity Updates

    • Use preUpdate listener to detect changes (e.g., via UnitOfWork).
    • Example: Dispatch UserProfileUpdatedEvent when email or name changes.
  3. Entity Deletion

    • Use preRemove listener to trigger cleanup (e.g., soft deletes, notifications).
    • Example: Dispatch UserDeletedEvent before deletion.
  4. Post-Save Actions

    • Use postFlush listener for async tasks (e.g., sending emails, logging).
    • Example: Dispatch OrderProcessedEvent after Order is saved.

Integration Tips

  • 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()));
    }
    

Gotchas and Tips

Pitfalls

  1. Listener Registration

    • Issue: Forgetting to run generate-listeners or misconfiguring bundles.php.
    • Fix: Verify listeners exist in config/packages/atournayre_entities_events.yaml after generation.
  2. Event Ordering

    • Issue: Events may fire out of expected order if not dispatched explicitly (e.g., during prePersist).
    • Fix: Use EventCollection to batch events and dispatch them in a controlled sequence.
  3. Circular Dependencies

    • Issue: Listeners depending on entities that trigger events can cause infinite loops.
    • Fix: Use UnitOfWork to check if the entity is already managed:
      if (!$entityManager->contains($entity)) {
          return;
      }
      
  4. Performance

    • Issue: Dispatching too many events during bulk operations.
    • Fix: Debounce events or use postFlush for batch processing.

Debugging Tips

  • 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 {}
    

Extension Points

  1. 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 = []
        ) {}
    }
    
  2. 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);
    }
    
  3. 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 {}
    }
    
  4. 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();
            }
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
emuniq/filament-browser-notifications
syriable/filament-translator
hungnm28/livewire-form
wenprise/eloquent
crudly/encrypted
fadion/bouncy
cuci/prototurk-sdk
gos/pubsub-router-bundle
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui