Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
7 / 7
CRAP
100.00% covered (success)
100.00%
1 / 1
RedisCache
100.00% covered (success)
100.00%
25 / 25
100.00% covered (success)
100.00%
7 / 7
13
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 get
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 set
100.00% covered (success)
100.00%
8 / 8
100.00% covered (success)
100.00%
1 / 1
4
 has
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 delete
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 clear
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 normalizeTtl
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
3
1<?php
2
3// ╔════════════════════════════════════════════════════════════╗
4// ║ MIT Licence (#Expat) - https://opensource.org/licenses/MIT ║
5// ║ Copyright 2026 Frederic Poeydomenge <dyno@phexium.com>     ║
6// ╚════════════════════════════════════════════════════════════╝
7
8declare(strict_types=1);
9
10namespace Phexium\Plugin\Cache\Adapter;
11
12use DateInterval;
13use DateTimeImmutable;
14use Override;
15use Phexium\Plugin\Cache\Internal\CacheMultipleOperationsTrait;
16use Phexium\Plugin\Cache\Port\CacheInterface;
17use Redis;
18
19final readonly class RedisCache implements CacheInterface
20{
21    use CacheMultipleOperationsTrait;
22
23    public function __construct(
24        private Redis $redis,
25        private array|bool $allowedClasses = [],
26    ) {}
27
28    #[Override]
29    public function get(string $key, mixed $default = null): mixed
30    {
31        if (!$this->has($key)) {
32            return $default;
33        }
34
35        $value = $this->redis->get($key);
36
37        return unserialize($value, ['allowed_classes' => $this->allowedClasses]);
38    }
39
40    #[Override]
41    public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool
42    {
43        $ttlMilliseconds = $this->normalizeTtl($ttl);
44
45        if ($ttlMilliseconds !== null && $ttlMilliseconds <= 0) {
46            $this->delete($key);
47
48            return true;
49        }
50
51        $serialized = serialize($value);
52
53        if ($ttlMilliseconds === null) {
54            return $this->redis->set($key, $serialized);
55        }
56
57        return $this->redis->psetex($key, $ttlMilliseconds, $serialized);
58    }
59
60    #[Override]
61    public function has(string $key): bool
62    {
63        return $this->redis->exists($key) > 0;
64    }
65
66    #[Override]
67    public function delete(string $key): bool
68    {
69        return $this->redis->del($key) > 0;
70    }
71
72    #[Override]
73    public function clear(): bool
74    {
75        return $this->redis->flushDB();
76    }
77
78    private function normalizeTtl(DateInterval|int|null $ttl): ?int
79    {
80        if ($ttl === null) {
81            return null;
82        }
83
84        if ($ttl instanceof DateInterval) {
85            $now = new DateTimeImmutable();
86            $future = $now->add($ttl);
87
88            $nowMicroseconds = intval($now->format('Uu'));
89            $futureMicroseconds = intval($future->format('Uu'));
90
91            return ($futureMicroseconds - $nowMicroseconds) / 1000;
92        }
93
94        return $ttl * 1000;
95    }
96}