MockCache   A
last analyzed

Complexity

Total Complexity 23

Size/Duplication

Total Lines 143
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 52
c 1
b 0
f 0
dl 0
loc 143
rs 10
wmc 23

11 Methods

Rating   Name   Duplication   Size   Complexity  
A get() 0 7 3
A setMultiple() 0 8 2
A set() 0 18 4
A clear() 0 6 1
A __construct() 0 4 1
A delete() 0 14 3
A skipTime() 0 3 1
A deleteMultiple() 0 8 2
A validateKey() 0 4 2
A getMultiple() 0 10 3
A has() 0 3 1
1
<?php
2
3
namespace Kodus\Cache;
4
5
use DateInterval;
6
use Psr\SimpleCache\CacheInterface;
7
use Traversable;
8
9
/**
10
 * WARNING! Don't use in production, only use for automated testing!
11
 *
12
 * This is a mock PSR-16 simple cache implementation - it's internal state survives only for the
13
 * lifetime of the object itself.
14
 */
15
class MockCache implements CacheInterface
16
{
17
    /**
18
     * @var int
19
     */
20
    const DEFAULT_TTL = 86400;
21
22
    /**
23
     * @var string control characters for keys, reserved by PSR-16
24
     */
25
    const PSR16_RESERVED = '/\{|\}|\(|\)|\/|\\\\|\@|\:/u';
26
27
    /**
28
     * @var array map where cache key => serialized value
29
     */
30
    protected $cache = [];
31
32
    /**
33
     * @var int[] map where cache key => expiration timestamp
34
     */
35
    protected $cache_expiration = [];
36
37
    /**
38
     * @var int current frozen timestamp
39
     */
40
    protected $time;
41
42
    /**
43
     * @var int
44
     */
45
    protected $default_ttl;
46
47
    /**
48
     * @param int $default_ttl default time-to-live (in seconds)
49
     */
50
    public function __construct($default_ttl = self::DEFAULT_TTL)
51
    {
52
        $this->default_ttl = $default_ttl;
53
        $this->time = 0;
54
    }
55
56
    /**
57
     * @param int $seconds
58
     */
59
    public function skipTime($seconds)
60
    {
61
        $this->time += $seconds;
62
    }
63
64
    public function get(string $key, mixed $default = null): mixed
65
    {
66
        $this->validateKey($key);
67
68
        return isset($this->cache_expiration[$key]) && ($this->time < $this->cache_expiration[$key])
69
            ? unserialize($this->cache[$key])
70
            : $default;
71
    }
72
73
    public function set(string $key, mixed $value, DateInterval|int|null $ttl = null): bool
74
    {
75
        $this->validateKey($key);
76
77
        if (is_int($ttl)) {
78
            $expires_at = $this->time + $ttl;
79
        } elseif ($ttl instanceof DateInterval) {
80
            $expires_at = date_create_from_format("U", $this->time)->add($ttl)->getTimestamp();
81
        } elseif ($ttl === null) {
0 ignored issues
show
introduced by
The condition $ttl === null is always true.
Loading history...
82
            $expires_at = $this->time + $this->default_ttl;
83
        } else {
84
            throw new InvalidArgumentException("invalid TTL: " . print_r($ttl, true));
85
        }
86
87
        $this->cache[$key] = serialize($value);
88
        $this->cache_expiration[$key] = $expires_at;
89
90
        return true;
91
    }
92
93
    public function delete(string $key): bool
94
    {
95
        $this->validateKey($key);
96
97
        $success = true;
98
99
        if (! isset($this->cache[$key]) || ! isset($this->cache_expiration[$key])) {
100
            $success = false;
101
        }
102
103
        unset($this->cache[$key]);
104
        unset($this->cache_expiration[$key]);
105
106
        return $success;
107
    }
108
109
    public function clear(): bool
110
    {
111
        $this->cache = [];
112
        $this->cache_expiration = [];
113
114
        return true;
115
    }
116
117
    public function getMultiple(iterable $keys, mixed $default = null): iterable
118
    {
119
        $values = [];
120
121
        foreach ($keys as $key) {
122
            $this->validateKey($key);
123
            $values[$key] = $this->get($key) ?: $default;
124
        }
125
126
        return $values;
127
    }
128
129
    public function setMultiple(iterable $values, DateInterval|int|null $ttl = null): bool
130
    {
131
        foreach ($values as $key => $value) {
132
            $this->validateKey($key);
133
            $this->set($key, $value, $ttl);
134
        }
135
136
        return true;
137
    }
138
139
    public function deleteMultiple(iterable $keys): bool
140
    {
141
        foreach ($keys as $key) {
142
            $this->validateKey($key);
143
            $this->delete($key);
144
        }
145
146
        return true;
147
    }
148
149
    public function has(string $key): bool
150
    {
151
        return $this->get($key, $this) !== $this;
152
    }
153
154
    protected function validateKey($key)
155
    {
156
        if (preg_match(self::PSR16_RESERVED, $key, $match) === 1) {
157
            throw new InvalidArgumentException("invalid character in key: {$match[0]}");
158
        }
159
    }
160
}
161