ez-php / event-store-snapshots
Snapshot store for ez-php/event-store streams: PDO and in-memory stores, every-N-events policy, snapshot-aware loader
2.6.3
2026-10-24 20:56 UTC
Requires
- php: ^8.5
- ez-php/contracts: ^2.6.0
- ez-php/event-store: ^2.6.0
Requires (Dev)
- ez-php/docker: ^2.6.0
- friendsofphp/php-cs-fixer: ^3.94
- phpstan/phpstan: ^2.1
- phpstan/phpstan-deprecation-rules: ^2.0
- phpstan/phpstan-strict-rules: ^2.0
- phpunit/phpunit: ^13.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Snapshots for ez-php/event-store streams. Long streams no longer have to be replayed in full: a load starts from the latest snapshot and replays only the events after it.
Installation
composer require ez-php/event-store-snapshots
Register the provider after EventStoreServiceProvider (both need a DatabaseInterface binding):
\EzPhp\EventStore\EventStoreServiceProvider::class, \EzPhp\EventStoreSnapshots\SnapshotServiceProvider::class,
Usage
use EzPhp\EventStore\EventStoreInterface; use EzPhp\EventStore\StoredEvent; use EzPhp\EventStoreSnapshots\EveryNEventsPolicy; use EzPhp\EventStoreSnapshots\SnapshotStoreInterface; use EzPhp\EventStoreSnapshots\SnapshottingLoader; $loader = new SnapshottingLoader( $container->make(EventStoreInterface::class), $container->make(SnapshotStoreInterface::class), new EveryNEventsPolicy(100), // snapshot once 100+ events had to be replayed stateVersion: '1', // bump when the reducer changes how state is derived ); $account = $loader->load('account-42', ['balance' => 0], fn (array $state, StoredEvent $e): array => match ($e->eventType) { 'deposited' => ['balance' => $state['balance'] + $e->payload['amount']], 'withdrawn' => ['balance' => $state['balance'] - $e->payload['amount']], default => $state, }); $account->state; // ['balance' => ...] $account->version; // pass as expectedVersion to the next append() $eventStore->append('account-42', [$withdrawal], expectedVersion: $account->version);
$loader->take(...) takes the same arguments and always writes a snapshot, e.g. from a maintenance command.
How it works
- State is a plain array, the reducer a function, matching event-store's array payloads. State is stored as JSON, so keep it JSON-serialisable.
- Snapshots are written on load, when the policy says so (
EveryNEventsPolicy, or your ownSnapshotPolicyInterface). - One snapshot per stream, never moving backwards: an older snapshot never overwrites a newer one.
stateVersion: snapshots saved under another state version are ignored and replaced. Bump it whenever the reducer or an upcaster changes the resulting state.- Snapshots are a cache.
SnapshotStoreInterface::delete($stream)or a lost table only costs a full replay; the event log is never touched.
Stores
| Store | Use |
|---|---|
PdoSnapshotStore |
Production (MySQL) and SQLite. Creates event_store_snapshots on first use; the MySQL DDL is in the class doc for a migration. |
InMemorySnapshotStore |
Tests and short-lived workers. |
License
MIT