prooph/snapshot-store
Lightweight snapshot store for prooph/event-sourcing setups. Provides a simple API to persist and load aggregate snapshots, reducing replay time and improving performance. Note: library support ended Dec 31, 2019 (deprecated).
Install Dependencies:
composer require prooph/snapshot-store prooph/event-sourcing prooph/snapshotter
Note: Requires prooph/event-sourcing and prooph/snapshotter for full functionality.
Configure a Basic PDO Store:
use Prooph\SnapshotStore\Pdo\PdoSnapshotStore;
use Prooph\SnapshotStore\Serializer\CallbackSerializer;
$pdo = new \PDO('mysql:host=localhost;dbname=your_db', 'user', 'pass');
$serializer = new CallbackSerializer('serialize', 'unserialize');
$snapshotStore = new PdoSnapshotStore(
$pdo,
['snapshot_table' => 'aggregate_snapshots'],
'default_snapshot_table',
$serializer
);
Integrate with Aggregate Repository:
use Prooph\EventSourcing\Aggregate\AggregateRepository;
$repository = new AggregateRepository(
$metadata,
$snapshotStore,
$eventStore
);
First Use Case: Load an aggregate with snapshots enabled:
$aggregate = $repository->get($aggregateId, $aggregateType);
Snapshots will now hydrate the aggregate, bypassing event replay when available.
Snapshot-Based Hydration:
AggregateRepository to use snapshots:
$repository = new AggregateRepository(
$metadata,
$snapshotStore,
$eventStore,
new Snapshotter($snapshotStore) // Optional: Auto-snapshot on save
);
Snapshotter for automation).Composite Store for Caching:
use Prooph\SnapshotStore\CompositeSnapshotStore;
$cacheStore = new RedisSnapshotStore($redis);
$persistenceStore = new PdoSnapshotStore($pdo);
$compositeStore = new CompositeSnapshotStore([$cacheStore, $persistenceStore]);
Custom Serialization:
igbinary) or compatibility (e.g., JSON):
$serializer = new CallbackSerializer('igbinary_serialize', 'igbinary_unserialize');
$snapshotStore = new PdoSnapshotStore($pdo, [], 'snapshots', $serializer);
Bulk Operations:
$snapshotStore->deleteAllByAggregateType('Order');
Event-Sourcing Workflow:
Snapshotter).Read-Heavy Optimizations:
CompositeSnapshotStore to cache hot aggregates (e.g., UserProfile).Testing:
SnapshotStore in unit tests:
$mockStore = $this->createMock(SnapshotStore::class);
$mockStore->method('load')->willReturn($snapshotData);
$this->app->singleton(SnapshotStore::class, function ($app) {
return new PdoSnapshotStore($app['db.connection'], [], 'snapshots');
});
$repository = new AggregateRepository(
$metadata,
$snapshotStore,
$eventStore,
new Snapshotter($snapshotStore, 10) // Snapshot every 10 events
);
CREATE TABLE aggregate_snapshots (
aggregate_id VARCHAR(36) PRIMARY KEY,
aggregate_type VARCHAR(255),
snapshot_data LONGTEXT,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
Deprecation Risk:
Snapshot Corruption:
try {
$snapshot = $snapshotStore->load($aggregateId, $aggregateType);
// Deserialize and verify aggregate state.
} catch (\Exception $e) {
// Fallback to event replay.
}
Performance Trade-offs:
igbinary for smaller snapshots or compress data (e.g., gzip).Composite Store Order:
CompositeSnapshotStore may bypass persistence layers.$compositeStore = new CompositeSnapshotStore([$cacheStore, $persistenceStore]);
Concurrency Issues:
Missing Snapshots:
Snapshotter is configured in the repository.Deserialization Errors:
igbinary vs. serialize).Slow Loads:
$start = microtime(true);
$aggregate = $repository->get($id, $type);
echo "Snapshot load time: " . (microtime(true) - $start) . "s";
Table Naming:
PdoSnapshotStore uses snapshot_table config. Defaults to aggregate_snapshots if omitted.$snapshotStore = new PdoSnapshotStore($pdo, ['snapshot_table' => 'my_snapshots']);
Aggregate Type Handling:
aggregate_type. Ensure consistency in type names across stores.Serializer Compatibility:
Prooph\SnapshotStore\Serializer\SerializerInterface.class JsonSerializer implements SerializerInterface {
public function serialize($data) { return json_encode($data); }
public function unserialize($data) { return json_decode($data, true); }
}
Custom Store Backends:
Prooph\SnapshotStore\SnapshotStoreInterface for MongoDB, DynamoDB, etc.class MongoSnapshotStore implements SnapshotStoreInterface {
public function load($aggregateId, $aggregateType) { /* ... */ }
public function save($aggregateId, $aggregateType, $snapshot) { /* ... */ }
public function delete($aggregateId, $aggregateType) { /* ... */ }
public function deleteAllByAggregateType($aggregateType) { /* ... */ }
}
Snapshot Validation:
Snapshotter to validate snapshots before saving:
$snapshotter = new Snapshotter($snapshotStore, 10, function ($snapshot) {
return strlen($snapshot) < 1024 * 1024; // Reject large snapshots.
});
Event-Based Snapshotting:
OrderPaid):
$repository = new AggregateRepository(
$metadata,
$snapshotStore,
$eventStore,
new EventBasedSnapshotter($snapshotStore, ['OrderPaid'])
);
How can I help you explore Laravel packages today?