Driver   B
last analyzed

Complexity

Total Complexity 36

Size/Duplication

Total Lines 296
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 296
rs 8.8
c 1
b 0
f 0
wmc 36

13 Methods

Rating   Name   Duplication   Size   Complexity  
A delete() 0 10 3
A filterValidateKey() 0 6 2
A set() 0 14 4
A deleteStorage() 0 6 2
A setMultiple() 0 12 4
A has() 0 11 3
A saveDataToStorage() 0 3 1
A clear() 0 3 1
A deleteMultiple() 0 12 4
A getDataFromStorage() 0 12 3
A getMultiple() 0 10 3
A __construct() 0 14 1
B get() 0 13 5
1
<?php
2
/**
3
 * @package Infobiotech\JsonCache
4
 * @version v1.0.0-alpha
5
 * @author Alessandro Raffa, Infobiotech S.r.l. <[email protected]>
6
 * @copyright (c) 2014-2017, Infobiotech S.r.l.
7
 * @license http://mit-license.org/
8
 * @uses league/flysystem
9
 * @uses psr/simple-cache
10
 */
11
12
namespace Infobiotech\JsonCache\Psr16;
13
14
/*
15
 *
16
 */
17
18
/** SPL use block. */
19
use DateInterval;
20
/** PSR-16 use block. */
21
use Psr\SimpleCache\CacheInterface;
22
/** Third-party use block. */
23
use League\Flysystem\Filesystem;
24
use League\Flysystem\AdapterInterface as FlysystemAdapter;
25
use Infobiotech\JsonCache\Psr16\InvalidArgumentException as CacheInvalidArgumentException;
26
27
/**
28
 * A key-value JSON-based PSR-16 cache implementation.
29
 *
30
 * @author Alessandro Raffa, Infobiotech S.r.l. <[email protected]>
31
 */
32
class Driver implements CacheInterface
33
{
34
    /*
35
     *
36
     */
37
    const FILED_VALUE      = 'value';
38
    const FILED_EXPIRATION = 'expiration';
39
    /*
40
     *
41
     */
42
    const DEFAULT_TTL      = 1200;
43
44
    /**
45
     *
46
     * @var \League\Flysystem\Filesystem
47
     */
48
    protected $filesystem;
49
50
    /**
51
     *
52
     * @var string
53
     */
54
    protected $namespace;
55
56
    /**
57
     *
58
     * @param FlysystemAdapter $filesystemAdapter
59
     * @param string $namespace
60
     * @return Driver
61
     */
62
    public function __construct(FlysystemAdapter $filesystemAdapter, $namespace)
63
    {
64
        /*
65
         *
66
         */
67
        $this->filesystem = new Filesystem($filesystemAdapter);
68
        /*
69
         *
70
         */
71
        $this->namespace  = $namespace.'.json';
72
        /*
73
         *
74
         */
75
        return $this;
76
    }
77
78
    /**
79
     * Fetches a value from the cache.
80
     *
81
     * @param string $key     The unique key of this item in the cache.
82
     * @param mixed  $default Default value to return if the key does not exist.
83
     *
84
     * @return mixed The value of the item from the cache, or $default in case of cache miss.
85
     *
86
     * @throws CacheInvalidArgumentException
87
     *   MUST be thrown if the $key string is not a legal value.
88
     *
89
     * @todo Implement better $key validation and filtering
90
     */
91
    public function get($key, $default = null)
92
    {
93
        $value = $default;
94
        if (!is_string($this->filterValidateKey($key))) {
95
            throw new CacheInvalidArgumentException('');
96
        }
97
        $data = $this->getDataFromStorage();
98
        if (isset($data[$key]) && isset($data[$key][self::FILED_EXPIRATION])) {
99
            if ($data[$key][self::FILED_EXPIRATION] > microtime(true)) {
100
                $value = $data[$key][self::FILED_VALUE];
101
            }
102
        }
103
        return $value;
104
    }
105
106
    /**
107
     * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
108
     *
109
     * @param string                $key   The key of the item to store.
110
     * @param mixed                 $value The value of the item to store, must be serializable.
111
     * @param null|int|DateInterval $ttl   Optional. The TTL value of this item. If no value is sent and
112
     *                                     the driver supports TTL then the library may set a default value
113
     *                                     for it or let the driver take care of that.
114
     *
115
     * @return bool True on success and false on failure.
116
     *
117
     * @throws CacheInvalidArgumentException
118
     *   MUST be thrown if the $key string is not a legal value.
119
     *
120
     * @todo Implement better $key validation and filtering
121
     */
122
    public function set($key, $value, $ttl = null)
123
    {
124
        if (!is_string($this->filterValidateKey($key))) {
125
            throw new CacheInvalidArgumentException('');
126
        }
127
        if (empty($ttl) || !is_numeric($ttl)) {
128
            $ttl = self::DEFAULT_TTL;
129
        }
130
        $data       = $this->getDataFromStorage();
131
        $data[$key] = [
132
            self::FILED_VALUE      => $value,
133
            self::FILED_EXPIRATION => microtime(true) + (float) $ttl,
134
        ];
135
        return $this->saveDataToStorage($data);
136
    }
137
138
    /**
139
     * Delete an item from the cache by its unique key.
140
     *
141
     * @param string $key The unique cache key of the item to delete.
142
     *
143
     * @return bool True if the item was successfully removed. False if there was an error.
144
     *
145
     * @throws CacheInvalidArgumentException
146
     *   MUST be thrown if the $key string is not a legal value.
147
     */
148
    public function delete($key)
149
    {
150
        if (!is_string($this->filterValidateKey($key))) {
151
            throw new CacheInvalidArgumentException('');
152
        }
153
        $data = $this->getDataFromStorage();
154
        if (isset($data[$key])) {
155
            unset($data[$key]);
156
        }
157
        return $this->saveDataToStorage($data);
158
    }
159
160
    /**
161
     * Wipes clean the entire cache's keys.
162
     *
163
     * @return bool True on success and false on failure.
164
     */
165
    public function clear()
166
    {
167
        return $this->deleteStorage();
168
    }
169
170
    /**
171
     * Obtains multiple cache items by their unique keys.
172
     *
173
     * @param iterable $keys    A list of keys that can obtained in a single operation.
174
     * @param mixed    $default Default value to return for keys that do not exist.
175
     *
176
     * @return iterable A list of key => value pairs.
177
     *      Cache keys that do not exist or are stale will have $default as value.
178
     *
179
     * @throws CacheInvalidArgumentException
180
     *      MUST be thrown if $keys is neither an array nor a Traversable,
181
     *      or if any of the $keys are not a legal value.
182
     */
183
    public function getMultiple($keys, $default = null)
184
    {
185
        if (!is_array($keys)) {
186
            throw new CacheInvalidArgumentException('');
187
        }
188
        $values = [];
189
        foreach ($keys as $key) {
190
            $values[$key] = $this->get($key, $default);
191
        }
192
        return $values;
193
    }
194
195
    /**
196
     * Persists a set of key => value pairs in the cache, with an optional TTL.
197
     *
198
     * @param iterable              $values A list of key => value pairs for a multiple-set operation.
199
     * @param null|int|DateInterval $ttl    Optional. The TTL value of this item. If no value is sent and
200
     *                                      the driver supports TTL then the library may set a default value
201
     *                                      for it or let the driver take care of that.
202
     *
203
     * @return bool True on success and false on failure.
204
     *
205
     * @throws CacheInvalidArgumentException
206
     *   MUST be thrown if $values is neither an array nor a Traversable,
207
     *   or if any of the $values are not a legal value.
208
     */
209
    public function setMultiple($values, $ttl = null)
210
    {
211
        $failure = false;
212
        if (!is_array($values)) {
213
            throw new CacheInvalidArgumentException('');
214
        }
215
        foreach ($values as $key => $value) {
216
            if (!$this->set($key, $value, $ttl)) {
217
                $failure = true;
218
            }
219
        }
220
        return (bool) !$failure;
221
    }
222
223
    /**
224
     * Deletes multiple cache items in a single operation.
225
     *
226
     * @param iterable $keys A list of string-based keys to be deleted.
227
     *
228
     * @return bool True if the items were successfully removed. False if there was an error.
229
     *
230
     * @throws CacheInvalidArgumentException
231
     *   MUST be thrown if $keys is neither an array nor a Traversable,
232
     *   or if any of the $keys are not a legal value.
233
     */
234
    public function deleteMultiple($keys)
235
    {
236
        $failure = false;
237
        if (!is_array($keys)) {
238
            throw new CacheInvalidArgumentException('');
239
        }
240
        foreach ($keys as $key) {
241
            if (!$this->delete($key)) {
242
                $failure = true;
243
            }
244
        }
245
        return (bool) !$failure;
246
    }
247
248
    /**
249
     * Determines whether an item is present in the cache.
250
     *
251
     * NOTE: It is recommended that has() is only to be used for cache warming type purposes
252
     * and not to be used within your live applications operations for get/set, as this method
253
     * is subject to a race condition where your has() will return true and immediately after,
254
     * another script can remove it making the state of your app out of date.
255
     *
256
     * @param string $key The cache item key.
257
     *
258
     * @return bool
259
     *
260
     * @throws CacheInvalidArgumentException
261
     *   MUST be thrown if the $key string is not a legal value.
262
     */
263
    public function has($key)
264
    {
265
        $has = false;
266
        if (!is_string($this->filterValidateKey($key))) {
267
            throw new CacheInvalidArgumentException('');
268
        }
269
        $data = $this->getDataFromStorage();
270
        if (isset($data[$key])) {
271
            $has = true;
272
        }
273
        return $has;
274
    }
275
276
    /**
277
     *
278
     * @return array
279
     */
280
    protected function getDataFromStorage()
281
    {
282
        $dataArrayFromStorage = [];
283
        if (!$this->filesystem->has($this->namespace)) {
284
            $this->filesystem->write($this->namespace, json_encode($dataArrayFromStorage));
285
        }
286
        $rawDataFromStorage = $this->filesystem->read($this->namespace);
287
        if ($rawDataFromStorage !== false) {
288
            $dataArrayFromStorage = json_decode($rawDataFromStorage, true);
289
        }
290
        unset($rawDataFromStorage);
291
        return $dataArrayFromStorage;
292
    }
293
294
    /**
295
     *
296
     * @param array $data
297
     * @return boolean
298
     */
299
    protected function saveDataToStorage($data)
300
    {
301
        return (bool) $this->filesystem->put($this->namespace, json_encode($data));
302
    }
303
304
    /**
305
     *
306
     * @param array $data
307
     * @return boolean
308
     */
309
    protected function deleteStorage()
310
    {
311
        if ($this->filesystem->has($this->namespace)) {
312
            return (bool) $this->filesystem->delete($this->namespace);
313
        }
314
        return true;
315
    }
316
317
    /**
318
     *
319
     * @param string $key
320
     * @return string|boolean
321
     */
322
    protected function filterValidateKey($key)
323
    {
324
        if (!is_string($key)) {
325
            return false;
326
        }
327
        return $key;
328
    }
329
}
330