arnedesmedt/event-engine-symfony-bundle
Install the Bundle Add the package to your Laravel project via Composer:
composer require arnedesmedt/event-engine-symfony-bundle
Since Laravel doesn’t natively support Symfony bundles, you’ll need to manually register the bundle in a custom BundleLoader or use a bridge like symfony/console-bridge (requires additional setup).
Configure Dependencies The bundle depends on Event Engine (PHP implementation) and Prooph Event Store. Install these first:
composer require event-engine/php-engine event-engine/php-postgres-document-store prooph/pdo-event-store
Configure your PostgreSQL connection and event store in config/event_engine.php (create if missing).
First Use Case: Dispatching Events Create a Symfony-style event listener or command to dispatch events:
use EventEngine\EventEngine;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
class DispatchUserCreatedEvent extends Command
{
protected function execute(InputInterface $input, OutputInterface $output): int
{
$eventEngine = new EventEngine();
$eventEngine->dispatch(new UserCreatedEvent('user-id-123', 'John Doe'));
$output->writeln('Event dispatched!');
return Command::SUCCESS;
}
}
Register the command in config/services.php or a custom Symfony bridge.
Symfony Messenger Integration Use Symfony’s Messenger component to handle events asynchronously:
use Symfony\Component\Messenger\MessageBusInterface;
class UserCreatedHandler
{
public function __construct(private MessageBusInterface $bus)
{
}
public function handle(UserCreatedEvent $event): void
{
$this->bus->dispatch(new NotifyUserEmail($event->userId()));
}
}
Configure the bus in config/messenger.php to route events to handlers.
Event Store Persistence Store events in PostgreSQL using Prooph’s PDO event store:
use Prooph\EventStore\PDO\PostgreSqlEventStore;
$eventStore = new PostgreSqlEventStore(
new PDO('pgsql:host=...;dbname=...'),
'event_engine'
);
$eventEngine = new EventEngine($eventStore);
Command-Query Separation Use read models (via Event Engine’s document store) for queries:
use EventEngine\DocumentStore;
class UserRepository
{
public function __construct(private DocumentStore $store)
{
}
public function findById(string $id): ?User
{
return $this->store->find(User::class, $id);
}
}
class EventEngineServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(EventEngine::class, fn() => new EventEngine());
$this->app->bind(MessageBusInterface::class, fn() => new SymfonyBus());
}
}
Command for Laravel’s Artisan:
use Symfony\Component\Console\Application;
use Illuminate\Console\Scheduling\Schedule;
class EventEngineCommand extends Command
{
protected function getSchedule(Schedule $schedule): void
{
$schedule->command('event:dispatch-user-created')->daily();
}
}
Symfony vs. Laravel Ecosystem Mismatch
HttpKernel and Messenger. For Laravel, mock these dependencies or use adapters (e.g., spatie/laravel-messenger).MessageBus to Laravel’s Bus (e.g., Laravel\SerializableClosure\Bus).Event Store Configuration
EventEngine constructor or create a custom store adapter.$eventStore->setLogger(new MonologLogger($logger));
Immutable Objects
The bundle relies on team-blue/php-value-objects for immutable DTOs. If your events are mutable, wrap them in value objects or use Laravel’s Illuminate\Support\CarbonImmutable.
event_store table:
SELECT * FROM event_store WHERE aggregate_id = 'user-id-123';
failed_jobs table if using database transport).Custom Event Engines
Extend the base EventEngine to add Laravel-specific features (e.g., Eloquent model integration):
class LaravelEventEngine extends EventEngine
{
public function dispatchModelEvent(Model $model): void
{
$this->dispatch(new ModelUpdatedEvent($model->getKey()));
}
}
Validation
Use Symfony’s Validator for event validation:
use Symfony\Component\Validator\Validator\ValidatorInterface;
class UserCreatedEventValidator
{
public function __construct(private ValidatorInterface $validator)
{
}
public function validate(UserCreatedEvent $event): void
{
$errors = $this->validator->validate($event);
if (count($errors) > 0) {
throw new \InvalidArgumentException('Event validation failed');
}
}
}
Testing Mock the event store and bus for unit tests:
$eventStore = $this->createMock(PostgreSqlEventStore::class);
$eventStore->method('load')->willReturn([]);
$eventEngine = new EventEngine($eventStore);
How can I help you explore Laravel packages today?