Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
- [2026-01-09] DamImpr: Redis and memcache cache, instance passed in construction [#32](https://github.com/DamImpr/cache-multi-layer/pull/32)

- [2026-01-09] DamImpr: Instance configuration [#33](https://github.com/DamImpr/cache-multi-layer/pull/33)

- [2026-01-12] DamImpr: redis cache with phpredis or predis [#34](https://github.com/DamImpr/cache-multi-layer/pull/34)
1 change: 1 addition & 0 deletions src/Enum/CacheEnum.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ enum CacheEnum: int
case APCU = 1;
case REDIS = 2;
case MEMCACHE = 3;
case PREDIS = 4;
}
4 changes: 0 additions & 4 deletions src/Exception/CacheMissingConfigurationException.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,4 @@
*/
class CacheMissingConfigurationException extends Exception
{
public function __construct(string $message = "", int $code = 0, ?Throwable $previous = null)
{
parent::__construct($message, $code, $previous);
}
}
1 change: 1 addition & 0 deletions src/Service/Cache.php
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public static function factory(CacheEnum $cacheEnum, int $ttl, array $configurat
return match ($cacheEnum) {
CacheEnum::APCU => new ApcuCache($ttl, $configuration),
CacheEnum::REDIS => new RedisCache($ttl, $configuration),
CacheEnum::PREDIS => new PRedisCache($ttl, $configuration),
CacheEnum::MEMCACHE => new MemcacheCache($ttl, $configuration)
};
}
Expand Down
5 changes: 0 additions & 5 deletions src/Service/CacheManagerImplDryMode.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,6 @@
*/
class CacheManagerImplDryMode extends CacheManagerImpl
{
protected function __construct(?CacheConfiguration $cacheConfiguration = null)
{
parent::__construct($cacheConfiguration);
}

#[\Override]
public function appendCache(Cache $cache): bool
{
Expand Down
6 changes: 5 additions & 1 deletion src/Service/MemcacheCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ protected function __construct(int $ttl, array $configuration = [])
} else {
$this->memcache = new Memcache();
$port = $configuration['port'] ?? 11211;
if (array_key_exists('persistent', $configuration)) {
if (array_key_exists('persistent', $configuration) && $configuration['persistent']) {
$resultConnection = $this->memcache->pconnect($configuration['server_address'], $port);
} else {
$resultConnection = $this->memcache->connect($configuration['server_address'], $port);
Expand All @@ -182,6 +182,7 @@ protected function __construct(int $ttl, array $configuration = [])
throw new Exception("Connection not found");
}
}

$this->compress = array_key_exists('compress', $configuration) && $configuration['compress'];
}

Expand All @@ -194,8 +195,11 @@ protected function assertConfig(array $configuration): void
throw new CacheMissingConfigurationException("instance must be " . Memcache::class . " class");
}
}

private readonly Memcache $memcache;

private readonly bool $compress;

private array $mandatoryKeys = [
'server_address'
];
Expand Down
173 changes: 173 additions & 0 deletions src/Service/PRedisCache.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
<?php

namespace CacheMultiLayer\Service;

use CacheMultiLayer\Enum\CacheEnum;
use CacheMultiLayer\Exception\CacheMissingConfigurationException;
use CacheMultiLayer\Interface\Cacheable;
use Override;
use Predis\Client as PredisClient;

/**
*
* PREDIS cache implementation
* @author Damiano Improta <code@damianoimprota.dev>
*/
class PRedisCache extends Cache
{
/**
*
* {@InheritDoc}
*/
#[\Override]
public function decrement(string $key, ?int $ttl = null): int|false
{
$value = $this->predisClient->decr($key);
if (empty($this->getRemainingTTL($key))) {
$this->predisClient->expire($key, $this->getTtlToUse($ttl));
}

return $value;
}

/**
*
* {@InheritDoc}
*/
#[\Override]
public function get(string $key): int|float|string|Cacheable|array|null
{
$val = $this->predisClient->get($key);
if ($val === null) {
return null;
}

$valDecoded = json_decode($val, true);
return is_array($valDecoded) ? $this->unserializeVal($valDecoded) : $valDecoded;
}

/**
*
* {@InheritDoc}
*/
#[\Override]
public function set(string $key, int|float|string|Cacheable|array $val, ?int $ttl = null): bool
{
$data = is_array($val) ? $this->serializeValArray($val) : $this->serializeVal($val);
return $this->predisClient->setex($key, $this->getTtlToUse($ttl), json_encode($data)) !== null;
}

/**
*
* {@InheritDoc}
*/
#[Override]
public function increment(string $key, ?int $ttl = null): int|false
{
$value = $this->predisClient->incr($key);
if (empty($this->getRemainingTTL($key))) {
$this->predisClient->expire($key, $this->getTtlToUse($ttl));
}

return $value;
}

/**
*
* {@inheritDoc}
*/
#[Override]
public function clear(string $key): bool
{
return (bool) $this->predisClient->del($key);
}

/**
*
* {@inheritDoc}
*/
#[Override]
public function clearAllCache(): bool
{
return $this->predisClient->flushall() !== null;
}

/**
*
* {@InheritDoc}
*/
#[Override]
public function getRemainingTTL(string $key): ?int
{
$ttl = $this->predisClient->ttl($key);
return $ttl !== false ? $ttl : null;
}

/**
*
* {@InheritDoc}
*/
protected function __construct(int $ttl, array $configuration = [])
{
parent::__construct($ttl, $configuration);
if (array_key_exists('instance', $configuration)) {
$this->predisClient = $configuration['instance'];
} else {
$this->predisClient = new PredisClient([
'scheme' => $configuration['tcp'] ?? 'tcp',
'host' => $configuration['server_address'],
'port' => $configuration['port'] ?? 6379,
'password' => $configuration['password'] ?? '',
'database' => $configuration['database'] ?? 0,
'persistent' => $configuration['persistent'] ?? false,
'conn_uid' => $configuration['connection_id'] ?? ''
]);
}
}

/**
*
* {@InheritDoc}
*/
#[\Override]
public function isConnected(): bool
{
return $this->predisClient->ping() !== null;
}

/**
*
* {@InheritDoc}
*/
#[\Override]
public function getEnum(): CacheEnum
{
return CacheEnum::PREDIS;
}

/**
*
* {@InheritDoc}
*/
#[\Override]
protected function getMandatoryConfig(): array
{
return $this->mandatoryKeys;
}

#[\Override]
protected function assertConfig(array $configuration): void
{
if (!array_key_exists('instance', $configuration) || $configuration['instance'] instanceof PredisClient) {
parent::assertConfig($configuration);
} elseif (array_key_exists('instance', $configuration)) {
throw new CacheMissingConfigurationException("instance must be " . PredisClient::class . " class");
}
}

private readonly PredisClient $predisClient;

private array $mandatoryKeys = [
'server_address'
];
}
47 changes: 23 additions & 24 deletions src/Service/RedisCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use CacheMultiLayer\Exception\CacheMissingConfigurationException;
use CacheMultiLayer\Interface\Cacheable;
use Override;
use Predis\Client as PredisClient;

/**
*
Expand All @@ -22,9 +21,9 @@ class RedisCache extends Cache
#[\Override]
public function decrement(string $key, ?int $ttl = null): int|false
{
$value = $this->predisClient->decr($key);
$value = $this->redis->decr($key);
if (empty($this->getRemainingTTL($key))) {
$this->predisClient->expire($key, $this->getTtlToUse($ttl));
$this->redis->expire($key, $this->getTtlToUse($ttl));
}

return $value;
Expand All @@ -37,12 +36,12 @@ public function decrement(string $key, ?int $ttl = null): int|false
#[\Override]
public function get(string $key): int|float|string|Cacheable|array|null
{
$val = $this->predisClient->get($key);
$val = $this->redis->get($key);
if ($val === null) {
return null;
}

$valDecoded = json_decode($val, true);
$valDecoded = json_decode((string) $val, true);
return is_array($valDecoded) ? $this->unserializeVal($valDecoded) : $valDecoded;
}

Expand All @@ -54,7 +53,7 @@ public function get(string $key): int|float|string|Cacheable|array|null
public function set(string $key, int|float|string|Cacheable|array $val, ?int $ttl = null): bool
{
$data = is_array($val) ? $this->serializeValArray($val) : $this->serializeVal($val);
return $this->predisClient->setex($key, $this->getTtlToUse($ttl), json_encode($data)) !== null;
return $this->redis->setex($key, $this->getTtlToUse($ttl), json_encode($data)) !== null;
}

/**
Expand All @@ -64,9 +63,9 @@ public function set(string $key, int|float|string|Cacheable|array $val, ?int $tt
#[Override]
public function increment(string $key, ?int $ttl = null): int|false
{
$value = $this->predisClient->incr($key);
$value = $this->redis->incr($key);
if (empty($this->getRemainingTTL($key))) {
$this->predisClient->expire($key, $this->getTtlToUse($ttl));
$this->redis->expire($key, $this->getTtlToUse($ttl));
}

return $value;
Expand All @@ -79,7 +78,7 @@ public function increment(string $key, ?int $ttl = null): int|false
#[Override]
public function clear(string $key): bool
{
return (bool) $this->predisClient->del($key);
return (bool) $this->redis->del($key);
}

/**
Expand All @@ -89,7 +88,7 @@ public function clear(string $key): bool
#[Override]
public function clearAllCache(): bool
{
return $this->predisClient->flushall() !== null;
return $this->redis->flushall() !== null;
}

/**
Expand All @@ -99,7 +98,7 @@ public function clearAllCache(): bool
#[Override]
public function getRemainingTTL(string $key): ?int
{
$ttl = $this->predisClient->ttl($key);
$ttl = $this->redis->ttl($key);
return $ttl !== false ? $ttl : null;
}

Expand All @@ -111,16 +110,14 @@ protected function __construct(int $ttl, array $configuration = [])
{
parent::__construct($ttl, $configuration);
if (array_key_exists('instance', $configuration)) {
$this->predisClient = $configuration['instance'];
$this->redis = $configuration['instance'];
} else {
$this->predisClient = new PredisClient([
'scheme' => $configuration['tcp'] ?? 'tcp',
'host' => $configuration['server_address'],
'port' => $configuration['port'] ?? 6379,
'password' => $configuration['password'] ?? '',
'database' => $configuration['database'] ?? 0,
'persistent' => $configuration['persistent'] ?? false
]);
$this->redis = new \Redis();
if (array_key_exists('persistent', $configuration) && $configuration['persistent']) {
$this->redis->connect($configuration['server_address'], $configuration['port'] ?? 6379, $configuration['timeout'] ?? 3, $configuration['connection_id'] ?? 'app_redis_connection');
} else {
$this->redis->connect($configuration['server_address'], $configuration['port'] ?? 6379, $configuration['timeout'] ?? 3);
}
}
}

Expand All @@ -131,7 +128,7 @@ protected function __construct(int $ttl, array $configuration = [])
#[\Override]
public function isConnected(): bool
{
return $this->predisClient->ping() !== null;
return $this->redis->ping() !== null;
}

/**
Expand All @@ -157,13 +154,15 @@ protected function getMandatoryConfig(): array
#[\Override]
protected function assertConfig(array $configuration): void
{
if (!array_key_exists('instance', $configuration) || $configuration['instance'] instanceof PredisClient) {
if (!array_key_exists('instance', $configuration) || $configuration['instance'] instanceof \Redis) {
parent::assertConfig($configuration);
} elseif (array_key_exists('instance', $configuration)) {
throw new CacheMissingConfigurationException("instance must be " . PredisClient::class . " class");
throw new CacheMissingConfigurationException("instance must be " . \Redis::class . " class");
}
}
private readonly PredisClient $predisClient;

private readonly \Redis $redis;

private array $mandatoryKeys = [
'server_address'
];
Expand Down
Loading