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