spriebsch / longbow
An event framework for PHP domain events
Requires
- php: ^8.5
- ext-posix: *
- ext-sqlite3: *
- spriebsch/di: ^2.1
- spriebsch/domain-event: ^2.1
- spriebsch/filesystem: ^1.0
- spriebsch/sequora: ^1.3
- spriebsch/sqlite: ^2.1
- spriebsch/timestamp: ^1.1
README
Aim high and shoot far with Longbow, the PHP 8.5 event framework.
Longbow 7 uses Domain Event for event definitions and Sequora for persistence.
Domain events
Events are readonly data objects. Topics and correlation identifiers are declared with attributes:
use spriebsch\DomainEvent\AbstractId; use spriebsch\DomainEvent\DomainEvent; use spriebsch\DomainEvent\MapToTopic; use spriebsch\DomainEvent\UseAsCorrelationId; final readonly class OrderId extends AbstractId { } #[MapToTopic('acme.sales.order.order-placed')] final readonly class OrderPlaced implements DomainEvent { public function __construct( private OrderId $orderId, public string $product, ) { } #[UseAsCorrelationId] public function orderId(): OrderId { return $this->orderId; } }
Generate the topic map with Domain Event's generate-topic-map command and
return its file from the application configuration.
Configuration
Application configuration implements spriebsch\longbow\LongbowConfiguration
and supplies:
- the orchestration directory;
- the generated topic-map file;
- the Sequora SQLite database path;
- the Longbow processor-position SQLite database path.
Configure Longbow with the application factory:
Longbow::configure($configuration, ApplicationFactory::class);
Command handlers persist their returned events through
spriebsch\sequora\EventWriter:
public function handle(PlaceOrder $command): DomainEvent { $event = new OrderPlaced(OrderId::generate(), $command->product); $this->eventWriter->store($event); return $event; }
Event streams
Streams extend Longbow's query-focused base class and define Sequora topics:
final readonly class SalesEvents extends EventStream { protected function topics(): array { return [Topic::fromString('acme.sales.order.order-placed')]; } }
Processors implement EventStreamProcessor and return an
EventStreamProcessorId. Longbow reads Sequora envelopes, passes their domain
events to processor methods, and stores the envelope event ID as the processor
position.
When a processor fails, Longbow leaves its successful position unchanged and
persists the failed event ID, timestamp, exception class, and exception message.
Applications can use Longbow::processorFailures() to distinguish a processor
that has not started from one that failed. A successful retry clears the
persisted failure.
Upgrading
Longbow 7 is a breaking release. It requires PHP 8.5 and does not migrate
databases created by spriebsch/eventstore; start with a fresh Sequora schema
or migrate existing event data with an application-specific migration.
(c) Stefan Priebsch.