AbstractCache::listContents()   A
last analyzed

Complexity

Conditions 6
Paths 5

Size

Total Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 6.1666

Importance

Changes 0
Metric Value
dl 0
loc 17
ccs 10
cts 12
cp 0.8333
rs 9.0777
c 0
b 0
f 0
cc 6
nc 5
nop 2
crap 6.1666
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 147
    public function __destruct()
29
    {
30 147
        if (! $this->autosave) {
31 6
            $this->save();
32 6
        }
33 147
    }
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 15
    public function storeContents($directory, array $contents, $recursive = false)
65
    {
66 15
        $directories = [$directory];
67
68 15
        foreach ($contents as $object) {
69 15
            $this->updateObject($object['path'], $object);
70 15
            $object = $this->cache[$object['path']];
71
72 15
            if ($recursive && $this->pathIsInDirectory($directory, $object['path'])) {
73 9
                $directories[] = $object['dirname'];
74 9
            }
75 15
        }
76
77 15
        foreach (array_unique($directories) as $directory) {
78 15
            $this->setComplete($directory, $recursive);
79 15
        }
80
81 15
        $this->autosave();
82 15
    }
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 48
    public function updateObject($path, array $object, $autosave = false)
92
    {
93 48
        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 48
            $this->cache[$path] = Util::pathinfo($path);
95 48
        }
96
97 48
        $this->cache[$path] = array_merge($this->cache[$path], $object);
98
99 48
        if ($autosave) {
100 21
            $this->autosave();
101 21
        }
102
103 48
        $this->ensureParentDirectories($path);
104 48
    }
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 9
    public function listContents($dirname = '', $recursive = false)
126
    {
127 9
        $result = [];
128
129 9
        foreach ($this->cache as $object) {
130 9
            if ($object === false) {
131 9
                continue;
132 9
            }
133 3
            if ($object['dirname'] === $dirname) {
134 3
                $result[] = $object;
135 9
            } elseif ($recursive && $this->pathIsInDirectory($dirname, $object['path'])) {
136
                $result[] = $object;
137 9
            }
138
        }
139
140
        return $result;
141
    }
142
143 60
    /**
144
     * {@inheritdoc}
145 60
     */
146 18
    public function has($path)
147
    {
148
        if ($path !== false && array_key_exists($path, $this->cache)) {
149 54
            return $this->cache[$path] !== false;
150 3
        }
151
152 51
        if ($this->isComplete(Util::dirname($path), false)) {
153
            return false;
154
        }
155
    }
156
157 12
    /**
158
     * {@inheritdoc}
159 12
     */
160 6
    public function read($path)
161
    {
162
        if (isset($this->cache[$path]['contents']) && $this->cache[$path]['contents'] !== false) {
163 9
            return $this->cache[$path];
164
        }
165
166
        return false;
167
    }
168
169 3
    /**
170
     * {@inheritdoc}
171 3
     */
172
    public function readStream($path)
173
    {
174
        return false;
175
    }
176
177 5
    /**
178
     * {@inheritdoc}
179 3
     */
180 3
    public function rename($path, $newpath)
181 3
    {
182 3
        if ($this->has($path)) {
183 3
            $object = $this->cache[$path];
184 3
            unset($this->cache[$path]);
185 5
            $object['path'] = $newpath;
186 3
            $object = array_merge($object, Util::pathinfo($newpath));
187 3
            $this->cache[$newpath] = $object;
188
            $this->autosave();
189
        }
190
    }
191
192 6
    /**
193
     * {@inheritdoc}
194 6
     */
195 3
    public function copy($path, $newpath)
196 3
    {
197 3
        if ($this->has($path)) {
198 3
            $object = $this->cache[$path];
199 6
            $object = array_merge($object, Util::pathinfo($newpath));
200
            $this->updateObject($newpath, $object, true);
201
        }
202
    }
203
204 3
    /**
205
     * {@inheritdoc}
206 3
     */
207 3
    public function delete($path)
208
    {
209
        $this->storeMiss($path);
210
    }
211
212 6
    /**
213
     * {@inheritdoc}
214 6
     */
215 6
    public function deleteDir($dirname)
216 6
    {
217 6
        foreach ($this->cache as $path => $object) {
218 6
            if ($this->pathIsInDirectory($dirname, $path) || $path === $dirname) {
219
                unset($this->cache[$path]);
220 6
            }
221
        }
222 6
223 6
        unset($this->complete[$dirname]);
224
225
        $this->autosave();
226
    }
227
228 6
    /**
229
     * {@inheritdoc}
230 6
     */
231 3
    public function getMimetype($path)
232
    {
233
        if (isset($this->cache[$path]['mimetype'])) {
234 6
            return $this->cache[$path];
235 3
        }
236
237
        if (! $result = $this->read($path)) {
238 3
            return false;
239 3
        }
240
241 3
        $mimetype = Util::guessMimeType($path, $result['contents']);
242
        $this->cache[$path]['mimetype'] = $mimetype;
243
244
        return $this->cache[$path];
245
    }
246
247 3
    /**
248
     * {@inheritdoc}
249 3
     */
250 3
    public function getSize($path)
251
    {
252
        if (isset($this->cache[$path]['size'])) {
253 3
            return $this->cache[$path];
254
        }
255
256
        return false;
257
    }
258
259 3
    /**
260
     * {@inheritdoc}
261 3
     */
262 3
    public function getTimestamp($path)
263
    {
264
        if (isset($this->cache[$path]['timestamp'])) {
265 3
            return $this->cache[$path];
266
        }
267
268
        return false;
269
    }
270
271 3
    /**
272
     * {@inheritdoc}
273 3
     */
274 3
    public function getVisibility($path)
275
    {
276
        if (isset($this->cache[$path]['visibility'])) {
277 3
            return $this->cache[$path];
278
        }
279
280
        return false;
281
    }
282
283 18
    /**
284
     * {@inheritdoc}
285 18
     */
286 15
    public function getMetadata($path)
287
    {
288
        if (isset($this->cache[$path]['type'])) {
289 3
            return $this->cache[$path];
290
        }
291
292
        return false;
293
    }
294
295 99
    /**
296
     * {@inheritdoc}
297 99
     */
298 75
    public function isComplete($dirname, $recursive)
299
    {
300
        if (! array_key_exists($dirname, $this->complete)) {
301 33
            return false;
302 3
        }
303
304
        if ($recursive && $this->complete[$dirname] !== 'recursive') {
305 33
            return false;
306
        }
307
308
        return true;
309
    }
310
311 24
    /**
312
     * {@inheritdoc}
313 24
     */
314 24
    public function setComplete($dirname, $recursive)
315
    {
316
        $this->complete[$dirname] = $recursive ? 'recursive' : true;
317
    }
318
319
    /**
320
     * Filter the contents from a listing.
321
     *
322
     * @param array $contents object listing
323 39
     *
324
     * @return array filtered contents
325 39
     */
326 39
    public function cleanContents(array $contents)
327 39
    {
328 39
        $cachedProperties = array_flip([
329
            'path', 'dirname', 'basename', 'extension', 'filename',
330 39
            'size', 'mimetype', 'visibility', 'timestamp', 'type',
331 12
            'md5',
332 12
        ]);
333 12
334 39
        foreach ($contents as $path => $object) {
335
            if (is_array($object)) {
336 39
                $contents[$path] = array_intersect_key($object, $cachedProperties);
337
            }
338
        }
339
340
        return $contents;
341
    }
342 3
343
    /**
344 3
     * {@inheritdoc}
345 3
     */
346 3
    public function flush()
347 3
    {
348
        $this->cache = [];
349
        $this->complete = [];
350
        $this->autosave();
351
    }
352 51
353
    /**
354 51
     * {@inheritdoc}
355 51
     */
356 51
    public function autosave()
357 51
    {
358
        if ($this->autosave) {
359
            $this->save();
360
        }
361
    }
362
363
    /**
364 24
     * Retrieve serialized cache data.
365
     *
366 24
     * @return string serialized data
367
     */
368 24
    public function getForStorage()
369
    {
370
        $cleaned = $this->cleanContents($this->cache);
371
372
        return json_encode([$cleaned, $this->complete]);
373
    }
374
375
    /**
376 18
     * Load from serialized cache data.
377
     *
378 18
     * @param string $json
379
     */
380 18
    public function setFromStorage($json)
381 18
    {
382 18
        list($cache, $complete) = json_decode($json, true);
383 18
384 18
        if (json_last_error() === JSON_ERROR_NONE && is_array($cache) && is_array($complete)) {
385
            $this->cache = $cache;
386
            $this->complete = $complete;
387
        }
388
    }
389
390
    /**
391 48
     * Ensure parent directories of an object.
392
     *
393 48
     * @param string $path object path
394
     */
395 48
    public function ensureParentDirectories($path)
396 12
    {
397 12
        $object = $this->cache[$path];
398 12
399 12
        while ($object['dirname'] !== '' && ! isset($this->cache[$object['dirname']])) {
400 48
            $object = Util::pathinfo($object['dirname']);
401
            $object['type'] = 'dir';
402
            $this->cache[$object['path']] = $object;
403
        }
404
    }
405
406
    /**
407
     * Determines if the path is inside the directory.
408
     *
409
     * @param string $directory
410 18
     * @param string $path
411
     *
412 18
     * @return bool
413
     */
414
    protected function pathIsInDirectory($directory, $path)
415
    {
416
        return $directory === '' || strpos($path, $directory . '/') === 0;
417
    }
418
}
419