| Server IP : 202.61.199.114 / Your IP : 216.73.217.139 Web Server : nginx/1.22.1 System : Linux de.arni-solutions.de 6.1.0-49-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.174-1 (2026-05-26) x86_64 User : web20 ( 1018) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /var/www/seaside2.pacim.de/web/app/services/ |
Upload File : |
<?php
/**
* Einfacher DB-Cache für teure Aggregations-Queries (Dashboard, Reports).
*
* Verwendung:
* $kpis = ReportCache::remember('dashboard.kpis', 300, fn() => $reportRepo->kpis());
*
* Garbage-Collection: läuft mit kleiner Wahrscheinlichkeit (1 %) bei jedem
* Aufruf — kein eigener Cron nötig.
*/
class ReportCache
{
private PDO $pdo;
private static ?ReportCache $instance = null;
public function __construct(Database $db)
{
$this->pdo = $db->getConnection();
}
public static function bind(ReportCache $instance): void
{
self::$instance = $instance;
}
/**
* Liefert den gecachten Wert oder ruft $producer() auf und speichert das Ergebnis.
* Bei Cache-Fehlern wird $producer() ausgeführt — die Anwendung bricht nie ab.
*/
public static function remember(string $key, int $ttlSeconds, callable $producer)
{
if (self::$instance === null) {
return $producer();
}
return self::$instance->doRemember($key, $ttlSeconds, $producer);
}
public static function forget(string $key): void
{
self::$instance?->doForget($key);
}
public static function flush(): void
{
self::$instance?->doFlush();
}
private function doRemember(string $key, int $ttlSeconds, callable $producer)
{
$this->gcMaybe();
try {
$stmt = $this->pdo->prepare(
"SELECT cache_value FROM report_cache
WHERE cache_key = :k AND expires_at > NOW() LIMIT 1"
);
$stmt->execute(['k' => $key]);
$val = $stmt->fetchColumn();
if ($val !== false) {
$decoded = json_decode((string)$val, true);
if ($decoded !== null || $val === 'null') return $decoded;
}
} catch (Throwable) {
return $producer();
}
$value = $producer();
try {
$stmt = $this->pdo->prepare(
"INSERT INTO report_cache (cache_key, cache_value, expires_at)
VALUES (:k, :v, DATE_ADD(NOW(), INTERVAL :ttl SECOND))
ON DUPLICATE KEY UPDATE
cache_value = VALUES(cache_value),
expires_at = VALUES(expires_at)"
);
$stmt->execute([
'k' => $key,
'v' => json_encode($value, JSON_UNESCAPED_UNICODE),
'ttl' => max(1, $ttlSeconds),
]);
} catch (Throwable $e) {
error_log('ReportCache write ' . $key . ': ' . $e->getMessage());
}
return $value;
}
private function doForget(string $key): void
{
try {
$stmt = $this->pdo->prepare("DELETE FROM report_cache WHERE cache_key = :k");
$stmt->execute(['k' => $key]);
} catch (Throwable) { /* selbstheilend */ }
}
private function doFlush(): void
{
try { $this->pdo->exec("DELETE FROM report_cache"); }
catch (Throwable) { /* selbstheilend */ }
}
private function gcMaybe(): void
{
// Mit 1 % Wahrscheinlichkeit abgelaufene Einträge wegräumen.
if (random_int(0, 99) !== 0) return;
try { $this->pdo->exec("DELETE FROM report_cache WHERE expires_at <= NOW()"); }
catch (Throwable) { /* selbstheilend */ }
}
}