initializeStrategies(); } public function render(TemplateContext $context, callable $renderer): string { // DEBUG: Log cache analysis for routes template if ($context->template === 'routes') { error_log("CacheManager::render - Template: routes"); } // 1. Template analysieren für optimale Strategy $analysis = $this->analyzer->analyze($context->template); $this->lastAnalysis = $analysis; // DEBUG: Log analysis results for routes template if ($context->template === 'routes') { error_log("CacheManager::render - Strategy: " . $analysis->recommendedStrategy->name); error_log("CacheManager::render - Cacheable: " . ($analysis->cacheability->isCacheable() ? 'YES' : 'NO')); error_log("CacheManager::render - Static ratio: " . $analysis->cacheability->staticContentRatio); } // 2. Passende Strategy auswählen $strategy = $this->selectStrategy($analysis); if (! $strategy->shouldCache($context)) { $content = $renderer(); if (! is_string($content)) { throw TemplateCacheException::invalidCacheFormat( 'non_cached_content', 'string', get_debug_type($content) ); } return $content; } // 3. Cache-Key generieren $cacheKey = $strategy->generateKey($context); // 4. Cache-Lookup $result = $this->cache->get($cacheKey); $cached = $result->getItem($cacheKey); if ($cached->isHit && is_string($cached->value)) { // DEBUG: Log cache hit for routes template if ($context->template === 'routes') { error_log("CacheManager::render - CACHE HIT! Returning cached content (length: " . strlen($cached->value) . ")"); error_log("CacheManager::render - First 200 chars: " . substr($cached->value, 0, 200)); } return $cached->value; } // 5. Rendern und cachen if ($context->template === 'routes') { error_log("CacheManager::render - CACHE MISS! Calling renderer()"); } $content = $renderer(); if (! is_string($content)) { throw TemplateCacheException::invalidCacheFormat( $cacheKey, 'string', get_debug_type($content) ); } $ttl = $strategy->getTtl($context); $this->cache->set(CacheItem::forSet($cacheKey, $content, \App\Framework\Core\ValueObjects\Duration::fromSeconds($ttl))); return $content; } public function invalidateTemplate(string $template): int { $invalidated = 0; // Invalidiere alle Strategies für dieses Template foreach ($this->strategies as $strategy) { if ($strategy->canInvalidate($template)) { // Pattern-basierte Invalidierung je nach Strategy $pattern = $this->buildInvalidationPattern($strategy, $template); $invalidated += $this->invalidateByPattern($pattern); } } return $invalidated; } private function selectStrategy(TemplateAnalysis $analysis): ViewCacheStrategy { return match($analysis->recommendedStrategy) { CacheStrategy::FULL_PAGE => $this->strategies['full_page'], CacheStrategy::COMPONENT => $this->strategies['component'], CacheStrategy::FRAGMENT => $this->strategies['fragment'], CacheStrategy::USER_AWARE => $this->strategies['user_aware'], default => $this->strategies['no_cache'] }; } private function initializeStrategies(): void { $this->strategies = [ 'full_page' => new FullPageCacheStrategy($this->cache), 'component' => new ComponentCacheStrategy($this->cache), 'fragment' => new FragmentCacheStrategy($this->cache), 'no_cache' => new NoCacheStrategy(), ]; } private function buildInvalidationPattern(mixed $strategy, string $template): string { return match(get_class($strategy)) { FullPageCacheStrategy::class => "page:{$template}:*", ComponentCacheStrategy::class => "component:*{$template}*", FragmentCacheStrategy::class => "fragment:{$template}:*", default => "*{$template}*" }; } private function invalidateByPattern(string $pattern): int { // Vereinfachte Implementation - in Realität müsste das der Cache-Driver unterstützen // Für jetzt: Cache komplett leeren bei Pattern-Match $invalidated = 0; if (str_contains($pattern, '*')) { $this->cache->clear(); $invalidated = 1; } return $invalidated; } }