Files
nabeh/backend/app/Core/Cache.php
2026-05-23 00:20:07 +03:00

129 lines
3.3 KiB
PHP

<?php
namespace App\Core;
/**
* Cache helper class providing Redis-based caching with automatic database fallback.
*/
class Cache
{
private static ?\Redis $client = null;
private static bool $connectionAttempted = false;
/**
* Get initialized Redis client or null if unavailable/disabled.
*/
private static function getClient(): ?\Redis
{
if (self::$connectionAttempted) {
return self::$client;
}
self::$connectionAttempted = true;
if (!Env::get('REDIS_ENABLED', false)) {
return null;
}
if (!class_exists('\Redis')) {
error_log('[Cache Warning] phpredis extension is not installed.');
return null;
}
try {
$redis = new \Redis();
$host = Env::get('REDIS_HOST', '127.0.0.1');
$port = (int)Env::get('REDIS_PORT', 6379);
$password = Env::get('REDIS_PASSWORD', null);
// Connect with 1.0s timeout to prevent request blocking
$connected = $redis->connect($host, $port, 1.0);
if (!$connected) {
error_log("[Cache Warning] Failed to connect to Redis at {$host}:{$port}");
return null;
}
if (!empty($password)) {
$redis->auth($password);
}
self::$client = $redis;
} catch (\Exception $e) {
error_log('[Cache Error] Redis connection error: ' . $e->getMessage());
self::$client = null;
}
return self::$client;
}
/**
* Retrieve cache item by key.
*/
public static function get(string $key)
{
$client = self::getClient();
if (!$client) {
return null;
}
try {
$value = $client->get($key);
return $value !== false ? json_decode($value, true) : null;
} catch (\Exception $e) {
error_log('[Cache Error] Redis get failed: ' . $e->getMessage());
return null;
}
}
/**
* Set cache item by key with TTL.
*/
public static function set(string $key, $value, int $ttl = 3600): bool
{
$client = self::getClient();
if (!$client) {
return false;
}
try {
return $client->setex($key, $ttl, json_encode($value));
} catch (\Exception $e) {
error_log('[Cache Error] Redis set failed: ' . $e->getMessage());
return false;
}
}
/**
* Delete cache item by key.
*/
public static function delete(string $key): bool
{
$client = self::getClient();
if (!$client) {
return false;
}
try {
return $client->del($key) > 0;
} catch (\Exception $e) {
error_log('[Cache Error] Redis delete failed: ' . $e->getMessage());
return false;
}
}
/**
* Retrieve cache item, or run callback and store results if cache misses.
*/
public static function remember(string $key, int $ttl, callable $callback)
{
$value = self::get($key);
if ($value !== null) {
return $value;
}
$value = $callback();
self::set($key, $value, $ttl);
return $value;
}
}