Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
namespace Doctrine\Common\Cache\Psr6;
4
 
5
use Doctrine\Common\Cache\Cache;
6
use Doctrine\Common\Cache\ClearableCache;
7
use Doctrine\Common\Cache\MultiDeleteCache;
8
use Doctrine\Common\Cache\MultiGetCache;
9
use Doctrine\Common\Cache\MultiPutCache;
10
use Psr\Cache\CacheItemInterface;
11
use Psr\Cache\CacheItemPoolInterface;
12
use Symfony\Component\Cache\DoctrineProvider as SymfonyDoctrineProvider;
13
 
14
use function array_key_exists;
15
use function assert;
16
use function count;
17
use function current;
18
use function get_class;
19
use function gettype;
20
use function is_object;
21
use function is_string;
22
use function microtime;
23
use function sprintf;
24
use function strpbrk;
25
 
26
use const PHP_VERSION_ID;
27
 
28
final class CacheAdapter implements CacheItemPoolInterface
29
{
30
    private const RESERVED_CHARACTERS = '{}()/\@:';
31
 
32
    /** @var Cache */
33
    private $cache;
34
 
35
    /** @var array<CacheItem|TypedCacheItem> */
36
    private $deferredItems = [];
37
 
38
    public static function wrap(Cache $cache): CacheItemPoolInterface
39
    {
40
        if ($cache instanceof DoctrineProvider && ! $cache->getNamespace()) {
41
            return $cache->getPool();
42
        }
43
 
44
        if ($cache instanceof SymfonyDoctrineProvider && ! $cache->getNamespace()) {
45
            $getPool = function () {
46
                // phpcs:ignore Squiz.Scope.StaticThisUsage.Found
47
                return $this->pool;
48
            };
49
 
50
            return $getPool->bindTo($cache, SymfonyDoctrineProvider::class)();
51
        }
52
 
53
        return new self($cache);
54
    }
55
 
56
    private function __construct(Cache $cache)
57
    {
58
        $this->cache = $cache;
59
    }
60
 
61
    /** @internal */
62
    public function getCache(): Cache
63
    {
64
        return $this->cache;
65
    }
66
 
67
    /**
68
     * {@inheritDoc}
69
     */
70
    public function getItem($key): CacheItemInterface
71
    {
72
        assert(self::validKey($key));
73
 
74
        if (isset($this->deferredItems[$key])) {
75
            $this->commit();
76
        }
77
 
78
        $value = $this->cache->fetch($key);
79
 
80
        if (PHP_VERSION_ID >= 80000) {
81
            if ($value !== false) {
82
                return new TypedCacheItem($key, $value, true);
83
            }
84
 
85
            return new TypedCacheItem($key, null, false);
86
        }
87
 
88
        if ($value !== false) {
89
            return new CacheItem($key, $value, true);
90
        }
91
 
92
        return new CacheItem($key, null, false);
93
    }
94
 
95
    /**
96
     * {@inheritDoc}
97
     */
98
    public function getItems(array $keys = []): array
99
    {
100
        if ($this->deferredItems) {
101
            $this->commit();
102
        }
103
 
104
        assert(self::validKeys($keys));
105
 
106
        $values = $this->doFetchMultiple($keys);
107
        $items  = [];
108
 
109
        if (PHP_VERSION_ID >= 80000) {
110
            foreach ($keys as $key) {
111
                if (array_key_exists($key, $values)) {
112
                    $items[$key] = new TypedCacheItem($key, $values[$key], true);
113
                } else {
114
                    $items[$key] = new TypedCacheItem($key, null, false);
115
                }
116
            }
117
 
118
            return $items;
119
        }
120
 
121
        foreach ($keys as $key) {
122
            if (array_key_exists($key, $values)) {
123
                $items[$key] = new CacheItem($key, $values[$key], true);
124
            } else {
125
                $items[$key] = new CacheItem($key, null, false);
126
            }
127
        }
128
 
129
        return $items;
130
    }
131
 
132
    /**
133
     * {@inheritDoc}
134
     */
135
    public function hasItem($key): bool
136
    {
137
        assert(self::validKey($key));
138
 
139
        if (isset($this->deferredItems[$key])) {
140
            $this->commit();
141
        }
142
 
143
        return $this->cache->contains($key);
144
    }
145
 
146
    public function clear(): bool
147
    {
148
        $this->deferredItems = [];
149
 
150
        if (! $this->cache instanceof ClearableCache) {
151
            return false;
152
        }
153
 
154
        return $this->cache->deleteAll();
155
    }
156
 
157
    /**
158
     * {@inheritDoc}
159
     */
160
    public function deleteItem($key): bool
161
    {
162
        assert(self::validKey($key));
163
        unset($this->deferredItems[$key]);
164
 
165
        return $this->cache->delete($key);
166
    }
167
 
168
    /**
169
     * {@inheritDoc}
170
     */
171
    public function deleteItems(array $keys): bool
172
    {
173
        foreach ($keys as $key) {
174
            assert(self::validKey($key));
175
            unset($this->deferredItems[$key]);
176
        }
177
 
178
        return $this->doDeleteMultiple($keys);
179
    }
180
 
181
    public function save(CacheItemInterface $item): bool
182
    {
183
        return $this->saveDeferred($item) && $this->commit();
184
    }
185
 
186
    public function saveDeferred(CacheItemInterface $item): bool
187
    {
188
        if (! $item instanceof CacheItem && ! $item instanceof TypedCacheItem) {
189
            return false;
190
        }
191
 
192
        $this->deferredItems[$item->getKey()] = $item;
193
 
194
        return true;
195
    }
196
 
197
    public function commit(): bool
198
    {
199
        if (! $this->deferredItems) {
200
            return true;
201
        }
202
 
203
        $now         = microtime(true);
204
        $itemsCount  = 0;
205
        $byLifetime  = [];
206
        $expiredKeys = [];
207
 
208
        foreach ($this->deferredItems as $key => $item) {
209
            $lifetime = ($item->getExpiry() ?? $now) - $now;
210
 
211
            if ($lifetime < 0) {
212
                $expiredKeys[] = $key;
213
 
214
                continue;
215
            }
216
 
217
            ++$itemsCount;
218
            $byLifetime[(int) $lifetime][$key] = $item->get();
219
        }
220
 
221
        $this->deferredItems = [];
222
 
223
        switch (count($expiredKeys)) {
224
            case 0:
225
                break;
226
            case 1:
227
                $this->cache->delete(current($expiredKeys));
228
                break;
229
            default:
230
                $this->doDeleteMultiple($expiredKeys);
231
                break;
232
        }
233
 
234
        if ($itemsCount === 1) {
235
            return $this->cache->save($key, $item->get(), (int) $lifetime);
236
        }
237
 
238
        $success = true;
239
        foreach ($byLifetime as $lifetime => $values) {
240
            $success = $this->doSaveMultiple($values, $lifetime) && $success;
241
        }
242
 
243
        return $success;
244
    }
245
 
246
    public function __destruct()
247
    {
248
        $this->commit();
249
    }
250
 
251
    /**
252
     * @param mixed $key
253
     */
254
    private static function validKey($key): bool
255
    {
256
        if (! is_string($key)) {
257
            throw new InvalidArgument(sprintf('Cache key must be string, "%s" given.', is_object($key) ? get_class($key) : gettype($key)));
258
        }
259
 
260
        if ($key === '') {
261
            throw new InvalidArgument('Cache key length must be greater than zero.');
262
        }
263
 
264
        if (strpbrk($key, self::RESERVED_CHARACTERS) !== false) {
265
            throw new InvalidArgument(sprintf('Cache key "%s" contains reserved characters "%s".', $key, self::RESERVED_CHARACTERS));
266
        }
267
 
268
        return true;
269
    }
270
 
271
    /**
272
     * @param mixed[] $keys
273
     */
274
    private static function validKeys(array $keys): bool
275
    {
276
        foreach ($keys as $key) {
277
            self::validKey($key);
278
        }
279
 
280
        return true;
281
    }
282
 
283
    /**
284
     * @param mixed[] $keys
285
     */
286
    private function doDeleteMultiple(array $keys): bool
287
    {
288
        if ($this->cache instanceof MultiDeleteCache) {
289
            return $this->cache->deleteMultiple($keys);
290
        }
291
 
292
        $success = true;
293
        foreach ($keys as $key) {
294
            $success = $this->cache->delete($key) && $success;
295
        }
296
 
297
        return $success;
298
    }
299
 
300
    /**
301
     * @param mixed[] $keys
302
     *
303
     * @return mixed[]
304
     */
305
    private function doFetchMultiple(array $keys): array
306
    {
307
        if ($this->cache instanceof MultiGetCache) {
308
            return $this->cache->fetchMultiple($keys);
309
        }
310
 
311
        $values = [];
312
        foreach ($keys as $key) {
313
            $value = $this->cache->fetch($key);
314
            if (! $value) {
315
                continue;
316
            }
317
 
318
            $values[$key] = $value;
319
        }
320
 
321
        return $values;
322
    }
323
 
324
    /**
325
     * @param mixed[] $keysAndValues
326
     */
327
    private function doSaveMultiple(array $keysAndValues, int $lifetime = 0): bool
328
    {
329
        if ($this->cache instanceof MultiPutCache) {
330
            return $this->cache->saveMultiple($keysAndValues, $lifetime);
331
        }
332
 
333
        $success = true;
334
        foreach ($keysAndValues as $key => $value) {
335
            $success = $this->cache->save($key, $value, $lifetime) && $success;
336
        }
337
 
338
        return $success;
339
    }
340
}