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

Domain Laravel Package

biig/domain

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require biig/domain
    

    For Laravel (Symfony-compatible), ensure you have symfony/doctrine-bridge and doctrine/orm installed.

  2. First Use Case: Define a Domain Event and dispatch it from a Doctrine entity:

    // src/Domain/Events/UserRegistered.php
    namespace App\Domain\Events;
    use Biig\Domain\DomainEvent;
    
    class UserRegistered extends DomainEvent
    {
        public function __construct(private int $userId) {}
        public function getUserId(): int { return $this->userId; }
    }
    

    Dispatch it in an entity:

    // src/Domain/Entities/User.php
    namespace App\Domain\Entities;
    use Biig\Domain\DomainEventDispatcher;
    use Doctrine\ORM\Mapping as ORM;
    
    #[ORM\Entity]
    class User
    {
        #[ORM\Id, ORM\GeneratedValue]
        private ?int $id = null;
    
        public function register(DomainEventDispatcher $dispatcher): void
        {
            $this->id = 123; // Simulate ID assignment
            $dispatcher->dispatch(new UserRegistered($this->id));
        }
    }
    
  3. Register the Dispatcher: In config/services.php (Laravel) or Symfony DI container:

    // Laravel: config/services.php
    'domain_event_dispatcher' => Biig\Domain\DomainEventDispatcher::class,
    

Implementation Patterns

Workflows

  1. Event-Driven Domain Logic:

    • Use events to decouple domain logic from infrastructure (e.g., notifications, analytics).
    • Example: Trigger OrderShipped event after saving an Order entity.
  2. Factory Pattern for Entities:

    • Avoid direct instantiation of entities. Use a factory to ensure proper initialization:
      // src/Domain/Factories/UserFactory.php
      class UserFactory
      {
          public function create(array $data): User
          {
              $user = new User();
              $user->setName($data['name']);
              return $user;
          }
      }
      
  3. Symfony Serializer Integration:

    • Serialize domain events for APIs or queues:
      use Biig\Domain\Serializer\DomainEventSerializer;
      
      $serializer = new DomainEventSerializer();
      $eventJson = $serializer->serialize([new UserRegistered(1)], 'json');
      
  4. Doctrine Event Listeners:

    • Attach listeners to domain events in config/packages/doctrine.yaml (Symfony) or Laravel's EventServiceProvider:
      # Symfony
      doctrine:
          orm:
              event_listeners:
                  App\Domain\Listeners\SendWelcomeEmail:
                      tags: [doctrine.event_listener]
      

Integration Tips

  • Laravel-Specific:

    • Bind the dispatcher to Laravel's container in AppServiceProvider:
      public function register()
      {
          $this->app->singleton(DomainEventDispatcher::class, function ($app) {
              return new DomainEventDispatcher();
          });
      }
      
    • Use Laravel's Event facade to listen to domain events (if needed):
      use Illuminate\Support\Facades\Event;
      
      Event::listen(UserRegistered::class, function ($event) {
          // Handle event
      });
      
  • ApiPlatform:

    • Annotate domain events with @ApiResource to expose them as API endpoints:
      use ApiPlatform\Core\Annotation\ApiResource;
      
      #[ApiResource]
      class UserRegistered extends DomainEvent {}
      

Gotchas and Tips

Pitfalls

  1. Entity Instantiation:

    • Gotcha: Directly instantiating entities (e.g., new User()) will fail if they rely on the dispatcher.
    • Fix: Always use a factory or repository to create entities.
  2. Circular Dependencies:

    • Gotcha: Injecting the dispatcher into entities can cause circular references if not managed.
    • Fix: Use lazy loading or pass the dispatcher as a parameter to entity methods (e.g., register(DomainEventDispatcher $dispatcher)).
  3. Event Dispatch Timing:

    • Gotcha: Events dispatched in entity setters may not trigger if the entity isn't persisted yet.
    • Fix: Dispatch events in prePersist/preUpdate Doctrine lifecycle callbacks or after explicit persistence.
  4. Serializer Compatibility:

    • Gotcha: Custom domain events may not serialize/deserialize correctly without proper annotations.
    • Fix: Implement JsonSerializable or add Symfony serializer groups:
      use Symfony\Component\Serializer\Annotation\Groups;
      
      class UserRegistered extends DomainEvent
      {
          #[Groups(['event'])]
          public function getUserId(): int { return $this->userId; }
      }
      

Debugging

  • Event Dispatch Logs: Enable debug logs for the biig.domain channel in config/logging.php (Laravel) or Symfony's monolog config:

    'channels' => [
        'biig.domain' => [
            'driver' => 'single',
            'path' => storage_path('logs/domain.log'),
            'level' => 'debug',
        ],
    ],
    
  • Doctrine Event Debugging: Use stderr logging for Doctrine events:

    # config/packages/doctrine.yaml (Symfony)
    doctrine:
        orm:
            logging: true
            logging_params:
                log_to_stderr: true
    

Extension Points

  1. Custom Event Dispatcher:

    • Extend DomainEventDispatcher to add middleware or logging:
      class CustomDispatcher extends DomainEventDispatcher
      {
          public function dispatch(DomainEvent $event): void
          {
              logger()->debug("Dispatching event: " . get_class($event));
              parent::dispatch($event);
          }
      }
      
  2. Event Subscribers:

    • Create subscribers for cross-cutting concerns (e.g., auditing):
      use Biig\Domain\DomainEventSubscriber;
      
      class AuditSubscriber implements DomainEventSubscriber
      {
          public function getSubscribedEvents(): array
          {
              return [
                  UserRegistered::class => 'onUserRegistered',
              ];
          }
      
          public function onUserRegistered(UserRegistered $event): void
          {
              // Audit logic
          }
      }
      
  3. Doctrine Extensions:

    • Add custom lifecycle callbacks to entities for event dispatching:
      #[ORM\Entity]
      class User
      {
          #[ORM\LifecycleCallbacks]
          class UserCallbacks
          {
              public function prePersist(User $user, EntityManagerInterface $em)
              {
                  $user->dispatcher->dispatch(new UserRegistered($user->id));
              }
          }
      }
      

Performance Tips

  • Batch Event Dispatching:
    • For bulk operations, dispatch events in batches to avoid overhead:
      $dispatcher->dispatch(new BulkUserRegistered([1, 2, 3]));
      
  • Lazy Event Loading:
    • Use Doctrine's UnitOfWork to defer event dispatching until flush:
      $em->persist($user);
      $em->flush(); // Events dispatch here
      
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky