feat(cache): implement centralized caching layer for improved performance and reduced API calls

feat(microsoft-integration): enhance inbox and events fetching with caching support
feat(auth): include theme and notification settings in user data retrieval
feat(profile): improve password visibility toggle functionality
feat(planner): optimize event synchronization with Outlook using caching
fix(notifications): update mail badge handling for mobile and desktop
This commit is contained in:
2026-09-10 15:19:46 +02:00
parent 5310b87fe5
commit 72ad1fb70e
15 changed files with 334 additions and 85 deletions
+139
View File
@@ -0,0 +1,139 @@
<?php
/**
* Centrale Caching Laag voor Fociz
* Biedt een supersnelle database- én in-memory transiënte cache voor externe API-aanroepen (Microsoft Graph, Jira Cloud).
*/
require_once __DIR__ . '/../config/database.php';
function ensure_app_cache_table(?PDO $db = null): void {
static $ensured = false;
if ($ensured) return;
try {
$pdo = $db ?: get_db_connection();
$pdo->exec("
CREATE TABLE IF NOT EXISTS `app_cache` (
`cache_key` VARCHAR(128) NOT NULL PRIMARY KEY,
`cache_value` MEDIUMTEXT NOT NULL,
`expires_at` INT UNSIGNED NOT NULL,
INDEX `idx_app_cache_expires` (`expires_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
");
$ensured = true;
} catch (Throwable $e) {
error_log("ensure_app_cache_table error: " . $e->getMessage());
}
}
/**
* Haalt een item op uit de cache.
* Controleert eerst het runtime statisch geheugen, vervolgens MariaDB.
*/
function fociz_cache_get(string $key, $default = null) {
static $memoryCache = [];
$now = time();
// 1. Runtime memory check (0ms)
if (isset($memoryCache[$key])) {
if ($memoryCache[$key]['expires_at'] > $now) {
return $memoryCache[$key]['value'];
}
unset($memoryCache[$key]);
}
// 2. Database check (< 0.5ms)
try {
$db = get_db_connection();
ensure_app_cache_table($db);
$stmt = $db->prepare("SELECT cache_value, expires_at FROM app_cache WHERE cache_key = ?");
$stmt->execute([$key]);
$row = $stmt->fetch();
if ($row) {
if ((int)$row['expires_at'] > $now) {
$decoded = json_decode($row['cache_value'], true);
$val = ($decoded !== null || $row['cache_value'] === 'null') ? $decoded : $row['cache_value'];
$memoryCache[$key] = [
'value' => $val,
'expires_at' => (int)$row['expires_at']
];
return $val;
} else {
// Verlopen item direct opruimen
$del = $db->prepare("DELETE FROM app_cache WHERE cache_key = ?");
$del->execute([$key]);
}
}
} catch (Throwable $e) {
error_log("fociz_cache_get error for {$key}: " . $e->getMessage());
}
return $default;
}
/**
* Slaat een item op in de cache met een bepaalde levensduur in seconden.
*/
function fociz_cache_set(string $key, $value, int $ttlSeconds = 60): bool {
static $memoryCache = [];
$now = time();
$expiresAt = $now + max(1, $ttlSeconds);
// 1. Sla op in runtime memory
$memoryCache[$key] = [
'value' => $value,
'expires_at' => $expiresAt
];
// 2. Sla op in database
try {
$db = get_db_connection();
ensure_app_cache_table($db);
$valToStore = is_string($value) ? $value : json_encode($value, JSON_UNESCAPED_UNICODE);
$stmt = $db->prepare("
INSERT INTO app_cache (cache_key, cache_value, expires_at)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE
cache_value = VALUES(cache_value),
expires_at = VALUES(expires_at)
");
return $stmt->execute([$key, $valToStore, $expiresAt]);
} catch (Throwable $e) {
error_log("fociz_cache_set error for {$key}: " . $e->getMessage());
return false;
}
}
/**
* Verwijdert een specifiek item uit de cache.
*/
function fociz_cache_delete(string $key): bool {
try {
$db = get_db_connection();
ensure_app_cache_table($db);
$stmt = $db->prepare("DELETE FROM app_cache WHERE cache_key = ?");
return $stmt->execute([$key]);
} catch (Throwable $e) {
return false;
}
}
/**
* Verwijdert alle items met een bepaald voorvoegsel (bijv. 'ms_events_1_')
*/
function fociz_cache_delete_pattern(string $prefix): bool {
try {
$db = get_db_connection();
ensure_app_cache_table($db);
$stmt = $db->prepare("DELETE FROM app_cache WHERE cache_key LIKE ?");
return $stmt->execute([$prefix . '%']);
} catch (Throwable $e) {
return false;
}
}