mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-09-16 12:01:36 +02:00
Mechanical, behaviour-preserving reformat produced by 'make cs-fix' under the new build/phpcs.xml.dist ruleset: K&R braces, tab indentation, and the other whitespace normalisations. No logic changes.
257 lines
5.6 KiB
PHP
257 lines
5.6 KiB
PHP
<?php
|
|
|
|
namespace XcVm\Core\Cache;
|
|
|
|
use XcVm\Infrastructure\Redis\RedisManager;
|
|
|
|
/**
|
|
* \Redis Cache Driver
|
|
*
|
|
* \Redis-based cache driver implementing CacheInterface.
|
|
* Wraps the phpredis extension with serialization and TTL support.
|
|
*
|
|
* ServiceContainer Registration:
|
|
*
|
|
* $container->set('redis', function($c) {
|
|
* $settings = $c->get('settings');
|
|
* $config = $c->get('config');
|
|
* return new RedisCache(
|
|
* $config['hostname'],
|
|
* 6379,
|
|
* $settings['redis_password']
|
|
* );
|
|
* });
|
|
*
|
|
* Raw \Redis Access:
|
|
*
|
|
* During migration, legacy code may need raw \Redis:
|
|
* $rawRedis = $redisCache->getConnection();
|
|
* $rawRedis->multi();
|
|
* $rawRedis->zAdd('LIVE', $timestamp, $uuid);
|
|
* $rawRedis->exec();
|
|
*
|
|
* @see CacheInterface
|
|
* @see RedisManager::ensureConnected()
|
|
*
|
|
* @package XC_VM_Core_Cache
|
|
* @author Divarion_D <https://github.com/Divarion-D>
|
|
* @copyright 2025-2026 Vateron Media
|
|
* @link https://github.com/Vateron-Media/XC_VM
|
|
* @license AGPL-3.0 https://www.gnu.org/licenses/agpl-3.0.html
|
|
*/
|
|
|
|
class RedisCache implements CacheInterface {
|
|
/** @var \Redis|null phpredis connection */
|
|
protected $redis = null;
|
|
|
|
/** @var string \Redis host */
|
|
protected $host;
|
|
|
|
/** @var int \Redis port */
|
|
protected $port;
|
|
|
|
/** @var string|null \Redis password */
|
|
protected $password;
|
|
|
|
/** @var bool Whether connection is established */
|
|
protected $connected = false;
|
|
|
|
/** @var string Key prefix to avoid collisions */
|
|
protected $prefix = '';
|
|
|
|
/**
|
|
* @param string $host \Redis host
|
|
* @param int $port \Redis port
|
|
* @param string|null $password \Redis AUTH password
|
|
* @param string $prefix Optional key prefix
|
|
*/
|
|
public function __construct(string $host = '127.0.0.1', int $port = 6379, ?string $password = null, string $prefix = '') {
|
|
$this->host = $host;
|
|
$this->port = $port;
|
|
$this->password = $password;
|
|
$this->prefix = $prefix;
|
|
}
|
|
|
|
/**
|
|
* Establish \Redis connection (lazy — called on first operation)
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function connect() {
|
|
if ($this->connected && $this->redis !== null) {
|
|
return true;
|
|
}
|
|
|
|
try {
|
|
$this->redis = new \Redis();
|
|
$this->redis->connect($this->host, $this->port);
|
|
|
|
if ($this->password) {
|
|
$this->redis->auth($this->password);
|
|
}
|
|
|
|
// Use igbinary serializer if available for consistency with FileCache
|
|
if (defined('Redis::SERIALIZER_IGBINARY')) {
|
|
$this->redis->setOption(\Redis::OPT_SERIALIZER, \Redis::SERIALIZER_IGBINARY);
|
|
}
|
|
|
|
$this->connected = true;
|
|
return true;
|
|
} catch (\Exception $e) {
|
|
$this->redis = null;
|
|
$this->connected = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function get($key, $maxAge = null) {
|
|
if (!$this->ensureConnected()) {
|
|
return false;
|
|
}
|
|
|
|
$prefixedKey = $this->prefix . $key;
|
|
$data = $this->redis->get($prefixedKey);
|
|
|
|
if ($data === false) {
|
|
return false;
|
|
}
|
|
|
|
// maxAge is handled by \Redis TTL, not by us
|
|
// But if caller wants to check age, we can't — \Redis doesn't store creation time
|
|
// For file-based TTL compat, we ignore maxAge here (\Redis uses its own TTL)
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function set($key, $data, $ttl = 0) {
|
|
if (!$this->ensureConnected()) {
|
|
return false;
|
|
}
|
|
|
|
$prefixedKey = $this->prefix . $key;
|
|
|
|
if ($ttl > 0) {
|
|
return $this->redis->setex($prefixedKey, $ttl, $data);
|
|
}
|
|
|
|
return $this->redis->set($prefixedKey, $data);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function delete($key) {
|
|
if (!$this->ensureConnected()) {
|
|
return false;
|
|
}
|
|
|
|
$prefixedKey = $this->prefix . $key;
|
|
$this->redis->del($prefixedKey);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*/
|
|
public function has($key, $maxAge = null) {
|
|
if (!$this->ensureConnected()) {
|
|
return false;
|
|
}
|
|
|
|
$prefixedKey = $this->prefix . $key;
|
|
|
|
return (bool) $this->redis->exists($prefixedKey);
|
|
}
|
|
|
|
/**
|
|
* {@inheritdoc}
|
|
*
|
|
* WARNING: Flushes the ENTIRE \Redis database. Use with caution.
|
|
*/
|
|
public function flush() {
|
|
if (!$this->ensureConnected()) {
|
|
return false;
|
|
}
|
|
|
|
return $this->redis->flushDB();
|
|
}
|
|
|
|
// ───────────────────────────────────────────────────────────
|
|
// Raw \Redis Access (for migration period)
|
|
// ───────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Get the raw phpredis connection
|
|
*
|
|
* Allows legacy code to use \Redis-specific operations (sorted sets,
|
|
* pipelines, pub/sub, etc.) that don't fit the CacheInterface.
|
|
*
|
|
* @return \Redis|null
|
|
*/
|
|
public function getConnection() {
|
|
$this->ensureConnected();
|
|
return $this->redis;
|
|
}
|
|
|
|
/**
|
|
* Check if connection is alive
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isConnected() {
|
|
if (!$this->connected || !$this->redis) {
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
return $this->redis->ping() !== false;
|
|
} catch (\Exception $e) {
|
|
$this->connected = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Close connection
|
|
*/
|
|
public function disconnect() {
|
|
if ($this->redis) {
|
|
try {
|
|
$this->redis->close();
|
|
} catch (\Exception $e) {
|
|
// ignore
|
|
}
|
|
}
|
|
|
|
$this->redis = null;
|
|
$this->connected = false;
|
|
}
|
|
|
|
/**
|
|
* Ensure connection is active, reconnect if needed
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function ensureConnected() {
|
|
if ($this->connected && $this->redis !== null) {
|
|
return true;
|
|
}
|
|
|
|
return $this->connect();
|
|
}
|
|
|
|
/**
|
|
* Disconnect from \Redis when the instance is destroyed.
|
|
*/
|
|
public function __destruct() {
|
|
$this->disconnect();
|
|
}
|
|
}
|