fileCachePath = __DIR__ . '/../../cache/'; $this->initRedis(); } /** * Redis-Verbindung initialisieren */ private function initRedis() { try { $this->redis = new Redis(); $this->redis->connect( getenv('REDIS_HOST') ?: 'redis', getenv('REDIS_PORT') ?: 6379 ); if (getenv('REDIS_PASSWORD')) { $this->redis->auth(getenv('REDIS_PASSWORD')); } $this->redis->select(getenv('REDIS_DB') ?: 0); } catch (Exception $e) { // Redis nicht verfügbar, verwende File-Cache $this->redis = null; } } /** * Cache-Schlüssel generieren */ private function generateKey($key, $prefix = 'ws') { return $prefix . ':' . md5($key); } /** * Wert im Cache speichern */ public function set($key, $value, $ttl = null) { if (!$this->cacheEnabled) { return false; } $ttl = $ttl ?: $this->defaultTtl; $cacheKey = $this->generateKey($key); try { if ($this->redis) { // Redis-Cache $serializedValue = serialize($value); return $this->redis->setex($cacheKey, $ttl, $serializedValue); } else { // File-Cache return $this->setFileCache($cacheKey, $value, $ttl); } } catch (Exception $e) { // Fallback zu File-Cache return $this->setFileCache($cacheKey, $value, $ttl); } } /** * Wert aus dem Cache abrufen */ public function get($key) { if (!$this->cacheEnabled) { return false; } $cacheKey = $this->generateKey($key); try { if ($this->redis) { // Redis-Cache $value = $this->redis->get($cacheKey); return $value ? unserialize($value) : false; } else { // File-Cache return $this->getFileCache($cacheKey); } } catch (Exception $e) { // Fallback zu File-Cache return $this->getFileCache($cacheKey); } } /** * Wert aus dem Cache löschen */ public function delete($key) { $cacheKey = $this->generateKey($key); try { if ($this->redis) { // Redis-Cache return $this->redis->del($cacheKey); } else { // File-Cache return $this->deleteFileCache($cacheKey); } } catch (Exception $e) { // Fallback zu File-Cache return $this->deleteFileCache($cacheKey); } } /** * Cache komplett leeren */ public function clear($pattern = null) { try { if ($this->redis) { // Redis-Cache if ($pattern) { $keys = $this->redis->keys($this->generateKey($pattern, 'ws*')); if (!empty($keys)) { return $this->redis->del($keys); } } else { return $this->redis->flushDB(); } } else { // File-Cache return $this->clearFileCache($pattern); } } catch (Exception $e) { return $this->clearFileCache($pattern); } } /** * Cache-Status prüfen */ public function has($key) { $cacheKey = $this->generateKey($key); try { if ($this->redis) { // Redis-Cache return $this->redis->exists($cacheKey); } else { // File-Cache return $this->hasFileCache($cacheKey); } } catch (Exception $e) { return $this->hasFileCache($cacheKey); } } /** * File-Cache: Wert speichern */ private function setFileCache($key, $value, $ttl) { $filename = $this->fileCachePath . $key . '.cache'; $data = [ 'value' => $value, 'expires' => time() + $ttl ]; if (!is_dir($this->fileCachePath)) { mkdir($this->fileCachePath, 0755, true); } return file_put_contents($filename, serialize($data)) !== false; } /** * File-Cache: Wert abrufen */ private function getFileCache($key) { $filename = $this->fileCachePath . $key . '.cache'; if (!file_exists($filename)) { return false; } $data = unserialize(file_get_contents($filename)); if (!$data || !isset($data['expires']) || $data['expires'] < time()) { // Cache abgelaufen unlink($filename); return false; } return $data['value']; } /** * File-Cache: Wert löschen */ private function deleteFileCache($key) { $filename = $this->fileCachePath . $key . '.cache'; if (file_exists($filename)) { return unlink($filename); } return true; } /** * File-Cache: Status prüfen */ private function hasFileCache($key) { $filename = $this->fileCachePath . $key . '.cache'; if (!file_exists($filename)) { return false; } $data = unserialize(file_get_contents($filename)); if (!$data || !isset($data['expires']) || $data['expires'] < time()) { // Cache abgelaufen unlink($filename); return false; } return true; } /** * File-Cache: Komplett leeren */ private function clearFileCache($pattern = null) { if (!is_dir($this->fileCachePath)) { return true; } $files = glob($this->fileCachePath . '*.cache'); $deleted = 0; foreach ($files as $file) { if ($pattern) { // Nur Dateien löschen, die dem Pattern entsprechen if (strpos(basename($file), md5($pattern)) !== false) { unlink($file); $deleted++; } } else { // Alle Cache-Dateien löschen unlink($file); $deleted++; } } return $deleted; } /** * Cache-Statistiken abrufen */ public function getStats() { $stats = [ 'enabled' => $this->cacheEnabled, 'driver' => $this->redis ? 'redis' : 'file', 'file_cache_path' => $this->fileCachePath, 'default_ttl' => $this->defaultTtl ]; if ($this->redis) { try { $stats['redis_info'] = $this->redis->info(); $stats['redis_keys'] = $this->redis->dbSize(); } catch (Exception $e) { $stats['redis_error'] = $e->getMessage(); } } else { $stats['file_cache_files'] = count(glob($this->fileCachePath . '*.cache')); } return $stats; } /** * Cache aktivieren/deaktivieren */ public function setEnabled($enabled) { $this->cacheEnabled = $enabled; } /** * Cache-Schlüssel mit Tags */ public function setWithTags($key, $value, $tags = [], $ttl = null) { $result = $this->set($key, $value, $ttl); if ($result && !empty($tags)) { foreach ($tags as $tag) { $tagKey = 'tag:' . $tag; $taggedKeys = $this->get($tagKey) ?: []; $taggedKeys[] = $key; $this->set($tagKey, $taggedKeys, $ttl); } } return $result; } /** * Cache mit Tags löschen */ public function deleteByTags($tags) { $deleted = 0; foreach ($tags as $tag) { $tagKey = 'tag:' . $tag; $taggedKeys = $this->get($tagKey) ?: []; foreach ($taggedKeys as $key) { if ($this->delete($key)) { $deleted++; } } $this->delete($tagKey); } return $deleted; } /** * Cache-Warmup für häufig verwendete Daten */ public function warmup() { // Kategorien cachen $this->cacheCategories(); // Konfiguration cachen $this->cacheConfiguration(); // Sprachen cachen $this->cacheLanguages(); } /** * Kategorien cachen */ private function cacheCategories() { try { $connectionParams = [ 'dbname' => getenv('DB_DATABASE') ?: 'freeshop', 'user' => getenv('DB_USERNAME') ?: 'freeshop_user', 'password' => getenv('DB_PASSWORD') ?: 'freeshop_password', 'host' => getenv('DB_HOST') ?: 'db', 'driver' => 'pdo_mysql', 'port' => getenv('DB_PORT') ?: 3306, 'charset' => 'utf8mb4', ]; $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams); $stmt = $conn->prepare('SELECT * FROM ws_category WHERE active = 1 ORDER BY sort_order ASC'); $stmt->execute(); $categories = $stmt->fetchAllAssociative(); $this->set('categories:all', $categories, 3600); // Einzelne Kategorien cachen foreach ($categories as $category) { $this->set('category:' . $category['id'], $category, 3600); } } catch (Exception $e) { // Ignore cache warmup errors } } /** * Konfiguration cachen */ private function cacheConfiguration() { try { $connectionParams = [ 'dbname' => getenv('DB_DATABASE') ?: 'freeshop', 'user' => getenv('DB_USERNAME') ?: 'freeshop_user', 'password' => getenv('DB_PASSWORD') ?: 'freeshop_password', 'host' => getenv('DB_HOST') ?: 'db', 'driver' => 'pdo_mysql', 'port' => getenv('DB_PORT') ?: 3306, 'charset' => 'utf8mb4', ]; $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams); $stmt = $conn->prepare('SELECT name, value FROM ws_configuration'); $stmt->execute(); $config = $stmt->fetchAllAssociative(); $configArray = []; foreach ($config as $item) { $configArray[$item['name']] = $item['value']; } $this->set('config:all', $configArray, 7200); } catch (Exception $e) { // Ignore cache warmup errors } } /** * Sprachen cachen */ private function cacheLanguages() { try { $connectionParams = [ 'dbname' => getenv('DB_DATABASE') ?: 'freeshop', 'user' => getenv('DB_USERNAME') ?: 'freeshop_user', 'password' => getenv('DB_PASSWORD') ?: 'freeshop_password', 'host' => getenv('DB_HOST') ?: 'db', 'driver' => 'pdo_mysql', 'port' => getenv('DB_PORT') ?: 3306, 'charset' => 'utf8mb4', ]; $conn = \Doctrine\DBAL\DriverManager::getConnection($connectionParams); $stmt = $conn->prepare('SELECT * FROM ws_language WHERE active = 1'); $stmt->execute(); $languages = $stmt->fetchAllAssociative(); $this->set('languages:all', $languages, 7200); } catch (Exception $e) { // Ignore cache warmup errors } } }