gember / event-sourcing-universal-service-provider
Universal service provider for Gember Event Sourcing (gember/event-sourcing)
Package info
github.com/GemberPHP/event-sourcing-universal-service-provider
pkg:composer/gember/event-sourcing-universal-service-provider
Requires
- php: ^8.3
- composer-runtime-api: ^2.0
- container-interop/service-provider: ^0.4.1
- doctrine/dbal: ^4.2
- gember/dependency-contracts: ^0.9
- gember/event-sourcing: ^0.22
- gember/identity-generator-symfony: ^0.12
- gember/message-bus-symfony: ^0.12
- gember/rdbms-event-store-doctrine-dbal: ^0.21 || ^0.22
- gember/serializer-symfony: ^0.12
- psr/container: ^2.0
- psr/log: ^3.0
- psr/simple-cache: ^3.0
- symfony/cache: ^7.1|^7.2|^8.0
- symfony/property-access: ^7.1|^7.2|^8.0
- symfony/serializer: ^7.1|^7.2|^8.0
- symfony/uid: ^7.1|^7.2|^8.0
Requires (Dev)
- captainhook/captainhook: ^5.23
- friendsofphp/php-cs-fixer: ^3.64
- phpstan/phpstan: ^2.1
- rector/rector: ^2.0
- shipmonk/composer-dependency-analyser: ^1.7
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- 0.16.1
- 0.16.0
- 0.15.2
- 0.15.1
- 0.15.0
- 0.14.1
- 0.14.0
- 0.13.0
- 0.12.0
- 0.11.0
- 0.10.0
- 0.9.0
- 0.8.0
- 0.7.0
- 0.6.0
- 0.5.0
- 0.4.0
- 0.3.1
- 0.3.0
- 0.2.0
- 0.1.0
- dev-add-build-badge
- dev-project-root-registry-path
- dev-support-event-sourcing-0.22
- dev-readme-review
- dev-default-uid-factories
- dev-initialize-use-case-attribute-registry
- dev-outbox-retry-backoff
- dev-resolver-refactor
This package is auto-updated.
Last update: 2026-11-01 19:58:18 UTC
README
Universal Service Provider for Gember Event Sourcing , compatible with any application or framework that supports container-interop/service-provider.
Installation
Install the service provider with composer:
composer require gember/event-sourcing-universal-service-provider
Configuration
This package installs Gember Event Sourcing with all required dependency adapters. Some of these adapters need to be configured.
By default, it uses the following configuration:
PSR-11 Container definition (https://www.php-fig.org/psr/psr-11):
use Doctrine\DBAL\Connection; use Gember\IdentityGeneratorSymfony\Ulid\SymfonyUlidIdentityGenerator; use Gember\IdentityGeneratorSymfony\Uuid\SymfonyUuidIdentityGenerator; use Psr\Container\ContainerInterface; use Symfony\Component\Serializer\Serializer; return [ 'gember_event_sourcing' => fn(ContainerInterface $container) => [ 'message_bus' => [ 'symfony' => [ 'event_bus' => $container->get('event.bus'), 'command_bus' => $container->get('command.bus'), ], ], 'cache' => [ 'enabled' => false, // set a PSR-6 or PSR-16 implementation // 'psr16' => $container->get('cache.file'), // 'psr6' => $container->get('cache.file'), ], 'serializer' => [ 'symfony' => [ 'serializer' => $container->get(Serializer::class), ], ], 'event_store' => [ 'rdbms' => [ 'doctrine_dbal' => [ 'connection' => $container->get(Connection::class), ], ], ], 'generator' => [ 'identity' => [ 'service' => $container->get(SymfonyUuidIdentityGenerator::class), // or use ULIDs // 'service' => $container->get(SymfonyUlidIdentityGenerator::class), ], ], 'registry' => [ 'event' => [ 'reflector' => [ 'path' => '/path/to/src', // default: the src/ directory next to your root composer.json ], ], 'command_handler' => [ 'reflector' => [ 'path' => '/path/to/src', // default: the src/ directory next to your root composer.json ], ], 'saga' => [ 'reflector' => [ 'path' => '/path/to/src', // default: the src/ directory next to your root composer.json ], ], ], 'logging' => [ // 'logger' => $container->get(LoggerInterface::class), ], 'snapshot' => [ 'enabled' => false, ], 'dispatch' => [ 'strategy' => 'direct', // 'direct' or 'outbox' 'max_retries' => 5, // only used with outbox strategy ], ], ];
You can override any of these defaults however you like.
The identity generators use Symfony\Component\Uid\Factory\UuidFactory / UlidFactory from the container when it has them, and create default factories otherwise.
Required dependencies
Some of the required dependencies also need to be configured separately.
Symfony Messenger (symfony/messenger)
The default configuration makes use of services with name event.bus and command.bus.
When these buses are configured, Gember Event Sourcing works out of the box.
However, when different buses are preferred, they must be services implementing Symfony\Component\Messenger\MessageBusInterface.
Commands with #[DomainCommandHandler] methods must be routed to UseCaseCommandHandler, and events that sagas subscribe to (#[SagaEventSubscriber]) to SagaEventHandler; both are registered by the service provider.
Example (minimum) configuration for symfony/messenger:
PSR-11 Container definition (https://www.php-fig.org/psr/psr-11):
use Gember\EventSourcing\Saga\SagaEventHandler; use Gember\EventSourcing\UseCase\CommandHandler\UseCaseCommandHandler; use Psr\Container\ContainerInterface; use Symfony\Component\Messenger\Handler\HandlerDescriptor; use Symfony\Component\Messenger\Handler\HandlersLocator; use Symfony\Component\Messenger\MessageBus; use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; return [ 'event.bus' => fn(ContainerInterface $container) => new MessageBus([ new HandleMessageMiddleware(new HandlersLocator([ // Ideally this could be autoconfigured SomeDomainEvent::class => [ new HandlerDescriptor([ $container->get(SomeProjector::class), 'onSomeDomainEvent' ]), // When a saga subscribes to this event new HandlerDescriptor([ $container->get(SagaEventHandler::class), '__invoke' ]), ], ]), allowNoHandlers: true), ]), 'command.bus' => fn(ContainerInterface $container) => new MessageBus([ new HandleMessageMiddleware(new HandlersLocator([ // A command handled by a #[DomainCommandHandler] method on a use case SomeCommand::class => [ new HandlerDescriptor([ $container->get(UseCaseCommandHandler::class), '__invoke' ]), ], ])), ]), ];
Symfony Cache (symfony/cache)
Caching is disabled by default. To enable it, set cache.enabled to true and pass a service implementing Psr\Cache\CacheItemPoolInterface (psr6) or Psr\SimpleCache\CacheInterface (psr16), e.g. a cache.file service as below.
Example (minimum) configuration for symfony/cache:
PSR-11 Container definition (https://www.php-fig.org/psr/psr-11):
use Symfony\Component\Cache\Adapter\FilesystemAdapter; use Symfony\Component\Cache\Psr16Cache; return [ 'cache.file' => fn() => new Psr16Cache(new FilesystemAdapter( directory: __DIR__ . '/../../var/cache', )), ];
Symfony Serializer (symfony/serializer)
The default configuration makes use of a service with name Symfony\Component\Serializer\Serializer.
When this serializer service is configured, Gember Event Sourcing works out of the box.
However, when a different serializer is preferred, it must be a service implementing Symfony\Component\Serializer\SerializerInterface.
Example (minimum) configuration for symfony/serializer:
PSR-11 Container definition (https://www.php-fig.org/psr/psr-11):
use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer; use Symfony\Component\Serializer\Normalizer\ObjectNormalizer; use Symfony\Component\Serializer\Serializer; return [ Serializer::class => fn() => new Serializer([ new DateTimeNormalizer([ DateTimeNormalizer::FORMAT_KEY => 'Y-m-d\TH:i:s.uP', ]), new ObjectNormalizer(), ], [ new JsonEncoder(), ]), ];
Doctrine DBAL (doctrine/dbal)
The default configuration makes use of a service with name Doctrine\DBAL\Connection.
When this connection service is configured, Gember Event Sourcing works out of the box.
However, when a different Doctrine connection is preferred, it must be a service implementing Doctrine\DBAL\Connection.
Example (minimum) configuration for doctrine/dbal:
PSR-11 Container definition (https://www.php-fig.org/psr/psr-11):
use Doctrine\DBAL\Connection; use Doctrine\DBAL\DriverManager; return [ Connection::class => fn() => DriverManager::getConnection([ 'host' => $_ENV['DB_HOST'], 'port' => $_ENV['DB_PORT'], 'dbname' => $_ENV['DB_DBNAME'], 'user' => $_ENV['DB_USER'], 'password' => $_ENV['DB_PASSWORD'], 'driver' => $_ENV['DB_DRIVER'], 'charset' => $_ENV['DB_CHARSET'], ]), ];
Database
Events, sagas, snapshots and outbox messages are stored in MySQL, MariaDB (InnoDB) or SQLite. Create the tables with the migrations or schema of gember/rdbms-event-store-doctrine-dbal, and see Upgrading when upgrading.
Outbox
With dispatch.strategy set to outbox, messages are dispatched by Gember\EventSourcing\Outbox\Processor\OutboxProcessor. There is no console command outside Symfony: run $container->get(OutboxProcessor::class)->process(limit: 100) in your own loop or cron job, outside any transaction. See Outbox.
Good to go!
Check the main package gember/event-sourcing or the demo application gember/example-event-sourcing-dcb for examples.