store->getLatest($aggregateId); if ($snapshot) { // Load from snapshot + events since snapshot $eventsSinceSnapshot = $eventStreamLoader($snapshot->getVersion()); $state = $this->reconstructState($snapshot); return AggregateRoot::rehydrate( $aggregateId, $state, $eventsSinceSnapshot ); } // No snapshot - load all events $events = $eventStreamLoader(0); return $aggregateFactory($aggregateId, $events); } /** * Save aggregate and create snapshot if strategy says so */ public function saveWithSnapshot(AggregateRoot $aggregate): void { // Check if snapshot should be taken if ($this->strategy->shouldTakeSnapshot($aggregate)) { $snapshot = $this->createSnapshot($aggregate); $this->store->save($snapshot); } } /** * Force snapshot creation */ public function forceSnapshot(AggregateRoot $aggregate): Snapshot { $snapshot = $this->createSnapshot($aggregate); $this->store->save($snapshot); return $snapshot; } /** * Get aggregate version from event recorder */ public function getVersion(AggregateRoot $aggregate): int { return $aggregate->eventRecorder->getVersion(); } /** * Create snapshot from aggregate */ private function createSnapshot(AggregateRoot $aggregate): Snapshot { return Snapshot::take( aggregateId: $aggregate->id, version: $this->getVersion($aggregate), state: $this->extractState($aggregate), aggregateClass: get_class($aggregate->state) ); } /** * Extract state array from aggregate */ private function extractState(AggregateRoot $aggregate): array { // Use reflection to extract state properties $reflection = new \ReflectionObject($aggregate->state); $state = []; foreach ($reflection->getProperties() as $property) { $property->setAccessible(true); $value = $property->getValue($aggregate->state); // Serialize Value Objects and complex types if (is_object($value)) { if (method_exists($value, 'toArray')) { $state[$property->getName()] = $value->toArray(); } elseif (method_exists($value, 'toString')) { $state[$property->getName()] = $value->toString(); } else { $state[$property->getName()] = serialize($value); } } else { $state[$property->getName()] = $value; } } return $state; } /** * Reconstruct state object from snapshot */ private function reconstructState(SnapshotInterface $snapshot): object { $stateClass = $snapshot->getAggregateClass(); $stateData = $snapshot->getState(); // Simple reconstruction - would need enhancement for complex VOs return new $stateClass(...$stateData); } }