Completed
Pull Request — master (#27)
by Chris
17:52
created

AbstractCache::has()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 5.024

Importance

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