Completed
Pull Request — master (#16)
by Naoki
19:11
created

AbstractCache::setFromStorage()   A

Complexity

Conditions 4
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4.0312

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
ccs 7
cts 8
cp 0.875
rs 9.2
cc 4
eloc 5
nc 2
nop 1
crap 4.0312
1
<?php
2
3
namespace League\Flysystem\Cached\Storage;
4
5
use League\Flysystem\Cached\CacheInterface;
6
use League\Flysystem\Util;
7
8
abstract class AbstractCache implements CacheInterface
9
{
10
    /**
11
     * @var bool
12
     */
13
    protected $autosave = true;
14
15
    /**
16
     * @var array
17
     */
18
    protected $cache = [];
19
20
    /**
21
     * @var array
22
     */
23
    protected $complete = [];
24
25
    /**
26
     * Destructor.
27
     */
28 138
    public function __destruct()
29
    {
30 138
        if (! $this->autosave) {
31 6
            $this->save();
32 6
        }
33 138
    }
34
35
    /**
36
     * Get the autosave setting.
37
     *
38
     * @return bool autosave
39
     */
40 3
    public function getAutosave()
41
    {
42 3
        return $this->autosave;
43
    }
44
45
    /**
46
     * Get the autosave setting.
47
     *
48
     * @param bool $autosave
49
     */
50 3
    public function setAutosave($autosave)
51
    {
52 3
        $this->autosave = $autosave;
53 3
    }
54
55
    /**
56
     * Store the contents listing.
57
     *
58
     * @param string $directory
59
     * @param array  $contents
60
     * @param bool   $recursive
61
     *
62
     * @return array contents listing
63
     */
64 12
    public function storeContents($directory, array $contents, $recursive = false)
65
    {
66 12
        $directories = [$directory];
67
68 12
        foreach ($contents as $index => $object) {
69 12
            $this->updateObject($object['path'], $object);
70 12
            $object = $this->cache[$object['path']];
71
72 12
            if ($recursive && (empty($directory) || strpos($object['dirname'], $directory) !== false)) {
73 6
                $directories[] = $object['dirname'];
74 6
            }
75 12
        }
76
77 12
        foreach ($directories as $directory) {
78 12
            $this->setComplete($directory, $recursive);
79 12
        }
80
81 12
        $this->autosave();
82 12
    }
83
84
    /**
85
     * Update the metadata for an object.
86
     *
87
     * @param string $path     object path
88
     * @param array  $object   object metadata
89
     * @param bool   $autosave whether to trigger the autosave routine
90
     */
91 42
    public function updateObject($path, array $object, $autosave = false)
92
    {
93 42
        if (! $this->has($path)) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->has($path) of type boolean|null is loosely compared to false; this is ambiguous if the boolean can be false. You might want to explicitly use !== null instead.

If an expression can have both false, and null as possible values. It is generally a good practice to always use strict comparison to clearly distinguish between those two values.

$a = canBeFalseAndNull();

// Instead of
if ( ! $a) { }

// Better use one of the explicit versions:
if ($a !== null) { }
if ($a !== false) { }
if ($a !== null && $a !== false) { }
Loading history...
94 42
            $this->cache[$path] = Util::pathinfo($path);
95 42
        }
96
97 42
        $this->cache[$path] = array_merge($this->cache[$path], $object);
98
99 42
        if ($autosave) {
100 18
            $this->autosave();
101 18
        }
102
103 42
        $this->ensureParentDirectories($path);
104 42
    }
105
106
    /**
107
     * Store object hit miss.
108
     *
109
     * @param string $path
110
     */
111 6
    public function storeMiss($path)
112
    {
113 6
        $this->cache[$path] = false;
114 6
        $this->autosave();
115 6
    }
116
117
    /**
118
     * Get the contents listing.
119
     *
120
     * @param string $dirname
121
     * @param bool   $recursive
122
     *
123
     * @return array contents listing
124
     */
125 6
    public function listContents($dirname = '', $recursive = false)
126
    {
127 6
        $result = [];
128
129 6
        foreach ($this->cache as $object) {
130 6
            if ($object['dirname'] !== $dirname) {
131 3
                continue;
132
            }
133
134 6
            $result[] = $object;
135
136 6
            if ($recursive && $object['type'] === 'dir') {
137 3
                $result = array_merge($result, $this->listContents($object['path'], true));
138 3
            }
139 6
        }
140
141 6
        return $result;
142
    }
143
144
    /**
145
     * {@inheritdoc}
146
     */
147 54
    public function has($path)
148
    {
149 54
        if (array_key_exists($path, $this->cache)) {
150 18
            return $this->cache[$path] !== false;
151
        }
152
153 48
        if ($this->isComplete(Util::dirname($path), false)) {
154 3
            return false;
155
        }
156 45
    }
157
158
    /**
159
     * {@inheritdoc}
160
     */
161 9
    public function read($path)
162
    {
163 9
        if (isset($this->cache[$path]['contents'])) {
164 6
            return $this->cache[$path];
165
        }
166
167 6
        return false;
168
    }
169
170
    /**
171
     * {@inheritdoc}
172
     */
173 3
    public function readStream($path)
174
    {
175 3
        return false;
176
    }
177
178
    /**
179
     * {@inheritdoc}
180
     */
181 3
    public function rename($path, $newpath)
182
    {
183 3
        if ($this->has($path)) {
184 3
            $object = $this->cache[$path];
185 3
            unset($this->cache[$path]);
186 3
            $object['path'] = $newpath;
187 3
            $object = array_merge($object, Util::pathinfo($newpath));
188 3
            $this->cache[$newpath] = $object;
189 3
            $this->autosave();
190 3
        }
191 3
    }
192
193
    /**
194
     * {@inheritdoc}
195
     */
196 6
    public function copy($path, $newpath)
197
    {
198 6
        if ($this->has($path)) {
199 3
            $object = $this->cache[$path];
200 3
            $object = array_merge($object, Util::pathinfo($newpath));
201 3
            $this->updateObject($newpath, $object, true);
202 3
        }
203 6
    }
204
205
    /**
206
     * {@inheritdoc}
207
     */
208 3
    public function delete($path)
209
    {
210 3
        $this->storeMiss($path);
211 3
    }
212
213
    /**
214
     * {@inheritdoc}
215
     */
216 3
    public function deleteDir($dirname)
217
    {
218 3
        foreach ($this->cache as $path => $object) {
219 3
            if (strpos($path, $dirname) === 0) {
220 3
                unset($this->cache[$path]);
221 3
            }
222 3
        }
223
224 3
        if (isset($this->complete[$dirname])) {
225 3
            unset($this->complete[$dirname]);
226 3
        }
227
228 3
        $this->autosave();
229 3
    }
230
231
    /**
232
     * {@inheritdoc}
233
     */
234 6
    public function getMimetype($path)
235
    {
236 6
        if (isset($this->cache[$path]['mimetype'])) {
237 3
            return $this->cache[$path];
238
        }
239
240 6
        if (! $result = $this->read($path)) {
241 3
            return false;
242
        }
243
244 3
        $mimetype = Util::guessMimeType($path, $result['contents']);
245 3
        $this->cache[$path]['mimetype'] = $mimetype;
246
247 3
        return $this->cache[$path];
248
    }
249
250
    /**
251
     * {@inheritdoc}
252
     */
253 3
    public function getSize($path)
254
    {
255 3
        if (isset($this->cache[$path]['size'])) {
256 3
            return $this->cache[$path];
257
        }
258
259 3
        return false;
260
    }
261
262
    /**
263
     * {@inheritdoc}
264
     */
265 3
    public function getTimestamp($path)
266
    {
267 3
        if (isset($this->cache[$path]['timestamp'])) {
268 3
            return $this->cache[$path];
269
        }
270
271 3
        return false;
272
    }
273
274
    /**
275
     * {@inheritdoc}
276
     */
277 3
    public function getVisibility($path)
278
    {
279 3
        if (isset($this->cache[$path]['visibility'])) {
280 3
            return $this->cache[$path];
281
        }
282
283 3
        return false;
284
    }
285
286
    /**
287
     * {@inheritdoc}
288
     */
289 18
    public function getMetadata($path)
290
    {
291 18
        if (isset($this->cache[$path]['type'])) {
292 15
            return $this->cache[$path];
293
        }
294
295 3
        return false;
296
    }
297
298
    /**
299
     * {@inheritdoc}
300
     */
301 93
    public function isComplete($dirname, $recursive)
302
    {
303 93
        if (! array_key_exists($dirname, $this->complete)) {
304 69
            return false;
305
        }
306
307 30
        if ($recursive && $this->complete[$dirname] !== 'recursive') {
308 3
            return false;
309
        }
310
311 30
        return true;
312
    }
313
314
    /**
315
     * {@inheritdoc}
316
     */
317 21
    public function setComplete($dirname, $recursive)
318
    {
319 21
        $this->complete[$dirname] = $recursive ? 'recursive' : true;
320 21
    }
321
322
    /**
323
     * Filter the contents from a listing.
324
     *
325
     * @param array $contents object listing
326
     *
327
     * @return array filtered contents
328
     */
329 33
    public function cleanContents(array $contents)
330
    {
331 33
        $cachedProperties = array_flip([
332 33
            'path', 'dirname', 'basename', 'extension', 'filename',
333 33
            'size', 'mimetype', 'visibility', 'timestamp', 'type',
334 33
        ]);
335
336 33
        foreach ($contents as $path => $object) {
337 6
            if (is_array($object)) {
338 6
                $contents[$path] = array_intersect_key($object, $cachedProperties);
339 6
            }
340 33
        }
341
342 33
        return $contents;
343
    }
344
345
    /**
346
     * {@inheritdoc}
347
     */
348 3
    public function flush()
349
    {
350 3
        $this->cache = [];
351 3
        $this->complete = [];
352 3
        $this->autosave();
353 3
    }
354
355
    /**
356
     * {@inheritdoc}
357
     */
358 42
    public function autosave()
359
    {
360 42
        if ($this->autosave) {
361 42
            $this->save();
362 42
        }
363 42
    }
364
365
    /**
366
     * Retrieve serialized cache data.
367
     *
368
     * @return string serialized data
369
     */
370 24
    public function getForStorage()
371
    {
372 24
        $cleaned = $this->cleanContents($this->cache);
373
374 24
        return json_encode([$cleaned, $this->complete]);
375
    }
376
377
    /**
378
     * Load from serialized cache data.
379
     *
380
     * @param string $json
381
     */
382 18
    public function setFromStorage($json)
383
    {
384 18
        list($cache, $complete) = json_decode($json, true);
385
386 18
        if (json_last_error() === JSON_ERROR_NONE && is_array($cache) && is_array($complete)) {
387 18
            $this->cache = $cache;
388 18
            $this->complete = $complete;
389 18
        }
390 18
    }
391
392
    /**
393
     * Ensure parent directories of an object.
394
     *
395
     * @param string $path object path
396
     */
397 42
    public function ensureParentDirectories($path)
398
    {
399 42
        $object = $this->cache[$path];
400
401 42
        while ($object['dirname'] !== '' && ! isset($this->cache[$object['dirname']])) {
402 9
            $object = Util::pathinfo($object['dirname']);
403 9
            $object['type'] = 'dir';
404 9
            $this->cache[$object['path']] = $object;
405 9
        }
406 42
    }
407
408
    /**
409
     * Call any method for plugin features.
410
     *
411
     * @param array $arguments [ $path ]
412
     *
413
     * @return array|false
414
     */
415
    public function __call($method, $arguments)
416
    {
417
        $path = $arguments[0];
418
        if (isset($this->cache[$path][$method])) {
419
            return $this->cache[$path];
420
        }
421
422
        return false;
423
    }
424
}
425