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

Es Lib Bundle Laravel Package

awd-studio/es-lib-bundle

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the Bundle

    composer require awd-studio/es-lib-bundle
    

    Ensure your composer.json meets the requirements (PHP 8.3+, Symfony 7.2+, Doctrine ORM).

  2. Enable the Bundle Add to config/bundles.php:

    return [
        AwdStudio\EsLibBundle\AwdEsBundle::class => ['all' => true],
    ];
    
  3. Configure the Bundle Create config/packages/awd_es.yaml:

    awd_es:
        event_store:
            driver: doctrine # or 'sqlite' for testing
            connection: default
        aggregates:
            - 'App\Entity\YourAggregate'
    
  4. Define an Aggregate Create an aggregate class (e.g., src/Entity/UserAggregate.php):

    namespace App\Entity;
    
    use AwdStudio\EsLib\Aggregate\AggregateRoot;
    use AwdStudio\EsLib\Event\EventInterface;
    
    class UserAggregate extends AggregateRoot
    {
        public function handle(EventInterface $event): void
        {
            // Handle events (e.g., update state)
        }
    
        public function create(string $name): void
        {
            $this->recordThat(new UserCreated($this->id, $name));
        }
    }
    
  5. First Use Case: Persisting an Event Inject the AggregateRepository and save an aggregate:

    use AwdStudio\EsLibBundle\Repository\AggregateRepository;
    
    class UserService
    {
        public function __construct(private AggregateRepository $aggregateRepo) {}
    
        public function registerUser(string $name): void
        {
            $aggregate = new UserAggregate();
            $aggregate->create($name);
            $this->aggregateRepo->save($aggregate);
        }
    }
    

Implementation Patterns

Core Workflow: Event-Driven Domain Logic

  1. Aggregate Design

    • Extend AggregateRoot for domain entities.
    • Define methods that emit events (e.g., create(), update()).
    • Implement handle(EventInterface) to react to past events (replay).
  2. Event Handling

    • Events must implement EventInterface (e.g., UserCreated, UserUpdated).
    • Use recordThat() to append events to the aggregate’s event stream.
  3. Repository Integration

    • Use AggregateRepository to load/save aggregates by ID:
      $aggregate = $aggregateRepo->load(UserAggregate::class, $id);
      $aggregate->updateProfile($newData);
      $aggregateRepo->save($aggregate);
      
  4. Event Storage

    • Configure Doctrine as the event store (default) or use SQLite for testing.
    • Events are stored in a table named event_store (customizable via config).

Common Patterns

  • Command Handling Map commands (e.g., RegisterUserCommand) to aggregate methods:

    $commandHandler = new RegisterUserCommandHandler($aggregateRepo);
    $commandHandler->handle(new RegisterUserCommand($name));
    
  • Projection Updates Subscribe to events to update read models (e.g., Elasticsearch, caches):

    $eventSubscriber = new UserProjectionSubscriber($elasticsearchClient);
    $eventDispatcher->addSubscriber($eventSubscriber);
    
  • Testing Aggregates Use AggregateTestCase to test event sourcing logic:

    public function testUserCreation()
    {
        $aggregate = new UserAggregate();
        $aggregate->create('John Doe');
        $this->assertEquals(['UserCreated'], $aggregate->getUncommittedEvents());
    }
    

Integration Tips

  • Doctrine Entities If your aggregate is also a Doctrine entity, extend both AggregateRoot and BaseEntity:

    use Doctrine\ORM\Mapping as ORM;
    use AwdStudio\EsLib\Aggregate\AggregateRoot;
    
    #[ORM\Entity]
    class UserAggregate extends AggregateRoot
    {
        #[ORM\Id]
        #[ORM\Column(type: 'string')]
        private string $id;
    }
    
  • Symfony Messenger Dispatch events as messages for async processing:

    $eventBus->dispatch(new UserCreated($id, $name));
    
  • Custom Event Store Implement EventStoreInterface for non-Doctrine storage (e.g., MongoDB, Redis):

    awd_es:
        event_store:
            driver: custom
            service: app.custom_event_store
    

Gotchas and Tips

Pitfalls

  1. Event Ordering

    • Events are stored in chronological order. Never modify past events directly (use recordThat() for new events).
    • Fix: Use AggregateRoot::loadFromHistory() to replay events if the stream is corrupted.
  2. Aggregate Loading

    • AggregateRepository::load() throws AggregateNotFoundException if the ID doesn’t exist.
    • Fix: Wrap in a try-catch or use AggregateRepository::exists().
  3. Doctrine Event Store Mismatch

    • If the event_store table schema doesn’t match, events won’t persist.
    • Fix: Run migrations or manually create the table:
      CREATE TABLE event_store (
          id BIGINT AUTO_INCREMENT PRIMARY KEY,
          aggregate_id VARCHAR(255) NOT NULL,
          aggregate_type VARCHAR(255) NOT NULL,
          event_data JSON NOT NULL,
          occurred_on DATETIME NOT NULL
      );
      
  4. Circular Dependencies

    • Avoid injecting AggregateRepository into aggregates (violates DDD principles).
    • Fix: Use dependency injection only in services/command handlers.
  5. Event Serialization

    • Events must be serializable (e.g., via Symfony\Component\Serializer).
    • Fix: Annotate events with @Serializer\SerializedName or implement JsonSerializable.

Debugging Tips

  • Enable Event Logging Configure the event bus to log dispatched events:

    awd_es:
        event_bus:
            logger: true
    
  • Inspect Event Streams Use the EventStore service to query events:

    $events = $eventStore->getEventsForAggregate(UserAggregate::class, $id);
    
  • Check Aggregate State Override AggregateRoot::getState() to debug current state:

    public function getState(): array
    {
        return ['name' => $this->name, 'version' => $this->version];
    }
    

Configuration Quirks

  • Default Connection The connection key in event_store defaults to default. Specify a custom connection:

    awd_es:
        event_store:
            connection: my_custom_connection
    
  • Aggregate Naming The bundle auto-discovers aggregates listed in aggregates config. For dynamic discovery, implement AggregateRegistryInterface.

  • Event Versioning The bundle doesn’t auto-version events. Manually set event_version in your event classes if needed.

Extension Points

  1. Custom Event Store Implement AwdStudio\EsLib\EventStore\EventStoreInterface and bind it as a service:

    services:
        app.custom_event_store:
            class: App\EventStore\CustomEventStore
            arguments:
                - '@doctrine.dbal.connection'
    
  2. Event Subscribers Extend AwdStudio\EsLib\EventBus\SubscriberInterface:

    class MySubscriber implements SubscriberInterface
    {
        public function handle(EventInterface $event): void
        {
            // React to events
        }
    }
    
  3. Aggregate Snapshotting Implement AwdStudio\EsLib\Aggregate\SnapshotableInterface to optimize large event streams:

    class UserAggregate extends AggregateRoot implements SnapshotableInterface
    {
        public function takeSnapshot(): array
        {
            return ['name' => $this->name];
        }
    }
    
  4. Custom Event Dispatcher Replace the default EventBus with a custom implementation (e.g., for async dispatch):

    awd_es:
        event_bus:
            service: app.async_event_bus
    
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.
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
spatie/mailcoach-vapor