hasDynamicComponents = $this->findDynamicComponentsInString($template, $analysis); $analysis->hasUserSpecificContent = $this->findUserContentInString($template, $context); $analysis->hasFormElements = $this->findFormsInString($template); $analysis->hasTimeBasedContent = $this->findTimeBasedContent($template); $analysis->hasSessionData = $this->findSessionData($template, $context); // Fragment-Analyse hinzufügen $this->autoDetectFragments($template, $analysis); // Bestimme beste Cache-Strategie $analysis->cacheStrategy = $this->determineBestStrategy($analysis); $analysis->ttl = $this->calculateOptimalTtl($analysis); $analysis->dependencies = $this->identifyDependencies($analysis, $context); } catch (\Exception $e) { // Bei Fehlern: Konservativ statisches Caching $analysis->cacheStrategy = CacheStrategy::STATIC; $analysis->ttl = 300; } return $analysis; } private function findDynamicComponentsInString(string $template, CacheabilityInfo $analysis): bool { $hasDynamic = false; foreach (self::DYNAMIC_COMPONENTS as $component) { if (str_contains($template, $component)) { $analysis->dynamicComponents[] = $component; $hasDynamic = true; } } return $hasDynamic; } private function findUserContentInString(string $template, RenderContext $context): bool { // Suche nach user-spezifischen Patterns $userPatterns = ['{{user', '$user', 'data-user', 'class="user-']; if (array_any($userPatterns, fn($pattern) => str_contains($template, $pattern))) { return true; } // Prüfe Context-Daten auf User-Informationen return isset($context->data['user']) || isset($context->data['session']); } private function findFormsInString(string $template): bool { return str_contains($template, ' str_contains($template, $pattern)); } private function findSessionData(string $template, RenderContext $context): bool { // Prüfe auf Session-bezogene Patterns im Template $sessionPatterns = ['session.', '{{session', '$session', 'data-session']; if (array_any($sessionPatterns, fn($pattern) => str_contains($template, $pattern))) { return true; } // Prüfe Context auf Session-Daten return isset($context->data['session']) || isset($context->data['flash']); } // Fragment-Analyse vereinfacht entfernt für bessere Stabilität private function determineBestStrategy(CacheabilityInfo $analysis): CacheStrategy { // Vollständig statisch if ($analysis->isFullyCacheable()) { return CacheStrategy::STATIC; } // Teilweise cacheable mit Fragmenten if ($analysis->shouldUseFragmentCache()) { return CacheStrategy::FRAGMENT; } // Teilweise cacheable ohne Fragmente if ($analysis->isPartiallyCacheable()) { return CacheStrategy::PARTIAL; } // Vollständig dynamisch return CacheStrategy::DYNAMIC; } private function calculateOptimalTtl(CacheabilityInfo $analysis): int { $baseTtl = $analysis->cacheStrategy->getTtl(); // Reduziere TTL basierend auf Komplexität $complexity = $analysis->getCacheComplexity(); $reduction = min($complexity * 60, $baseTtl * 0.5); // Max 50% Reduktion return max(0, $baseTtl - (int)$reduction); } private function identifyDependencies(CacheabilityInfo $analysis, RenderContext $context): array { $dependencies = []; // Template-File als Basis-Dependency $dependencies['template'] = $context->template; // Dynamic Fragment Dependencies - verwende dynamicFragments anstatt dynamicComponents foreach ($analysis->dynamicFragments as $fragment) { // Verwende einfach den Fragment-Namen und aktuellen Timestamp $dependencies['fragment:' . $fragment] = time(); } // User-spezifische Dependencies if ($analysis->hasUserSpecificContent && isset($context->data['user']['id'])) { $dependencies['user'] = $context->data['user']['id']; } return $dependencies; } private function autoDetectFragments(string $template, CacheabilityInfo $info): void { $fragmentsFound = false; // Erkenne große statische Blöcke (Navigation, Footer, etc.) if (preg_match('/]*>(.*?)<\/nav>/s', $template)) { $info->addStaticFragment('navigation'); $fragmentsFound = true; } if (preg_match('/]*>(.*?)<\/footer>/s', $template)) { $info->addStaticFragment('footer'); $fragmentsFound = true; } if (preg_match('/]*>(.*?)<\/header>/s', $template)) { $info->addStaticFragment('header'); $fragmentsFound = true; } // Erkenne HTML-Sektionen if (preg_match('/]*>(.*?)<\/section>/s', $template)) { $info->addStaticFragment('content_section'); $fragmentsFound = true; } if (preg_match('/]*>(.*?)<\/main>/s', $template)) { $info->addStaticFragment('main_content'); $fragmentsFound = true; } // Erkenne CSS-Klassen-basierte Bereiche if (preg_match('/class=["\'].*sidebar.*["\']/', $template)) { $info->addStaticFragment('sidebar'); $fragmentsFound = true; } // Erkenne dynamische Bereiche if (preg_match('/\{\{\s*flash|errors|session/', $template)) { $info->addDynamicFragment('user_messages'); $fragmentsFound = true; } // Analysiere Template-Komplexität $dynamicMatches = preg_match_all('/\{\{[^}]+}}/', $template); $templateLength = strlen($template); // Debugging der Fragment-Erkennung error_log("TemplateAnalyzer DEBUG: Template length: {$templateLength}, Dynamic matches: {$dynamicMatches}, Fragments found: " . ($fragmentsFound ? 'yes' : 'no')); // Wenn weniger als 5 dynamische Platzhalter pro 1_000 Zeichen UND keine anderen Fragmente $dynamicDensity = $templateLength > 0 ? ($dynamicMatches / $templateLength) * 1000 : 0; error_log("TemplateAnalyzer DEBUG: Dynamic density: {$dynamicDensity}, Has dynamic components: " . ($info->hasDynamicComponents ? 'yes' : 'no')); // Immer ein template_main Fragment hinzufügen wenn wenig dynamische Inhalte if ($dynamicDensity < 5 || (!$fragmentsFound && !$info->hasDynamicComponents)) { $info->addStaticFragment('template_main'); error_log("TemplateAnalyzer DEBUG: Added template_main fragment (density: {$dynamicDensity})"); } } }