toString(); if (isset($this->data[$key])) { $value = $this->data[$key]; $hits[$key] = $value instanceof CacheItem ? $value->value : $value; } else { $misses[] = $key; } } return new CacheResult($hits, $misses); } public function set(CacheItem ...$items): bool { foreach ($items as $item) { $this->data[$item->key->toString()] = $item; } return true; } public function has(CacheIdentifier ...$identifiers): array { $result = []; foreach ($identifiers as $identifier) { $key = (string) $identifier; $result[$key] = isset($this->data[$key]); } return $result; } public function forget(CacheIdentifier ...$identifiers): bool { foreach ($identifiers as $identifier) { $key = (string) $identifier; unset($this->data[$key]); } return true; } public function clear(): bool { $this->data = []; return true; } public function remember(CacheKey $key, callable $callback, ?Duration $ttl = null): CacheItem { $keyStr = $key->toString(); if (isset($this->data[$keyStr])) { return $this->data[$keyStr]; } $value = $callback(); $item = CacheItem::forSetting($key, $value, $ttl); $this->data[$keyStr] = $item; return $item; } }; // Create test clock $clock = new class implements Clock { public function now(): \DateTimeImmutable { return new \DateTimeImmutable(); } public function fromTimestamp(Timestamp $timestamp): \DateTimeImmutable { return $timestamp->toDateTime(); } public function fromString(string $dateTime, ?string $format = null): \DateTimeImmutable { return new \DateTimeImmutable($dateTime); } public function today(): \DateTimeImmutable { return new \DateTimeImmutable('today'); } public function yesterday(): \DateTimeImmutable { return new \DateTimeImmutable('yesterday'); } public function tomorrow(): \DateTimeImmutable { return new \DateTimeImmutable('tomorrow'); } public function time(): Timestamp { return Timestamp::now(); } }; echo "Creating ErrorAggregator...\n"; $storage = new InMemoryErrorStorage(); $alertQueue = new InMemoryQueue(); $errorAggregator = new ErrorAggregator( storage: $storage, cache: $cache, clock: $clock, alertQueue: $alertQueue ); echo "Creating exception and context...\n"; $exception = FrameworkException::create( DatabaseErrorCode::QUERY_FAILED, 'Test database query failed' ); $exceptionContext = ExceptionContext::empty() ->withOperation('test_operation', 'TestComponent') ->withData(['test_key' => 'test_value']); $requestContext = RequestContext::fromGlobals(); $systemContext = SystemContext::current(); $errorHandlerContext = ErrorHandlerContext::create( $exceptionContext, $requestContext, $systemContext, ['http_status' => 500] ); echo "Processing error...\n"; try { $errorAggregator->processError($errorHandlerContext); echo "SUCCESS: Error processed without exception\n"; } catch (\Throwable $e) { echo "ERROR processing error: " . $e->getMessage() . "\n"; echo "Stack trace:\n" . $e->getTraceAsString() . "\n"; } echo "\nGetting recent events...\n"; $recentEvents = $errorAggregator->getRecentEvents(10); echo "Recent events count: " . count($recentEvents) . "\n"; echo "\nGetting active patterns...\n"; $activePatterns = $errorAggregator->getActivePatterns(10); echo "Active patterns count: " . count($activePatterns) . "\n"; if (count($recentEvents) > 0) { echo "\nFirst event details:\n"; $event = $recentEvents[0]; echo " Error message: " . $event->errorMessage . "\n"; echo " Component: " . $event->component . "\n"; echo " Operation: " . $event->operation . "\n"; } if (count($activePatterns) > 0) { echo "\nFirst pattern details:\n"; $pattern = $activePatterns[0]; echo " Component: " . $pattern->component . "\n"; echo " Occurrence count: " . $pattern->occurrenceCount . "\n"; }