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

Doctrine Modification Events Bundle Laravel Package

dmytrof/doctrine-modification-events-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require dmytrof/doctrine-modification-events-bundle
    

    Enable the bundle in config/bundles.php:

    Dmytrof\DoctrineModificationEventsBundle\DmytrofDoctrineModificationEventsBundle::class => ['all' => true],
    
  2. First Use Case:

    • Trigger Events on Entity Updates: Annotate your entity with @ModificationEvent to automatically dispatch events when fields change.
      use Dmytrof\DoctrineModificationEventsBundle\Annotation\ModificationEvent;
      
      /**
       * @ModificationEvent("user.updated", fields={"email", "status"})
       */
      class User {}
      
    • Listen for Events: Create a listener to handle the dispatched events:
      namespace App\EventListener;
      
      use Symfony\Component\EventDispatcher\EventSubscriberInterface;
      use Dmytrof\DoctrineModificationEventsBundle\Event\ModificationEvent;
      
      class UserUpdateListener implements EventSubscriberInterface
      {
          public static function getSubscribedEvents(): array
          {
              return [
                  'user.updated' => 'onUserUpdated',
              ];
          }
      
          public function onUserUpdated(ModificationEvent $event): void
          {
              $entity = $event->getEntity();
              $changes = $event->getChanges();
              // Handle changes (e.g., log, notify, audit)
          }
      }
      
  3. Where to Look First:

    • Bundle Docs: Check the Annotation and Event classes in the bundle’s src directory for available configurations.
    • Symfony EventDispatcher: Familiarize yourself with Symfony’s event system if unfamiliar.
    • Entity Annotations: Focus on the @ModificationEvent annotation for defining event triggers.

Implementation Patterns

Common Workflows

  1. Tracking Field-Specific Changes: Use the fields attribute in @ModificationEvent to narrow event triggers to specific fields:

    /**
     * @ModificationEvent("order.status_changed", fields={"status"})
     */
    class Order {}
    
    • Listener:
      public function onOrderStatusChanged(ModificationEvent $event): void
      {
          $oldStatus = $event->getOldValue('status');
          $newStatus = $event->getNewValue('status');
          // Logic for status transitions (e.g., send notifications)
      }
      
  2. Bulk Entity Updates: For Doctrine\ORM\QueryBuilder or Repository::createQueryBuilder(), ensure the bundle’s event listener is registered globally (via bundles.php). Events will trigger automatically for UPDATE operations.

  3. Conditional Event Dispatching: Combine with Symfony’s EventDispatcher to add logic:

    public function onUserUpdated(ModificationEvent $event): void
    {
        if ($event->hasChange('status') && $event->getNewValue('status') === 'active') {
            $this->notifyAdmin($event->getEntity());
        }
    }
    
  4. Integration with Doctrine Lifecycle Callbacks: Use @PreUpdate or @PostUpdate alongside @ModificationEvent for hybrid workflows:

    use Doctrine\ORM\Mapping as ORM;
    
    /**
     * @ORM\PreUpdate
     * @ModificationEvent("user.pre_update")
     */
    class User {}
    
  5. Dynamic Event Names: Generate event names dynamically based on entity metadata:

    $eventName = sprintf('entity.%s.%s', $entityClass, 'updated');
    $this->eventDispatcher->dispatch($eventName, new ModificationEvent($entity, $changes));
    

Best Practices

  • Namespace Events: Prefix event names with your bundle/entity namespace (e.g., app.user.updated) to avoid collisions.
  • Test Event Triggers: Use PHPUnit to verify events fire as expected:
    public function testUserEmailUpdateEvent()
    {
        $user = new User();
        $user->setEmail('new@example.com');
        $this->entityManager->persist($user);
        $this->entityManager->flush();
    
        $this->assertEventDispatched('user.updated');
    }
    
  • Performance: Avoid heavy logic in event listeners. Offload work to services or queues if needed.

Gotchas and Tips

Pitfalls

  1. Event Not Triggering:

    • Cause: Forgetting to enable the bundle in bundles.php or misconfiguring the annotation.
    • Fix: Verify the bundle is enabled and annotations are parsed (use doctrine:schema:validate to check).
  2. Incorrect Field Changes:

    • Cause: The fields attribute in @ModificationEvent is case-sensitive or misspelled.
    • Fix: Double-check field names against the entity’s getter/setter methods.
  3. Circular Dependencies:

    • Cause: Event listeners depending on entities that trigger events (e.g., UserListener updating User in onUserUpdated).
    • Fix: Use services or repositories to decouple logic. Avoid direct entity manipulation in listeners.
  4. Doctrine Proxy Issues:

    • Cause: Events may not trigger for proxied entities (e.g., lazy-loaded collections).
    • Fix: Ensure entities are fully initialized before updates or use entityManager->refresh() if needed.
  5. Symfony Cache:

    • Cause: Changes to annotations or event configurations require cache clearing:
      php bin/console cache:clear
      

Debugging Tips

  • Log Events: Temporarily log dispatched events to verify triggers:
    public function onUserUpdated(ModificationEvent $event): void
    {
        $this->logger->info('Event triggered', ['event' => $event->getName(), 'changes' => $event->getChanges()]);
    }
    
  • Check Event Dispatcher: Use Symfony’s EventDispatcher debug command to list subscribed events:
    php bin/console debug:event-dispatcher
    
  • Inspect Entity Changes: Use Doctrine’s UnitOfWork to debug changes:
    $uow = $this->entityManager->getUnitOfWork();
    $changes = $uow->getEntityChangeSet($entity);
    

Extension Points

  1. Custom Event Classes: Extend Dmytrof\DoctrineModificationEventsBundle\Event\ModificationEvent to add custom data:

    class CustomModificationEvent extends ModificationEvent
    {
        public function __construct(object $entity, array $changes, private string $customData) {}
        public function getCustomData(): string { return $this->customData; }
    }
    

    Update annotations to use the new event name.

  2. Dynamic Field Mapping: Override the bundle’s ModificationEventListener to dynamically resolve fields:

    public function onFlush(): void
    {
        $entity = $this->uow->getEntityChangeSet($entity);
        if ($entity && $this->isEventTriggered($entity)) {
            $this->dispatchEvent($entity, $entity);
        }
    }
    
  3. Batch Processing: For bulk updates, disable event dispatching temporarily:

    $this->entityManager->getEventManager()->removeEventListeners('user.updated');
    // Perform bulk updates
    $this->entityManager->flush();
    $this->entityManager->getEventManager()->addEventListener('user.updated', [$listener, 'onUserUpdated']);
    
  4. API Versioning: Use events to trigger actions for specific API versions (e.g., user.v1.updated). Combine with Symfony’s RequestContext or custom headers.

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.
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
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager