Completed
Push — master ( f002f3...6be6c0 )
by Alessandro
01:49
created

Driver::set()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 9
nc 2
nop 3
dl 0
loc 14
rs 9.2
c 0
b 0
f 0
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
use Psr\SimpleCache\CacheInterface;
19
use League\Flysystem\Filesystem;
20
use League\Flysystem\AdapterInterface as FlysystemAdapter;
21
22
/**
23
 * A key-value JSON-based PSR-16 cache implementation.
24
 *
25
 * @author Alessandro Raffa, Infobiotech S.r.l. <[email protected]>
26
 */
27
class Driver implements CacheInterface
28
{
29
    /*
30
     *
31
     */
32
    const FILED_VALUE      = 'value';
33
    const FILED_EXPIRATION = 'expiration';
34
    /*
35
     *
36
     */
37
    const DEFAULT_TTL      = 1200;
38
39
    /**
40
     *
41
     * @var \League\Flysystem\Filesystem
42
     */
43
    protected $filesystem;
44
45
    /**
46
     *
47
     * @var string
48
     */
49
    protected $namespace;
50
51
    /**
52
     *
53
     * @param FlysystemAdapter $filesystemAdapter
54
     * @param string $namespace
55
     * @return JsonCache
0 ignored issues
show
Bug introduced by
The type Infobiotech\JsonCache\Psr16\JsonCache was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
56
     */
57
    public function __construct(FlysystemAdapter $filesystemAdapter, $namespace)
58
    {
59
        /*
60
         *
61
         */
62
        $this->filesystem = new Filesystem($filesystemAdapter);
63
        /*
64
         *
65
         */
66
        $this->namespace  = $namespace.'.json';
67
        /*
68
         *
69
         */
70
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type Infobiotech\JsonCache\Psr16\Driver which is incompatible with the documented return type Infobiotech\JsonCache\Psr16\JsonCache.
Loading history...
71
    }
72
73
    /**
74
     * Fetches a value from the cache.
75
     *
76
     * @param string $key     The unique key of this item in the cache.
77
     * @param mixed  $default Default value to return if the key does not exist.
78
     *
79
     * @return mixed The value of the item from the cache, or $default in case of cache miss.
80
     *
81
     * @throws \Psr\SimpleCache\InvalidArgumentException
82
     *   MUST be thrown if the $key string is not a legal value.
83
     *
84
     * @todo Implement better $key validation and filtering
85
     */
86
    public function get($key, $default = null)
87
    {
88
        $value = $default;
89
        if (!is_string($this->filterValidateKey($key))) {
90
            throw new \Psr\SimpleCache\InvalidArgumentException();
91
        }
92
        $data = $this->getDataFromStorage();
93
        if (isset($data[$key]) && isset($data[$key][self::FILED_EXPIRATION])) {
94
            if ($data[$key][self::FILED_EXPIRATION] > microtime(true)) {
95
                $value = $data[$key][self::FILED_VALUE];
96
            }
97
        }
98
        return $value;
99
    }
100
101
    /**
102
     * Persists data in the cache, uniquely referenced by a key with an optional expiration TTL time.
103
     *
104
     * @param string                $key   The key of the item to store.
105
     * @param mixed                 $value The value of the item to store, must be serializable.
106
     * @param null|int|DateInterval $ttl   Optional. The TTL value of this item. If no value is sent and
0 ignored issues
show
Bug introduced by
The type Infobiotech\JsonCache\Psr16\DateInterval was not found. Did you mean DateInterval? If so, make sure to prefix the type with \.
Loading history...
107
     *                                     the driver supports TTL then the library may set a default value
108
     *                                     for it or let the driver take care of that.
109
     *
110
     * @return bool True on success and false on failure.
111
     *
112
     * @throws \Psr\SimpleCache\InvalidArgumentException
113
     *   MUST be thrown if the $key string is not a legal value.
114
     *
115
     * @todo Implement better $key validation and filtering
116
     */
117
    public function set($key, $value, $ttl = null)
118
    {
119
        if (!is_string($this->filterValidateKey($key))) {
120
            throw new \Psr\SimpleCache\InvalidArgumentException();
121
        }
122
        if (empty($ttl) || !is_numeric($ttl)) {
123
            $ttl = self::DEFAULT_TTL;
124
        }
125
        $data       = $this->getDataFromStorage();
126
        $data[$key] = [
127
            self::FILED_VALUE      => $value,
128
            self::FILED_EXPIRATION => microtime(true) + (float) $ttl,
129
        ];
130
        return $this->saveDataToStorage($data);
131
    }
132
133
    /**
134
     * Delete an item from the cache by its unique key.
135
     *
136
     * @param string $key The unique cache key of the item to delete.
137
     *
138
     * @return bool True if the item was successfully removed. False if there was an error.
139
     *
140
     * @throws \Psr\SimpleCache\InvalidArgumentException
141
     *   MUST be thrown if the $key string is not a legal value.
142
     */
143
    public function delete($key)
144
    {
145
        if (!is_string($this->filterValidateKey($key))) {
146
            throw new \Psr\SimpleCache\InvalidArgumentException();
147
        }
148
        $data = $this->getDataFromStorage();
149
        if (isset($data[$key])) {
150
            unset($data[$key]);
151
        }
152
        return $this->saveDataToStorage($data);
153
    }
154
155
    /**
156
     * Wipes clean the entire cache's keys.
157
     *
158
     * @return bool True on success and false on failure.
159
     */
160
    public function clear()
161
    {
162
        return $this->deleteStorage();
163
    }
164
165
    /**
166
     * Obtains multiple cache items by their unique keys.
167
     *
168
     * @param iterable $keys    A list of keys that can obtained in a single operation.
169
     * @param mixed    $default Default value to return for keys that do not exist.
170
     *
171
     * @return iterable A list of key => value pairs.
172
     *      Cache keys that do not exist or are stale will have $default as value.
173
     *
174
     * @throws \Psr\SimpleCache\InvalidArgumentException
175
     *      MUST be thrown if $keys is neither an array nor a Traversable,
176
     *      or if any of the $keys are not a legal value.
177
     */
178
    public function getMultiple($keys, $default = null)
179
    {
180
        if (!is_array($keys)) {
181
            throw new \Psr\SimpleCache\InvalidArgumentException();
182
        }
183
        $values = [];
184
        foreach ($keys as $key) {
185
            $values[$key] = $this->get($key, $default);
186
        }
187
        return $values;
188
    }
189
190
    /**
191
     * Persists a set of key => value pairs in the cache, with an optional TTL.
192
     *
193
     * @param iterable              $values A list of key => value pairs for a multiple-set operation.
194
     * @param null|int|DateInterval $ttl    Optional. The TTL value of this item. If no value is sent and
195
     *                                      the driver supports TTL then the library may set a default value
196
     *                                      for it or let the driver take care of that.
197
     *
198
     * @return bool True on success and false on failure.
199
     *
200
     * @throws \Psr\SimpleCache\InvalidArgumentException
201
     *   MUST be thrown if $values is neither an array nor a Traversable,
202
     *   or if any of the $values are not a legal value.
203
     */
204
    public function setMultiple($values, $ttl = null)
205
    {
206
        $failure = false;
207
        if (!is_array($values)) {
208
            throw new \Psr\SimpleCache\InvalidArgumentException();
209
        }
210
        foreach ($values as $key => $value) {
211
            if (!$this->set($key, $value, $ttl)) {
212
                $failure = true;
213
            }
214
        }
215
        return (bool) !$failure;
216
    }
217
218
    /**
219
     * Deletes multiple cache items in a single operation.
220
     *
221
     * @param iterable $keys A list of string-based keys to be deleted.
222
     *
223
     * @return bool True if the items were successfully removed. False if there was an error.
224
     *
225
     * @throws \Psr\SimpleCache\InvalidArgumentException
226
     *   MUST be thrown if $keys is neither an array nor a Traversable,
227
     *   or if any of the $keys are not a legal value.
228
     */
229
    public function deleteMultiple($keys)
230
    {
231
        $failure = false;
232
        if (!is_array($keys)) {
233
            throw new \Psr\SimpleCache\InvalidArgumentException();
234
        }
235
        foreach ($keys as $key) {
236
            if (!$this->delete($key)) {
237
                $failure = true;
238
            }
239
        }
240
        return (bool) !$failure;
241
    }
242
243
    /**
244
     * Determines whether an item is present in the cache.
245
     *
246
     * NOTE: It is recommended that has() is only to be used for cache warming type purposes
247
     * and not to be used within your live applications operations for get/set, as this method
248
     * is subject to a race condition where your has() will return true and immediately after,
249
     * another script can remove it making the state of your app out of date.
250
     *
251
     * @param string $key The cache item key.
252
     *
253
     * @return bool
254
     *
255
     * @throws \Psr\SimpleCache\InvalidArgumentException
256
     *   MUST be thrown if the $key string is not a legal value.
257
     */
258
    public function has($key)
259
    {
260
        $has = false;
261
        if (!is_string($this->filterValidateKey($key))) {
262
            throw new \Psr\SimpleCache\InvalidArgumentException();
263
        }
264
        $data = $this->getDataFromStorage();
265
        if (isset($data[$key])) {
266
            $has = true;
267
        }
268
        return $has;
269
    }
270
271
    /**
272
     *
273
     * @return array
274
     */
275
    protected function getDataFromStorage()
276
    {
277
        if (!$this->filesystem->has($this->namespace)) {
278
            $this->filesystem->write($this->namespace, json_encode([]));
279
        }
280
        return json_decode($this->filesystem->read($this->namespace), true);
0 ignored issues
show
Bug introduced by
It seems like $this->filesystem->read($this->namespace) can also be of type false; however, parameter $json of json_decode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

280
        return json_decode(/** @scrutinizer ignore-type */ $this->filesystem->read($this->namespace), true);
Loading history...
281
    }
282
283
    /**
284
     *
285
     * @param array $data
286
     * @return boolean
287
     */
288
    protected function saveDataToStorage($data)
289
    {
290
        return (bool) $this->filesystem->put($this->namespace, json_encode($data));
291
    }
292
293
    /**
294
     *
295
     * @param array $data
296
     * @return boolean
297
     */
298
    protected function deleteStorage()
299
    {
300
        if ($this->filesystem->has($this->namespace)) {
301
            return (bool) $this->filesystem->delete($this->namespace);
302
        }
303
        return true;
304
    }
305
306
    /**
307
     *
308
     * @param string $key
309
     * @return string|boolean
310
     */
311
    protected function filterValidateKey($key)
312
    {
313
        if (!is_string($key)) {
314
            return false;
315
        }
316
        return $key;
317
    }
318
}
319