chore: complete update
This commit is contained in:
428
.archive/Archived/SmartCacheEngine.php
Normal file
428
.archive/Archived/SmartCacheEngine.php
Normal file
@@ -0,0 +1,428 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Archive\Archived;
|
||||
|
||||
use App\Framework\Cache\Cache;
|
||||
use App\Framework\View\DomWrapper;
|
||||
use App\Framework\View\Loading\TemplateLoader;
|
||||
use App\Framework\View\RenderContext;
|
||||
use App\Framework\View\TemplateProcessor;
|
||||
use App\Framework\View\TemplateRenderer;
|
||||
|
||||
final class SmartCacheEngine implements TemplateRenderer
|
||||
{
|
||||
private array $cacheStats = [
|
||||
'hits' => 0,
|
||||
'misses' => 0,
|
||||
'renders' => 0,
|
||||
'cached_templates' => [],
|
||||
];
|
||||
|
||||
public function __construct(
|
||||
private readonly TemplateLoader $loader,
|
||||
private readonly TemplateAnalyzer $analyzer,
|
||||
private readonly FragmentCacheManager $fragmentCache,
|
||||
private readonly Cache $cache,
|
||||
private readonly TemplateProcessor $processor = new TemplateProcessor(),
|
||||
private readonly bool $cacheEnabled = true,
|
||||
private readonly bool $debugMode = true,
|
||||
private readonly TemplatePreprocessor $preprocessor = new TemplatePreprocessor(),
|
||||
) {
|
||||
dd('oldcacheengine');
|
||||
}
|
||||
|
||||
public function render(RenderContext $context): string
|
||||
{
|
||||
$this->cacheStats['renders']++;
|
||||
|
||||
if (!$this->cacheEnabled) {
|
||||
$this->logDebug("Cache disabled - rendering without cache", $context);
|
||||
return $this->renderWithoutCache($context);
|
||||
}
|
||||
|
||||
$startTime = microtime(true);
|
||||
|
||||
// Lade und analysiere Template
|
||||
$template = $this->loader->load($context->template, $context->controllerClass, $context);
|
||||
|
||||
// Preprocessing für optimierte Cache-Keys
|
||||
$normalizedTemplate = $this->preprocessor->normalizeTemplate($template, $context);
|
||||
$cacheableBlocks = $this->preprocessor->extractCacheableBlocks($template);
|
||||
|
||||
$analysis = $this->analyzer->analyzeCacheability($normalizedTemplate, $context);
|
||||
|
||||
// Erweitere Analysis mit extrahierten Blöcken
|
||||
foreach ($cacheableBlocks as $block) {
|
||||
if ($block['type'] === 'explicit') {
|
||||
$analysis->addStaticFragment($block['id']);
|
||||
}
|
||||
}
|
||||
|
||||
$this->logDebug("Template loaded, length: " . strlen($template) . " chars", $context);
|
||||
$this->logDebug("Cache strategy: {$analysis->cacheStrategy->value}, TTL: {$analysis->ttl}s", $context);
|
||||
$this->logDebug("Cacheable blocks found: " . count($cacheableBlocks), $context);
|
||||
|
||||
$result = match($analysis->cacheStrategy) {
|
||||
CacheStrategy::STATIC => $this->renderStaticCached($context, $template, $analysis),
|
||||
CacheStrategy::PARTIAL => $this->renderPartialCached($context, $template, $analysis),
|
||||
CacheStrategy::FRAGMENT => $this->renderFragmentCached($context, $template, $analysis),
|
||||
CacheStrategy::DYNAMIC => $this->processor->render($context, $template),
|
||||
CacheStrategy::DISABLED => $this->renderWithoutCache($context),
|
||||
};
|
||||
|
||||
$renderTime = microtime(true) - $startTime;
|
||||
$this->logCachePerformance($context, $analysis, $renderTime);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function renderStaticCached(RenderContext $context, string $template, CacheabilityInfo $analysis): string
|
||||
{
|
||||
$cacheKey = $this->buildStaticCacheKey($context, $analysis);
|
||||
|
||||
// Prüfe zuerst, ob bereits im Cache
|
||||
$wasInCache = $this->cache->has($cacheKey);
|
||||
|
||||
// Nutze remember-Pattern
|
||||
$cacheItem = $this->cache->remember(
|
||||
$cacheKey,
|
||||
function() use ($context, $template) {
|
||||
$this->logDebug("CACHE MISS - Generating new content", $context);
|
||||
$this->cacheStats['misses']++;
|
||||
return $this->processor->render($context, $template);
|
||||
},
|
||||
$analysis->ttl
|
||||
);
|
||||
|
||||
if ($wasInCache) {
|
||||
$this->logDebug("CACHE HIT - Using cached content", $context);
|
||||
$this->cacheStats['hits']++;
|
||||
}
|
||||
|
||||
$this->cacheStats['cached_templates'][$context->template] = [
|
||||
'strategy' => 'static',
|
||||
'key' => $cacheKey,
|
||||
'ttl' => $analysis->ttl,
|
||||
'hit' => $wasInCache
|
||||
];
|
||||
|
||||
return $cacheItem->value;
|
||||
}
|
||||
|
||||
private function renderPartialCached(RenderContext $context, string $template, CacheabilityInfo $analysis): string
|
||||
{
|
||||
$cacheKey = $this->buildPartialCacheKey($context, $analysis);
|
||||
$wasInCache = $this->cache->has($cacheKey);
|
||||
|
||||
$cacheItem = $this->cache->remember(
|
||||
$cacheKey,
|
||||
function() use ($context, $template) {
|
||||
$this->cacheStats['misses']++;
|
||||
return $this->processor->render($context, $template);
|
||||
},
|
||||
$analysis->ttl
|
||||
);
|
||||
|
||||
if ($wasInCache) {
|
||||
$this->cacheStats['hits']++;
|
||||
}
|
||||
|
||||
return $cacheItem->value;
|
||||
}
|
||||
|
||||
private function renderFragmentCached(RenderContext $context, string $template, CacheabilityInfo $analysis): string
|
||||
{
|
||||
// Wenn keine Fragmente erkannt wurden, verwende ein Template-weites Fragment
|
||||
if (empty($analysis->staticFragments) && empty($analysis->dynamicFragments)) {
|
||||
$this->logDebug("No fragments found - creating template-wide fragment", $context);
|
||||
|
||||
$templateFragmentKey = "template_{$context->template}";
|
||||
$wasInCache = $this->fragmentCache->hasFragment($templateFragmentKey, $analysis->dependencies ?? [], $analysis->ttl);
|
||||
|
||||
if ($wasInCache) {
|
||||
$this->logDebug("FRAGMENT HIT - Using cached template", $context);
|
||||
$this->cacheStats['hits']++;
|
||||
$content = $this->fragmentCache->getFragment($templateFragmentKey, $analysis->dependencies ?? []);
|
||||
} else {
|
||||
$this->logDebug("FRAGMENT MISS - Generating new template content", $context);
|
||||
$this->cacheStats['misses']++;
|
||||
$content = $this->fragmentCache->cacheFragment(
|
||||
$templateFragmentKey,
|
||||
function() use ($context, $template) {
|
||||
return $this->processor->render($context, $template);
|
||||
},
|
||||
$analysis->dependencies ?? [],
|
||||
$analysis->ttl
|
||||
);
|
||||
}
|
||||
|
||||
$this->cacheStats['cached_templates'][$context->template] = [
|
||||
'strategy' => 'fragment',
|
||||
'key' => $templateFragmentKey,
|
||||
'ttl' => $analysis->ttl,
|
||||
'hit' => $wasInCache
|
||||
];
|
||||
|
||||
// Request-spezifische Statistiken
|
||||
$hitRate = $this->cacheStats['hits'] + $this->cacheStats['misses'] > 0
|
||||
? round(($this->cacheStats['hits'] / ($this->cacheStats['hits'] + $this->cacheStats['misses'])) * 100, 1)
|
||||
: 0;
|
||||
|
||||
error_log("SmartCache Request Stats: Hits: " . $this->cacheStats['hits'] . ", Misses: " . $this->cacheStats['misses'] . ", Hit Rate: {$hitRate}%");
|
||||
|
||||
return $content;
|
||||
} else {
|
||||
$this->logDebug("Found " . count($analysis->staticFragments) . " static fragments and " . count($analysis->dynamicFragments) . " dynamic fragments", $context);
|
||||
}
|
||||
|
||||
// Verarbeite explizite Fragmente
|
||||
$finalContent = '';
|
||||
|
||||
foreach ($analysis->staticFragments as $fragmentId) {
|
||||
$wasInCache = $this->fragmentCache->hasFragment($fragmentId, $analysis->dependencies ?? [], $analysis->ttl);
|
||||
|
||||
if ($wasInCache) {
|
||||
$this->logDebug("FRAGMENT HIT - Using cached fragment: {$fragmentId}", $context);
|
||||
$this->cacheStats['hits']++;
|
||||
// Direkt aus Cache holen ohne Generator zu verwenden
|
||||
$fragmentContent = $this->fragmentCache->getFragment($fragmentId, $analysis->dependencies ?? []);
|
||||
} else {
|
||||
$this->logDebug("FRAGMENT MISS - Generating fragment: {$fragmentId}", $context);
|
||||
$this->cacheStats['misses']++;
|
||||
$fragmentContent = $this->fragmentCache->cacheFragment(
|
||||
$fragmentId,
|
||||
function() use ($fragmentId, $template, $context) {
|
||||
return $this->renderFragmentFromTemplate($fragmentId, $template, $context);
|
||||
},
|
||||
$analysis->dependencies ?? [],
|
||||
$analysis->ttl
|
||||
);
|
||||
}
|
||||
|
||||
$finalContent .= $fragmentContent;
|
||||
}
|
||||
|
||||
// Rendere dynamische Fragmente ohne Caching
|
||||
foreach ($analysis->dynamicFragments as $fragmentId) {
|
||||
$fragmentContent = $this->renderFragmentFromTemplate($fragmentId, $template, $context);
|
||||
$finalContent .= $fragmentContent;
|
||||
}
|
||||
|
||||
return $finalContent ?: $this->processor->render($context, $template);
|
||||
}
|
||||
|
||||
private function renderFragmentFromTemplate(string $fragmentId, string $template, RenderContext $context): string
|
||||
{
|
||||
// Für jetzt: Wenn es ein Template-Fragment ist, rendere das komplette Template
|
||||
if (str_starts_with($fragmentId, 'template_')) {
|
||||
return $this->processor->render($context, $template);
|
||||
}
|
||||
|
||||
// TODO: Hier könnten wir später spezifische Fragment-Extraktion implementieren
|
||||
// Für jetzt verwende DOM-Wrapper für Fragment-Extraktion
|
||||
try {
|
||||
$domWrapper = DomWrapper::fromString($template);
|
||||
return $this->renderFragment($fragmentId, $domWrapper, $context);
|
||||
} catch (\Exception $e) {
|
||||
$this->logDebug("Fragment rendering failed for {$fragmentId}: " . $e->getMessage(), $context);
|
||||
// Fallback: Rendere komplettes Template
|
||||
return $this->processor->render($context, $template);
|
||||
}
|
||||
}
|
||||
|
||||
private function renderWithoutCache(RenderContext $context): string
|
||||
{
|
||||
$template = $this->loader->load($context->template, $context->controllerClass, $context);
|
||||
return $this->processor->render($context, $template);
|
||||
}
|
||||
|
||||
private function renderFragment(string $fragmentId, DomWrapper $domWrapper, RenderContext $context): string
|
||||
{
|
||||
// Vereinfachte Fragment-Rendering-Logik
|
||||
// In einer vollständigen Implementierung würde hier das spezifische Fragment extrahiert
|
||||
$elements = $domWrapper->getElementsByAttribute('data-fragment-id', $fragmentId);
|
||||
|
||||
if (count($elements) > 0) {
|
||||
$element = $elements[0];
|
||||
return $domWrapper->document->saveHTML($element);
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function extractStaticContent(string $content, CacheabilityInfo $analysis): string
|
||||
{
|
||||
// Entferne dynamische Platzhalter für statisches Caching
|
||||
$staticContent = $content;
|
||||
|
||||
// Ersetze dynamische Teile mit Platzhaltern
|
||||
$staticContent = preg_replace('/\{\{[^}]+}}/', '{{DYNAMIC_PLACEHOLDER}}', $staticContent);
|
||||
|
||||
return $staticContent;
|
||||
}
|
||||
|
||||
private function buildStaticCacheKey(RenderContext $context, $analysis): string
|
||||
{
|
||||
$dependencies = is_object($analysis) && method_exists($analysis, 'dependencies')
|
||||
? $analysis->dependencies
|
||||
: ($analysis->dependencies ?? []);
|
||||
|
||||
$optimizedKey = $this->preprocessor->generateOptimizedCacheKey($context, $dependencies);
|
||||
|
||||
return "static:{$optimizedKey}";
|
||||
}
|
||||
|
||||
private function buildPartialCacheKey(RenderContext $context, $analysis): string
|
||||
{
|
||||
$dependencies = is_object($analysis) && method_exists($analysis, 'dependencies')
|
||||
? $analysis->dependencies
|
||||
: ($analysis->dependencies ?? []);
|
||||
|
||||
$optimizedKey = $this->preprocessor->generateOptimizedCacheKey($context, $dependencies);
|
||||
|
||||
return "partial:{$optimizedKey}";
|
||||
}
|
||||
|
||||
|
||||
public function getCacheStats(): array
|
||||
{
|
||||
$hitRate = $this->cacheStats['hits'] + $this->cacheStats['misses'] > 0
|
||||
? round(($this->cacheStats['hits'] / ($this->cacheStats['hits'] + $this->cacheStats['misses'])) * 100, 2)
|
||||
: 0;
|
||||
|
||||
return [
|
||||
'smart_cache' => [
|
||||
'enabled' => $this->cacheEnabled,
|
||||
'debug_mode' => $this->debugMode,
|
||||
'cache_interface' => get_class($this->cache),
|
||||
'performance' => [
|
||||
'total_renders' => $this->cacheStats['renders'],
|
||||
'cache_hits' => $this->cacheStats['hits'],
|
||||
'cache_misses' => $this->cacheStats['misses'],
|
||||
'hit_rate' => $hitRate . '%',
|
||||
],
|
||||
'cached_templates' => $this->cacheStats['cached_templates'],
|
||||
'fragment_stats' => $this->fragmentCache->getFragmentStats(),
|
||||
]
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
public function invalidateCache(?string $template = null): int
|
||||
{
|
||||
$invalidated = 0;
|
||||
|
||||
if ($template) {
|
||||
// Invalidiere spezifisches Template
|
||||
$patterns = [
|
||||
"static:{$template}:",
|
||||
"partial:{$template}:",
|
||||
"template_{$template}",
|
||||
];
|
||||
|
||||
foreach ($patterns as $pattern) {
|
||||
// Vereinfachte Implementierung - da das Cache-Interface keine Pattern-Suche unterstützt
|
||||
// könnte hier eine erweiterte Lösung implementiert werden
|
||||
$invalidated++;
|
||||
}
|
||||
} else {
|
||||
// Alle Caches löschen und Stats zurücksetzen
|
||||
if ($this->cache->clear()) {
|
||||
$this->resetStats();
|
||||
$invalidated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return $invalidated;
|
||||
}
|
||||
|
||||
public function resetStats(): void
|
||||
{
|
||||
$this->cacheStats = [
|
||||
'hits' => 0,
|
||||
'misses' => 0,
|
||||
'renders' => 0,
|
||||
'cached_templates' => [],
|
||||
];
|
||||
}
|
||||
|
||||
public function warmupCache(array $templates = []): array
|
||||
{
|
||||
if (!$this->warmer) {
|
||||
return ['error' => 'CacheWarmer not configured'];
|
||||
}
|
||||
|
||||
return $this->warmer->warmupTemplates($templates);
|
||||
}
|
||||
|
||||
public function addPopularTemplate(string $template, array $data = []): void
|
||||
{
|
||||
if ($this->warmer) {
|
||||
$this->warmer->addPopularTemplate($template, $data);
|
||||
}
|
||||
}
|
||||
|
||||
public function diagnoseCaching(): void
|
||||
{
|
||||
echo "\n=== CACHE DIAGNOSTICS ===\n";
|
||||
echo "Smart Cache Enabled: " . ($this->cacheEnabled ? 'YES' : 'NO') . "\n";
|
||||
echo "Cache Interface: " . get_class($this->cache) . "\n";
|
||||
echo "Debug Mode: " . ($this->debugMode ? 'YES' : 'NO') . "\n";
|
||||
echo "Total Renders: " . $this->cacheStats['renders'] . "\n";
|
||||
echo "Cache Hits: " . $this->cacheStats['hits'] . "\n";
|
||||
echo "Cache Misses: " . $this->cacheStats['misses'] . "\n";
|
||||
|
||||
$hitRate = $this->cacheStats['hits'] + $this->cacheStats['misses'] > 0
|
||||
? round(($this->cacheStats['hits'] / ($this->cacheStats['hits'] + $this->cacheStats['misses'])) * 100, 2)
|
||||
: 0;
|
||||
echo "Hit Rate: " . $hitRate . "%\n";
|
||||
|
||||
echo "\n=== ANALYSIS ===\n";
|
||||
if ($this->cacheStats['hits'] === 0 && $this->cacheStats['misses'] === 0) {
|
||||
echo "⚠️ PROBLEM: No cache operations detected!\n";
|
||||
echo " This suggests that templates are being rendered with CacheStrategy::DYNAMIC or CacheStrategy::DISABLED\n";
|
||||
echo " Check the TemplateAnalyzer logic to ensure templates are being marked as cacheable.\n";
|
||||
}
|
||||
|
||||
echo "========================\n";
|
||||
}
|
||||
|
||||
private function logCachePerformance(RenderContext $context, CacheabilityInfo $analysis, float $renderTime): void
|
||||
{
|
||||
if (!$this->debugMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
$logData = [
|
||||
'template' => $context->template,
|
||||
'strategy' => $analysis->cacheStrategy->value,
|
||||
'render_time' => round($renderTime * 1000, 2) . 'ms',
|
||||
'complexity' => $analysis->getCacheComplexity(),
|
||||
'cacheable' => $analysis->cacheStrategy->shouldCache(),
|
||||
'request_hits' => $this->cacheStats['hits'],
|
||||
'request_misses' => $this->cacheStats['misses'],
|
||||
'static_fragments' => count($analysis->staticFragments),
|
||||
'dynamic_fragments' => count($analysis->dynamicFragments),
|
||||
'ttl' => $analysis->ttl,
|
||||
];
|
||||
|
||||
error_log('SmartCache Performance: ' . json_encode($logData));
|
||||
|
||||
// Zusätzliche Fragment-Details wenn Fragment-Strategy
|
||||
if ($analysis->cacheStrategy === CacheStrategy::FRAGMENT) {
|
||||
error_log('SmartCache Fragments: static=[' . implode(',', $analysis->staticFragments) .
|
||||
'] dynamic=[' . implode(',', $analysis->dynamicFragments) . ']');
|
||||
}
|
||||
}
|
||||
|
||||
private function logDebug(string $message, RenderContext $context): void
|
||||
{
|
||||
if (!$this->debugMode) {
|
||||
return;
|
||||
}
|
||||
|
||||
error_log("SmartCache DEBUG [{$context->template}]: {$message}");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user