PHPackages                             andreo/eventsauce-bundle - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. andreo/eventsauce-bundle

AbandonedSymfony-bundle[Framework](/categories/framework)

andreo/eventsauce-bundle
========================

Symfony bundle for EventSauce.

3.0(3y ago)05.6kMITPHPPHP &gt;=8.2

Since Feb 23Pushed 9mo agoCompare

[ Source](https://github.com/andreo-code/eventsauce-bundle)[ Packagist](https://packagist.org/packages/andreo/eventsauce-bundle)[ RSS](/packages/andreo-eventsauce-bundle/feed)WikiDiscussions main Synced 1mo ago

READMEChangelogDependencies (17)Versions (5)Used By (0)

 [ ![](https://camo.githubusercontent.com/bb7103ec65390265f0c0cb66a8a182e699cc9929b6b02425b2b5894dae3dcc20/68747470733a2f2f6576656e7473617563652e696f2f7374617469632f6c6f676f2e737667) ](https://eventsauce.io)

EventSauceBundle 3.0
====================

[](#eventsaucebundle-30)

Official [documentation](https://eventsauce.io/docs/) of eventsauce

### Supports

[](#supports)

- Doctrine3 event store
- Symfony messenger message dispatcher
- Anti-Corruption Layer
- Event dispatcher
- Message Outbox
- Snapshot doctrine repository, versioning, conditional persist
- All events in table per aggregate type
- Generating migrations per aggregate

### Previous versions

[](#previous-versions)

- [2.0](https://github.com/eventsauce-symfony/eventsauce-bundle/tree/2.0.1)

### Requirements

[](#requirements)

- PHP &gt;=8.2
- Symfony ^6.2

### Installation

[](#installation)

```
composer require andreo/eventsauce-bundle
```

```
// config/bundles.php

return [
    Andreo\EventSauceBundle\AndreoEventSauceBundle::class => ['all' => true],
];
```

### Introduction

[](#introduction)

Below configs presents default values and some example values.
Note that most of default config values do not need to configure.

### [Clock](https://eventsauce.io/docs/utilities/clock/)

[](#clock)

```
andreo_event_sauce:
  clock:
    timezone: UTC
```

***Useful aliases***

```
EventSauce\Clock\Clock: EventSauce\Clock\SystemClock
```

### [Message Storage](https://eventsauce.io/docs/message-storage/)

[](#message-storage)

### Doctrine 3

[](#doctrine-3)

```
andreo_event_sauce:
  #...
  message_storage:
    repository:
      doctrine_3:
        enabled: true
        json_encode_flags: []
        connection: doctrine.dbal.default_connection
        table_name: event_store
```

Require

- doctrine/dbal

### Message dispatcher

[](#message-dispatcher)

[SynchronousMessageDispatcher](https://eventsauce.io/docs/reacting-to-events/setup-consumers/#synchronous-message-dispatcher)

```
andreo_event_sauce:
  #...
  message_dispatcher: # chain of message dispatchers
    foo_dispatcher:
      type:
        sync: true
    bar_dispatcher:
      type:
        sync: true
```

[EventConsumer](https://eventsauce.io/docs/reacting-to-events/projections-and-read-models/)

```
use EventSauce\EventSourcing\MessageConsumer;
use Andreo\EventSauceBundle\Attribute\AsSyncMessageConsumer;
use EventSauce\EventSourcing\EventConsumption\EventConsumer;
use Andreo\EventSauce\Messenger\EventConsumer\InjectedHandleMethodInflector;
use EventSauce\EventSourcing\Message;

#[AsSyncMessageConsumer(dispatcher: 'foo_dispatcher')]
final class FooBarEventConsumer extends EventConsumer
{
    // copy-paste trait for inject HandleMethodInflector of EventSauce
    use InjectedHandleMethodInflector;

    public function __construct(
        private HandleMethodInflector $handleMethodInflector
    ){}

    public function onFooCreated(FooCreated $fooCreated, Message $message): void {
    }

    public function onBarCreated(BarCreated $barCreated, Message $message): void {
    }
}
```

Example of manually registration sync consumer
(without attribute and autoconfiguration)

```
services:
  #...
  App\Consumer\FooBarEventConsumer:
    tags:
      -
        name: andreo.eventsauce.sync_message_consumer
```

[MessengerMessageDispatcher](https://github.com/andrew-pakula/eventsauce-messenger)

Dispatching with [Symfony messenger](https://symfony.com/doc/current/messenger.html)

Install [andreo/eventsauce-messenger](https://github.com/eventsauce-symfony/eventsauce-messenger)

```
composer require andreo/eventsauce-messenger
```

```
andreo_event_sauce:
 #...
  message_dispatcher: # chain of message dispatchers
    foo_dispatcher:
      type:
        messenger:
          bus: event_bus # bus alias from messenger config
```

It registers alias of handle event sauce message middleware:

```
$busAlias.handle_eventsauce_message: Andreo\EventSauce\Messenger\Middleware\HandleEventSauceMessageMiddleware
```

Update messenger config. According to above config

```
framework:
  messenger:
    #...
    buses:
      event_bus:
        default_middleware: false # disable default middleware order
        middleware:
          - 'add_bus_name_stamp_middleware': ['event_bus']
          - 'dispatch_after_current_bus'
          - 'failed_message_processing_middleware'
          - 'send_message'
          - 'event_bus.handle_eventsauce_message' # our middleware should be placed after send_message and before default handle massage middleware (if you use)
          - 'handle_message'
```

[EventConsumer](https://eventsauce.io/docs/reacting-to-events/projections-and-read-models/)

```
use Andreo\EventSauce\Messenger\EventConsumer\InjectedHandleMethodInflector;
use EventSauce\EventSourcing\EventConsumption\EventConsumer;
use EventSauce\EventSourcing\EventConsumption\HandleMethodInflector;
use Andreo\EventSauce\Messenger\Attribute\AsEventSauceMessageHandler;
use EventSauce\EventSourcing\Message;

final class FooBarEventConsumer extends EventConsumer
{
    use InjectedHandleMethodInflector;

    public function __construct(
        private HandleMethodInflector $handleMethodInflector
    )
    {}

    #[AsEventSauceMessageHandler(bus: 'fooBus')]
    public function onFooCreated(FooCreated $fooCreated, Message $message): void
    {
    }

    #[AsEventSauceMessageHandler(bus: 'barBus')]
    public function onBarCreated(BarCreated $barCreated, Message $message): void
    {
    }
}
```

***Useful aliases***

```
EventSauce\EventSourcing\EventConsumption\HandleMethodInflector: EventSauce\EventSourcing\EventConsumption\InflectHandlerMethodsFromType
```

**Message dispatcher tag** (for manually registration of dispatchers, if you will want)

```
andreo.eventsauce.message_dispatcher
```

### [Anti-Corruption Layer](https://eventsauce.io/docs/advanced/anti-corruption-layer/)

[](#anti-corruption-layer)

```
andreo_event_sauce:
  #...
  acl: true
```

Enable for **Message dispatcher** (by config)

```
andreo_event_sauce:
 #...
  message_dispatcher:
    fooDispatcher:
      type:
        messenger:
          bus: fooBus
      acl:
        enabled: true
        message_filter_strategy:
          before_translate: match_all # or match_any
          after_translate: match_all # or match_any
```

Enable for **Message consumer**

```
use Andreo\EventSauceBundle\Attribute\EnableAcl;
use Andreo\EventSauceBundle\Enum\MessageFilterStrategy;
use EventSauce\EventSourcing\EventConsumption\EventConsumer;

#[EnableAcl]
final class FooHandler extends EventConsumer
{
    #[AsEventSauceMessageHandler(
        handles: FooEvent::class // If you use a translator, "handles" must be configured.
    )]
    public function onFooCreated(BarEvent $barEvent): void
    {
        // ...
    }
}
```

Example of manually registration acl consumer (or dispatcher)
(without attribute and autoconfiguration)

```
services:
  #...
  App\Consumer\FooConsumer:
    tags:
      -
        name: andreo.eventsauce.acl
        message_filter_strategy_before_translate: match_all # or match_any
        message_filter_strategy_after_translate: match_all # or match_any
```

#### Message translator

[](#message-translator)

```
use EventSauce\EventSourcing\AntiCorruptionLayer\MessageTranslator;
use Andreo\EventSauceBundle\Attribute\AsMessageTranslator;
use EventSauce\EventSourcing\Message;

#[AsMessageTranslator]
final readonly class FooMessageTranslator implements MessageTranslator
{
    public function translateMessage(Message $message): Message
    {
        assert($message->payload() instanceof FooEvent);
        // ...

        return new Message(new BarEvent());
    }
}
```

Example of manually registration message filter
(without attribute and autoconfiguration)

```
services:
  #...
  App\Acl\FooMessageTranslator:
    tags:
      -
        name: andreo.eventsauce.acl.message_translator
        priority: 0
        owners: []
```

#### Message filter

[](#message-filter)

Message filter strategies:

`match_all` - all filters passed a condition
`match_any` - any filter passed a condition

Message Filter

```
use EventSauce\EventSourcing\AntiCorruptionLayer\MessageFilter;
use Andreo\EventSauceBundle\Attribute\AsMessageFilter;
use Andreo\EventSauceBundle\Enum\MessageFilterTrigger;

#[AsMessageFilter(MessageFilterTrigger::BEFORE_TRANSLATE)] // or after AFTER_TRANSLATE
final readonly class FooMessageFilter implements MessageFilter
{
    public function allows(Message $message): bool
    {
    }
}
```

Example of manually registration message filter
(without attribute and autoconfiguration)

```
services:
  #...
  App\Acl\FooMessageFilter:
    tags:
      -
        name: andreo.eventsauce.acl.message_filter
        trigger: before_translate # or after_translate
        priority: 0
        owners: []
```

#### Owners of message translator or filters

[](#owners-of-message-translator-or-filters)

For example, we use Translator, but Filter works the same

```
use EventSauce\EventSourcing\AntiCorruptionLayer\MessageTranslator;
use Andreo\EventSauceBundle\Attribute\AsMessageTranslator;
use EventSauce\EventSourcing\MessageConsumer;
use EventSauce\EventSourcing\MessageDispatcher;

// Translator will be using through all dispatchers as MessageDispatcher::class (or consumers as MessageConsumer::class)
// Single FooConsumer (or single FooDispatcher) uses translator also
#[AsMessageTranslator(owners: [MessageDispatcher::class, FooConsumer::class])]
final readonly class FooMessageTranslator implements MessageTranslator
{
    public function translateMessage(Message $message): Message
    {
    }
}
```

### [Event Dispatcher](https://eventsauce.io/docs/utilities/event-dispatcher/)

[](#event-dispatcher)

```
andreo_event_sauce:
  # ...
  event_dispatcher:
    enabled: false
    message_outbox:
      enabled: false
      table_name: event_message_outbox # it will be used if the outbox config has doctrine repository
      relay_id: event_dispatcher_relay # it is used by consume outbox message command
```

Example of Event Dispatcher

```
use EventSauce\EventSourcing\EventDispatcher;

final readonly class FooHandler
{
    public function __construct(
        private EventDispatcher $eventDispatcher
    ) {
    }

    public function handle(): void
    {
        $this->eventDispatcher->dispatch(
            new FooEvent()
        );
    }
}
```

### [Upcaster](https://eventsauce.io/docs/advanced/upcasting/#main-article)

[](#upcaster)

```
andreo_event_sauce:
    #...
  upcaster:
    enabled: false
    trigger: before_unserialize # or after_unserialize (on payload or on object of message)
```

Before unserialize

```
use Andreo\EventSauceBundle\Attribute\AsUpcaster;
use EventSauce\EventSourcing\Upcasting\Upcaster;

#[AsUpcaster(aggregateClass: FooAggregate::class, version: 2)]
final class FooEventV2Upcaster implements Upcaster {

    public function upcast(array $message): array
    {
    }
}
```

[After unserialize](https://github.com/andrew-pakula/eventsauce-upcasting)

Install [andreo/eventsauce-upcasting](https://github.com/eventsauce-symfony/eventsauce-upcasting)

```
composer require andreo/eventsauce-upcasting
```

```
use EventSauce\EventSourcing\Message;
use Andreo\EventSauce\Upcasting\MessageUpcaster\MessageUpcaster;
use Andreo\EventSauce\Upcasting\MessageUpcaster\Event;
use Andreo\EventSauceBundle\Attribute\AsUpcaster;

#[AsUpcaster(aggregateClass: FooAggregate::class, version: 2)]
final class SomeEventV2Upcaster implements MessageUpcaster {

    #[Event(event: FooEvent::class)]
    public function upcast(Message $message): Message
    {
    }
}
```

Example of manually registration (without attribute and autoconfiguration)

```
services:
  #...
  App\Upcaster\FooUpcaster:
    tags:
      -
        name: andreo.eventsauce.upcaster
        class: App\Domain\FooAggregate
        version: 2
```

### [Message decorator](https://eventsauce.io/docs/advanced/message-decoration/)

[](#message-decorator)

```
andreo_event_sauce:
    #...
    message_decorator: true
```

```
use Andreo\EventSauceBundle\Attribute\AsMessageDecorator;
use EventSauce\EventSourcing\Message;
use EventSauce\EventSourcing\MessageDecorator;

#[AsMessageDecorator]
final class FooDecorator implements MessageDecorator
{
    public function decorate(Message $message): Message
    {
    }
}
```

Example of manually registration (without attribute and autoconfiguration)

```
services:
  #...
  App\Decorator\FooDecorator:
    tags:
      -
        name: andreo.eventsauce.message_decorator
```

### [Message Outbox](https://eventsauce.io/docs/message-outbox/)

[](#message-outbox)

Install [andreo/eventsauce-outbox](https://github.com/eventsauce-symfony/eventsauce-outbox)

```
composer require andreo/eventsauce-outbox
```

Base configuration

```
andreo_event_sauce:
  #...
  message_outbox:
    enabled: false
    repository:
      doctrine:
        enabled: true
        table_name: message_outbox
    logger: Psr\Log\LoggerInterface # default if monolog bundle has been installed
```

Consume outbox messages

```
bin/console andreo:eventsauce:message-outbox:consume relay_id
```

***Useful aliases***

```
EventSauce\BackOff\BackOffStrategy: EventSauce\BackOff\ExponentialBackOffStrategy
```

```
EventSauce\MessageOutbox\RelayCommitStrategy: EventSauce\MessageOutbox\MarkMessagesConsumedOnCommit
```

### [Snapshotting](https://eventsauce.io/docs/snapshotting/)

[](#snapshotting)

**To use:**

- doctrine snapshot repository
- versioned snapshots
- conditional persist

package [andreo/eventsauce-snapshotting](https://github.com/eventsauce-symfony/eventsauce-snapshotting) is required

```
andreo_event_sauce:
  #...
  snapshot:
    enabled: false
    repository:
      enabled: false
      doctrine:
        enabled: true
        table_name: snapshot_store
    versioned: false # it enables versioned repository for all aggregates with snapshots enabled
    conditional: false
```

***Useful aliases***

```
Andreo\EventSauce\Snapshotting\Repository\Versioned\SnapshotVersionInflector: Andreo\EventSauce\Snapshotting\Repository\Versioned\InflectVersionFromReturnedTypeOfSnapshotStateCreationMethod
```

```
Andreo\EventSauce\Snapshotting\Repository\Versioned\SnapshotVersionComparator: Andreo\EventSauce\Snapshotting\Repository\Versioned\EqSnapshotVersionComparator
```

### [Migration generator](https://github.com/eventsauce-symfony/eventsauce-migration-generator)

[](#migration-generator)

Install [andreo/eventsauce-migration-generator](https://github.com/eventsauce-symfony/eventsauce-migration-generator)

```
andreo_event_sauce:
  #...
  migration_generator:
    dependency_factory: doctrine.migrations.dependency_factory # default if doctrine migrations bundle has been installed
```

Generate migration for foo prefix

```
bin/console andreo:eventsauce:doctrine-migrations:generate foo
```

***Useful aliases***

```
EventSauce\MessageRepository\TableSchema\TableSchema: EventSauce\MessageRepository\TableSchema\DefaultTableSchema
```

### [Aggregates](https://eventsauce.io/docs/event-sourcing/create-an-aggregate-root)

[](#aggregates)

```
andreo_event_sauce:
  #...
  aggregates:
    foo: # aggregate name
      class: ~ # aggregate FQCN
      repository_alias: fooRepository # according to convention: $name . "Repository"
      message_outbox:
        enabled: false # enable message outbox for this aggregate
        relay_id: foo_aggregate_relay # relay-id for run consume outbox messages command, according to convention: $name . "aggregate_relay"
      dispatchers: [] # dispatcher service aliases (from config, or manually registered), if empty, messages will be sent to all dispatchers
      upcaster: false # enable upcaster for this aggregate
      snapshot:
        conditional: # enable conditional snapshot repository for this aggregate.
          enabled: false
          every_n_event: # you can use this strategy, or make your own implementation
            enabled: false
            number: 100
```

Repository injection

```
use Symfony\Component\DependencyInjection\Attribute\Target;
use EventSauce\EventSourcing\AggregateRootRepository;

final class FooHandler {

   public function __construct(
        #[Target('fooRepository')] private AggregateRootRepository $fooRepository
    ){}
}
```

Snapshotting repository injection (if aggregate snapshot is enabled)

```
use Symfony\Component\DependencyInjection\Attribute\Target;
use EventSauce\EventSourcing\Snapshotting\AggregateRootRepositoryWithSnapshotting;

final class FooHandler {

   public function __construct(
        #[Target('fooRepository')] private AggregateRootRepositoryWithSnapshotting $fooRepository
    ){}
}
```

***Useful aliases***

```
andreo.eventsauce.snapshot.conditional_strategy.$aggregateName: Andreo\EventSauce\Snapshotting\Repository\Conditional\ConditionalSnapshotStrategy
```

```
EventSauce\EventSourcing\Serialization\PayloadSerializer: EventSauce\EventSourcing\Serialization\ConstructingPayloadSerializer
```

```
EventSauce\EventSourcing\Serialization\MessageSerializer: EventSauce\EventSourcing\Serialization\ConstructingMessageSerializer
```

```
EventSauce\UuidEncoding\UuidEncoder: EventSauce\UuidEncoding\BinaryUuidEncoder
```

```
EventSauce\EventSourcing\ClassNameInflector: EventSauce\EventSourcing\DotSeparatedSnakeCaseInflector
```

### Other tips

[](#other-tips)

#### Decorating aggregate root repository

[](#decorating-aggregate-root-repository)

```
