Completed
Push — drivers ( aadeb1...dadabd )
by Joe
02:08
created

CacheProvider::flushDelayedEvents()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 6
c 0
b 0
f 0
dl 0
loc 11
rs 10
cc 2
nc 2
nop 1
1
<?php
2
3
namespace PhpWinTools\WmiScripting\Support\Cache;
4
5
use Closure;
6
use DateInterval;
7
use Psr\SimpleCache\CacheInterface;
8
use Psr\SimpleCache\InvalidArgumentException;
9
use PhpWinTools\WmiScripting\Configuration\Config;
10
use PhpWinTools\WmiScripting\Support\Events\Event;
11
use PhpWinTools\WmiScripting\Support\Events\EventProvider;
12
use function PhpWinTools\WmiScripting\Support\reduce_value;
13
use PhpWinTools\WmiScripting\Support\Cache\Events\CacheHit;
14
use PhpWinTools\WmiScripting\Support\Cache\Events\CacheMissed;
15
use PhpWinTools\WmiScripting\Support\Cache\Events\CacheCleared;
16
use PhpWinTools\WmiScripting\Support\Cache\Events\CacheKeyStored;
17
use PhpWinTools\WmiScripting\Support\Cache\Events\CacheKeyExpired;
18
use PhpWinTools\WmiScripting\Support\Cache\Events\CacheKeyForgotten;
19
use PhpWinTools\WmiScripting\Exceptions\CacheInvalidArgumentException;
20
21
class CacheProvider implements CacheInterface
22
{
23
    /** @var Config */
24
    protected $config;
25
26
    /** @var CacheDriver */
27
    protected $driver;
28
29
    /** @var EventProvider */
30
    protected $events;
31
32
    /** @var array|Event[] */
33
    protected $delayedEvents = [];
34
35
    public function __construct(Config $config = null, CacheDriver $driver = null, EventProvider $events = null)
36
    {
37
        $this->config = $config ?? Config::instance();
38
        $this->driver = $driver ?? $this->config->getCacheDriver();
39
        $this->events = $events ?? $this->config->eventProvider();
40
    }
41
42
    /**
43
     * @param string|array       $key
44
     * @param Closure|null|mixed $default
45
     *
46
     * @throws CacheInvalidArgumentException|InvalidArgumentException
47
     *
48
     * @return iterable|mixed|null
49
     */
50
    public function get($key, $default = null)
51
    {
52
        if (is_array($key)) {
53
            return $this->getMultiple($key, $default);
54
        }
55
56
        $value = $this->driver()->get($key, null);
57
58
        if ($this->driver()->expired($key)) {
59
            $this->fire(new CacheKeyExpired($this->driver(), $key, $value));
60
            $this->delete($key);
61
            $value = null;
62
        }
63
64
        if (is_null($value)) {
65
            $value = reduce_value($default);
66
            $this->fire(new CacheMissed($this->driver(), $key));
67
        } else {
68
            $this->fire(new CacheHit($this->driver(), $key, $value));
69
        }
70
71
        return $value;
72
    }
73
74
    /**
75
     * Accepts either a string or a key-value pair array. If the given an array than the second value is used as the
76
     * ttl, unless the ttl is explicitly set.
77
     *
78
     * @param string|array          $key
79
     * @param mixed                 $value
80
     * @param null|int|DateInterval $ttl
81
     *
82
     * @throws CacheInvalidArgumentException|InvalidArgumentException
83
     *
84
     * @return bool
85
     */
86
    public function set($key, $value = null, $ttl = null)
87
    {
88
        if (is_array($key)) {
89
            return $this->setMultiple($key, $ttl ?? $value);
90
        }
91
92
        $result = $this->driver()->set($key, $value, $ttl);
93
94
        if ($result) {
95
            $this->fire(new CacheKeyStored($this->driver(), $key, $value, $ttl));
96
        }
97
98
        return $result;
99
    }
100
101
    /**
102
     * @param string|array $key
103
     *
104
     * @throws CacheInvalidArgumentException|InvalidArgumentException
105
     *
106
     * @return bool
107
     */
108
    public function delete($key)
109
    {
110
        if (is_array($key)) {
111
            return $this->deleteMultiple($key);
112
        }
113
114
        $result = $this->driver()->delete($key);
115
116
        if ($result) {
117
            $this->fire(new CacheKeyForgotten($this->driver(), $key));
118
        }
119
120
        return $result;
121
    }
122
123
    /**
124
     * @return bool
125
     */
126
    public function clear()
127
    {
128
        $result = $this->driver->clear();
129
130
        if ($result) {
131
            $this->fire(new CacheCleared($this->driver));
132
        }
133
134
        return $result;
135
    }
136
137
    /**
138
     * @param iterable           $keys
139
     * @param Closure|mixed|null $default
140
     *
141
     * @return iterable|mixed
142
     */
143
    public function getMultiple($keys, $default = null)
144
    {
145
        return $this->multiple('get', $keys) ? $this->driver()->getMultiple($keys, $default) : reduce_value($default);
146
    }
147
148
    /**
149
     * @param iterable $values
150
     * @param null     $ttl
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $ttl is correct as it would always require null to be passed?
Loading history...
151
     *
152
     * @return bool
153
     */
154
    public function setMultiple($values, $ttl = null)
155
    {
156
        return $this->multiple('set', $values, $ttl) ? $this->driver()->setMultiple($values, $ttl) : false;
157
    }
158
159
    /**
160
     * @param iterable $keys
161
     *
162
     * @return bool
163
     */
164
    public function deleteMultiple($keys)
165
    {
166
        return $this->multiple('delete', $keys) ? $this->driver()->deleteMultiple($keys) : false;
167
    }
168
169
    /**
170
     * @param string $key
171
     *
172
     * @return bool
173
     */
174
    public function has($key)
175
    {
176
        return $this->driver()->has($key);
177
    }
178
179
    /**
180
     * @return bool
181
     */
182
    public function empty(): bool
183
    {
184
        return $this->driver()->empty();
185
    }
186
187
    /**
188
     * @return bool
189
     */
190
    public function notEmpty(): bool
191
    {
192
        return $this->driver()->notEmpty();
193
    }
194
195
    /**
196
     * @return CacheDriver
197
     */
198
    public function driver()
199
    {
200
        return $this->driver;
201
    }
202
203
    /**
204
     * @param string         $method
205
     * @param iterable       $keys
206
     * @param null|int|mixed $ttl
207
     *
208
     * @return bool
209
     */
210
    protected function multiple(string $method, $keys, $ttl = null): bool
211
    {
212
        foreach ($keys as $key => $value) {
213
            $result = false;
214
215
            if ($method === 'get' && $result = $this->driver()->canGet($value)) {
216
                $this->delayedFire(new CacheHit($this->driver, $key, $this->driver()->get($value)));
217
            }
218
219
            if ($method === 'set' && $result = $this->driver()->canSet($key, $value)) {
220
                $this->delayedFire(new CacheKeyStored($this->driver, $key, $value, $ttl));
221
            }
222
223
            if ($method === 'delete' && $result = $this->driver()->canDelete($value)) {
224
                $this->delayedFire(new CacheKeyForgotten($this->driver, $value));
225
            }
226
227
            if ($result === false) {
228
                $this->flushDelayedEvents(false);
229
                return false;
230
            }
231
        }
232
233
        $this->flushDelayedEvents();
234
235
        return true;
236
    }
237
238
    /**
239
     * @param Event $event
240
     *
241
     * @return self
242
     */
243
    protected function fire(Event $event): self
244
    {
245
        $this->events->fire($event);
246
247
        return $this;
248
    }
249
250
    /**
251
     * @param bool $fire
252
     *
253
     * @return self
254
     */
255
    protected function flushDelayedEvents(bool $fire = true): self
256
    {
257
        if ($fire) {
258
            array_map(function (Event $event) {
259
                $this->fire($event);
260
            }, $this->delayedEvents);
261
        }
262
263
        $this->delayedEvents = [];
264
265
        return $this;
266
    }
267
268
    /**
269
     * @param Event $event
270
     *
271
     * @return $this
272
     */
273
    protected function delayedFire(Event $event): self
274
    {
275
        $this->delayedEvents[] = $event;
276
277
        return $this;
278
    }
279
}
280