Generates Snapshot pattern for PHP 8.4. Creates aggregate snapshot infrastructure for event sourcing performance optimization with configurable strategies and version tracking. Includes unit tests.
From accnpx claudepluginhub dykyi-roman/awesome-claude-code --plugin accThis skill uses the workspace's default tool permissions.
references/examples.mdreferences/templates.mdCreates Snapshot infrastructure for optimizing event sourcing aggregate rebuilds.
| Scenario | Example |
|---|---|
| Long event streams | Aggregates with 100+ events in their history |
| Slow aggregate rebuild | Event replay taking too long for read operations |
| Frequent reads | Aggregates loaded many times per second |
| Large aggregates | Complex state requiring many events to reconstruct |
fromArray() / toArray() for serializationsave(Snapshot $snapshot): void — persist snapshot (upsert)load(string $aggregateId): ?Snapshot — retrieve latest snapshotdelete(string $aggregateId): void — remove all snapshots for aggregateshouldTakeSnapshot(int $eventsSinceLastSnapshot): boolPath: src/Domain/{BC}/Snapshot/
Snapshot.php — Immutable snapshot value objectSnapshotStoreInterface.php — Repository interface for snapshot persistencePath: src/Application/{BC}/Snapshot/
SnapshotStrategy.php — Configurable threshold strategyAggregateSnapshotter.php — Application service for snapshot operationsPath: src/Infrastructure/{BC}/Snapshot/
DoctrineSnapshotStore.php — Doctrine DBAL implementation of SnapshotStoreInterfaceSnapshotTest.php — Construction, serialization, validation testsSnapshotStrategyTest.php — Threshold behavior testsAggregateSnapshotterTest.php — Load and take snapshot tests| Component | Path |
|---|---|
| Snapshot, SnapshotStoreInterface | src/Domain/{BC}/Snapshot/ |
| SnapshotStrategy, AggregateSnapshotter | src/Application/{BC}/Snapshot/ |
| DoctrineSnapshotStore | src/Infrastructure/{BC}/Snapshot/ |
| Unit Tests | tests/Unit/Domain/{BC}/Snapshot/, tests/Unit/Application/{BC}/Snapshot/ |
| Component | Pattern | Example |
|---|---|---|
| Value Object | Snapshot | Snapshot |
| Store Interface | SnapshotStoreInterface | SnapshotStoreInterface |
| Strategy | SnapshotStrategy | SnapshotStrategy |
| Application Service | AggregateSnapshotter | AggregateSnapshotter |
| Infrastructure Store | DoctrineSnapshotStore | DoctrineSnapshotStore |
| Test | {ClassName}Test | SnapshotTest |
final readonly class Snapshot
{
public function __construct(
public string $aggregateId,
public string $aggregateType,
public int $version,
public string $state,
public \DateTimeImmutable $createdAt
) {
// version >= 1 validation
}
public static function fromArray(array $data): self;
public function toArray(): array;
}
interface SnapshotStoreInterface
{
public function save(Snapshot $snapshot): void;
public function load(string $aggregateId): ?Snapshot;
public function delete(string $aggregateId): void;
}
final readonly class SnapshotStrategy
{
public function __construct(
private int $eventThreshold = 100
) {}
public function shouldTakeSnapshot(int $eventsSinceLastSnapshot): bool;
}
$snapshotter = new AggregateSnapshotter($snapshotStore, $strategy);
// Load aggregate from snapshot + remaining events
$result = $snapshotter->loadWithSnapshot($aggregateId, $eventStore);
$snapshot = $result['snapshot'];
$remainingEvents = $result['remainingEvents'];
$aggregate = $snapshot !== null
? Order::fromSnapshot($snapshot)
: new Order($aggregateId);
foreach ($remainingEvents as $event) {
$aggregate->apply($event);
}
// Take snapshot if threshold reached
$snapshotter->takeSnapshotIfNeeded(
aggregateId: $aggregateId,
aggregateType: 'Order',
version: $aggregate->getVersion(),
state: $aggregate->toSnapshot(),
eventsSinceSnapshot: count($remainingEvents)
);
CREATE TABLE snapshots (
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
aggregate_id VARCHAR(36) NOT NULL,
aggregate_type VARCHAR(255) NOT NULL,
version INT UNSIGNED NOT NULL,
state JSON NOT NULL,
created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
UNIQUE INDEX idx_snapshots_aggregate_id (aggregate_id),
INDEX idx_snapshots_aggregate_type (aggregate_type)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
| Anti-pattern | Problem | Solution |
|---|---|---|
| Snapshot Every Event | Storage bloat, no performance gain | Use threshold strategy (e.g., every 100 events) |
| Mutable Snapshots | State corruption, debugging nightmares | Make Snapshot immutable (final readonly) |
| Missing Version | Cannot determine event replay start point | Always track version in snapshot |
| No Cleanup | Unbounded storage growth | Implement retention policy, keep only latest |
| Tight Coupling | Snapshot tied to infrastructure | Domain interface, infrastructure implementation |
| Skipping Validation | Invalid snapshots persisted | Validate version >= 1, non-empty state |
For complete PHP templates and examples, see:
references/templates.md — Snapshot, SnapshotStoreInterface, SnapshotStrategy, AggregateSnapshotter, DoctrineSnapshotStore templatesreferences/examples.md — OrderAggregate integration, event sourcing examples and testsProvides UI/UX resources: 50+ styles, color palettes, font pairings, guidelines, charts for web/mobile across React, Next.js, Vue, Svelte, Tailwind, React Native, Flutter. Aids planning, building, reviewing interfaces.