Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
10 / 10
CRAP
100.00% covered (success)
100.00%
1 / 1
InMemoryCache
100.00% covered (success)
100.00%
40 / 40
100.00% covered (success)
100.00%
10 / 10
22
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%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 set
100.00% covered (success)
100.00%
9 / 9
100.00% covered (success)
100.00%
1 / 1
4
 has
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
4
 delete
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 clear
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getMultiple
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 setMultiple
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 deleteMultiple
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 normalizeTtl
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
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\CacheEntry;
16use Phexium\Plugin\Cache\Port\CacheInterface;
17use Phexium\Plugin\Clock\Port\ClockInterface;
18
19final class InMemoryCache implements CacheInterface
20{
21    private array $cache = [];
22
23    public function __construct(
24        private readonly ClockInterface $clock,
25    ) {}
26
27    #[Override]
28    public function get(string $key, mixed $default = null): mixed
29    {
30        if (!$this->has($key)) {
31            return $default;
32        }
33
34        return $this->cache[$key]->value;
35    }
36
37    #[Override]
38    public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool
39    {
40        $ttlSeconds = $this->normalizeTtl($ttl);
41
42        if ($ttlSeconds !== null && $ttlSeconds <= 0) {
43            $this->delete($key);
44
45            return true;
46        }
47
48        $expiresAt = null;
49
50        if ($ttlSeconds !== null) {
51            $expiresAt = $this->clock->now()->getTimestamp() + $ttlSeconds;
52        }
53
54        $this->cache[$key] = new CacheEntry($value, $expiresAt);
55
56        return true;
57    }
58
59    #[Override]
60    public function has(string $key): bool
61    {
62        if (!array_key_exists($key, $this->cache)) {
63            return false;
64        }
65
66        $entry = $this->cache[$key];
67
68        if ($entry->expiresAt !== null && $entry->expiresAt <= $this->clock->now()->getTimestamp()) {
69            unset($this->cache[$key]);
70
71            return false;
72        }
73
74        return true;
75    }
76
77    #[Override]
78    public function delete(string $key): bool
79    {
80        if (!array_key_exists($key, $this->cache)) {
81            return false;
82        }
83
84        unset($this->cache[$key]);
85
86        return true;
87    }
88
89    #[Override]
90    public function clear(): bool
91    {
92        $this->cache = [];
93
94        return true;
95    }
96
97    #[Override]
98    public function getMultiple(iterable $keys, mixed $default = null): iterable
99    {
100        $result = [];
101
102        foreach ($keys as $key) {
103            $result[$key] = $this->get($key, $default);
104        }
105
106        return $result;
107    }
108
109    #[Override]
110    public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool
111    {
112        foreach ($values as $key => $value) {
113            $this->set($key, $value, $ttl);
114        }
115
116        return true;
117    }
118
119    #[Override]
120    public function deleteMultiple(iterable $keys): bool
121    {
122        foreach ($keys as $key) {
123            $this->delete($key);
124        }
125
126        return true;
127    }
128
129    private function normalizeTtl(DateInterval|int|null $ttl): ?int
130    {
131        if ($ttl instanceof DateInterval) {
132            $now = new DateTimeImmutable();
133
134            return $now->add($ttl)->getTimestamp() - $now->getTimestamp();
135        }
136
137        return $ttl;
138    }
139}