Installation
composer require prooph/snapshotter
Add to composer.json under require-dev if using for testing.
First Use Case: Snapshot Creation
Define a snapshot for an aggregate root (e.g., Order):
use Prooph\Snapshotter\AggregateSnapshot;
class OrderSnapshot extends AggregateSnapshot
{
public function __construct(
string $aggregateId,
int $version,
string $state,
int $totalItems,
float $totalPrice
) {
parent::__construct($aggregateId, $version, $state);
$this->totalItems = $totalItems;
$this->totalPrice = $totalPrice;
}
}
Register Snapshot in Event Store
Configure the snapshotter in your EventStore setup:
$snapshotter = new Prooph\Snapshotter\Snapshotter(
$eventStore,
new Prooph\Snapshotter\Metadata\SnapshotMetadataFactory(),
new Prooph\Snapshotter\Serializer\JsonSerializer()
);
Trigger Snapshot on Aggregate
Use the Snapshotter in your aggregate root:
$this->snapshotter->takeSnapshot(
new OrderSnapshot(
$this->aggregateId(),
$this->version(),
'confirmed',
$this->totalItems(),
$this->totalPrice()
)
);
Check for Snapshots on Load
$snapshot = $snapshotter->getSnapshot($aggregateId);
if ($snapshot) {
$this->reconstructFromSnapshot($snapshot);
}
Conditional Snapshot Triggering Use version-based or event-based triggers:
if ($this->version() % 10 === 0) {
$this->snapshotter->takeSnapshot($snapshot);
}
Event Store Integration
Pair with prooph/event-store for seamless snapshot storage/retrieval:
$eventStore->load($aggregateId, $snapshotter);
Command Handling Use snapshots to optimize command processing:
if ($snapshot && $snapshot->version() >= $expectedVersion) {
return $snapshot->state(); // Skip replay
}
Prooph\Snapshotter\Serializer\SnapshotSerializerInterface for domain-specific formats (e.g., XML, Avro):
class CustomSerializer implements SnapshotSerializerInterface
{
public function serialize($snapshot): string { ... }
public function unserialize(string $serialized): object { ... }
}
Version Mismatch
if ($snapshot->version() !== $this->version()) {
throw new \RuntimeException("Snapshot version mismatch");
}
Serialization Errors
__serialize()/__unserialize() or exclude them.Concurrency Issues
EventStore::appendToStream() with snapshots in a single transaction if possible.Inspect Stored Snapshots Query the event store directly:
php artisan prooph:events:list --stream=order-123
Look for SnapshotCreated events.
Enable Logging
Configure the Snapshotter to log snapshot operations:
$snapshotter->setLogger(new Monolog\Logger('snapshotter'));
Metadata Customization
Extend SnapshotMetadata for additional metadata (e.g., timestamps, user IDs):
class ExtendedMetadata extends SnapshotMetadata
{
public function setTakenAt(\DateTimeInterface $dateTime): self { ... }
}
Snapshot Validation
Implement Prooph\Snapshotter\SnapshotValidatorInterface to enforce business rules:
class OrderSnapshotValidator implements SnapshotValidatorInterface
{
public function validate($snapshot): void
{
if ($snapshot->totalPrice < 0) {
throw new \InvalidArgumentException("Price cannot be negative");
}
}
}
Performance Tuning
How can I help you explore Laravel packages today?