Completed
Pull Request — master (#38)
by Lito
33:32 queued 13:32
created

AbstractCache::getConfig()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 0
crap 2
1
<?php
2
3
namespace League\Flysystem\Cached\Storage;
4
5
use League\Flysystem\Cached\CacheInterface;
6
use League\Flysystem\Config;
7
use League\Flysystem\Util;
8
9
abstract class AbstractCache implements CacheInterface
10
{
11
    /**
12
     * @var bool
13
     */
14
    protected $autosave = true;
15
16
    /**
17
     * @var array
18
     */
19
    protected $cache = [];
20
21
    /**
22
     * @var array
23
     */
24
    protected $complete = [];
25
26
    /**
27
     * @var Config
28 147
     */
29
    protected $config;
30 147
31 6
    /**
32 6
     * Destructor.
33 147
     */
34
    public function __destruct()
35
    {
36
        if (! $this->autosave) {
37
            $this->save();
38
        }
39
    }
40 3
41
    /**
42 3
     * Get the config object or null.
43
     *
44
     * @return Config|null config
45
     */
46
    public function getConfig()
47
    {
48
        return $this->config;
49
    }
50 3
51
    /**
52 3
     * Set the config.
53 3
     *
54
     * @param Config|array|null $config
55
     */
56
    public function setConfig($config)
57
    {
58
        $this->config = Util::ensureConfig($config);
59
    }
60
61
    /**
62
     * Get the autosave setting.
63
     *
64 15
     * @return bool autosave
65
     */
66 15
    public function getAutosave()
67
    {
68 15
        return $this->autosave;
69 15
    }
70 15
71
    /**
72 15
     * Get the autosave setting.
73 9
     *
74 9
     * @param bool $autosave
75 15
     */
76
    public function setAutosave($autosave)
77 15
    {
78 15
        $this->autosave = $autosave;
79 15
    }
80
81 15
    /**
82 15
     * Store the contents listing.
83
     *
84
     * @param string $directory
85
     * @param array  $contents
86
     * @param bool   $recursive
87
     *
88
     * @return array contents listing
89
     */
90
    public function storeContents($directory, array $contents, $recursive = false)
91 48
    {
92
        $directories = [$directory];
93 48
94 48
        foreach ($contents as $object) {
95 48
            $this->updateObject($object['path'], $object);
96
97 48
            $object = $this->cache[$this->pathCase($object['path'])];
98
99 48
            if ($recursive && $this->pathIsInDirectory($directory, $object['path'])) {
100 21
                $directories[] = $object['dirname'];
101 21
            }
102
        }
103 48
104 48
        foreach (array_unique($directories) as $directory) {
105
            $this->setComplete($directory, $recursive);
106
        }
107
108
        $this->autosave();
109
    }
110
111 6
    /**
112
     * Update the metadata for an object.
113 6
     *
114 6
     * @param string $path     object path
115 6
     * @param array  $object   object metadata
116
     * @param bool   $autosave whether to trigger the autosave routine
117
     */
118
    public function updateObject($path, array $object, $autosave = false)
119
    {
120
        $key = $this->pathCase($path);
121
122
        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...
123
            $this->cache[$key] = Util::pathinfo($path);
124
        }
125 9
126
        $this->cache[$key] = array_merge($this->cache[$key], $object);
127 9
128
        if ($autosave) {
129 9
            $this->autosave();
130 9
        }
131 9
132 9
        $this->ensureParentDirectories($path);
133 3
    }
134 3
135 9
    /**
136
     * Store object hit miss.
137 9
     *
138
     * @param string $path
139
     */
140
    public function storeMiss($path)
141
    {
142
        $this->cache[$this->pathCase($path)] = false;
143 60
        $this->autosave();
144
    }
145 60
146 18
    /**
147
     * Get the contents listing.
148
     *
149 54
     * @param string $dirname
150 3
     * @param bool   $recursive
151
     *
152 51
     * @return array contents listing
153
     */
154
    public function listContents($dirname = '', $recursive = false)
155
    {
156
        $key = $this->pathCase($dirname);
157 12
        $result = [];
158
159 12
        foreach ($this->cache as $object) {
160 6
            if ($object === false) {
161
                continue;
162
            }
163 9
164
            if ($this->pathCase($object['dirname']) === $key) {
165
                $result[] = $object;
166
            } elseif ($recursive && $this->pathIsInDirectory($key, $object['path'])) {
167
                $result[] = $object;
168
            }
169 3
        }
170
171 3
        return $result;
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177 5
    public function has($path)
178
    {
179 3
        $key = $this->pathCase($path);
180 3
181 3
        if ($path !== false && array_key_exists($key, $this->cache)) {
182 3
            return $this->cache[$key] !== false;
183 3
        }
184 3
185 5
        if ($this->isComplete(Util::dirname($path), false)) {
186 3
            return false;
187 3
        }
188
    }
189
190
    /**
191
     * {@inheritdoc}
192 6
     */
193
    public function read($path)
194 6
    {
195 3
        $key = $this->pathCase($path);
196 3
197 3
        if (isset($this->cache[$key]['contents']) && $this->cache[$key]['contents'] !== false) {
198 3
            return $this->cache[$key];
199 6
        }
200
201
        return false;
202
    }
203
204 3
    /**
205
     * {@inheritdoc}
206 3
     */
207 3
    public function readStream($path)
208
    {
209
        return false;
210
    }
211
212 6
    /**
213
     * {@inheritdoc}
214 6
     */
215 6
    public function rename($path, $newpath)
216 6
    {
217 6
        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...
218 6
            return;
219
        }
220 6
221
        $key = $this->pathCase($path);
222 6
        $object = $this->cache[$key];
223 6
224
        unset($this->cache[$key]);
225
226
        $object['path'] = $newpath;
227
        $object = array_merge($object, Util::pathinfo($newpath));
228 6
229
        $this->cache[$this->pathCase($newpath)] = $object;
230 6
        $this->autosave();
231 3
    }
232
233
    /**
234 6
     * {@inheritdoc}
235 3
     */
236
    public function copy($path, $newpath)
237
    {
238 3
        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...
239 3
            return;
240
        }
241 3
242
        $object = $this->cache[$this->pathCase($path)];
243
        $object = array_merge($object, Util::pathinfo($newpath));
244
245
        $this->updateObject($newpath, $object, true);
246
    }
247 3
248
    /**
249 3
     * {@inheritdoc}
250 3
     */
251
    public function delete($path)
252
    {
253 3
        $this->storeMiss($path);
254
    }
255
256
    /**
257
     * {@inheritdoc}
258
     */
259 3
    public function deleteDir($dirname)
260
    {
261 3
        $dirname = $this->pathCase($dirname);
262 3
263
        foreach ($this->cache as $path => $object) {
264
            $key = $this->pathCase($path);
265 3
266
            if ($this->pathIsInDirectory($dirname, $path) || $key === $dirname) {
267
                unset($this->cache[$key]);
268
            }
269
        }
270
271 3
        unset($this->complete[$dirname]);
272
273 3
        $this->autosave();
274 3
    }
275
276
    /**
277 3
     * {@inheritdoc}
278
     */
279
    public function getMimetype($path)
280
    {
281
        $key = $this->pathCase($path);
282
283 18
        if (isset($this->cache[$key]['mimetype'])) {
284
            return $this->cache[$key];
285 18
        }
286 15
287
        if (! $result = $this->read($path)) {
288
            return false;
289 3
        }
290
291
        $this->cache[$key]['mimetype'] = Util::guessMimeType($path, $result['contents']);
292
293
        return $this->cache[$key];
294
    }
295 99
296
    /**
297 99
     * {@inheritdoc}
298 75
     */
299
    public function getSize($path)
300
    {
301 33
        $key = $this->pathCase($path);
302 3
303
        if (isset($this->cache[$key]['size'])) {
304
            return $this->cache[$key];
305 33
        }
306
307
        return false;
308
    }
309
310
    /**
311 24
     * {@inheritdoc}
312
     */
313 24
    public function getTimestamp($path)
314 24
    {
315
        $key = $this->pathCase($path);
316
317
        if (isset($this->cache[$key]['timestamp'])) {
318
            return $this->cache[$key];
319
        }
320
321
        return false;
322
    }
323 39
324
    /**
325 39
     * {@inheritdoc}
326 39
     */
327 39
    public function getVisibility($path)
328 39
    {
329
        $key = $this->pathCase($path);
330 39
331 12
        if (isset($this->cache[$key]['visibility'])) {
332 12
            return $this->cache[$key];
333 12
        }
334 39
335
        return false;
336 39
    }
337
338
    /**
339
     * {@inheritdoc}
340
     */
341
    public function getMetadata($path)
342 3
    {
343
        $key = $this->pathCase($path);
344 3
345 3
        if (isset($this->cache[$key]['type'])) {
346 3
            return $this->cache[$key];
347 3
        }
348
349
        return false;
350
    }
351
352 51
    /**
353
     * {@inheritdoc}
354 51
     */
355 51
    public function isComplete($dirname, $recursive)
356 51
    {
357 51
        $key = $this->pathCase($dirname);
358
359
        if (! array_key_exists($key, $this->complete)) {
360
            return false;
361
        }
362
363
        if ($recursive && $this->complete[$key] !== 'recursive') {
364 24
            return false;
365
        }
366 24
367
        return true;
368 24
    }
369
370
    /**
371
     * {@inheritdoc}
372
     */
373
    public function setComplete($dirname, $recursive)
374
    {
375
        $this->complete[$this->pathCase($dirname)] = $recursive ? 'recursive' : true;
376 18
    }
377
378 18
    /**
379
     * Filter the contents from a listing.
380 18
     *
381 18
     * @param array $contents object listing
382 18
     *
383 18
     * @return array filtered contents
384 18
     */
385
    public function cleanContents(array $contents)
386
    {
387
        $cachedProperties = array_flip([
388
            'path', 'dirname', 'basename', 'extension', 'filename',
389
            'size', 'mimetype', 'visibility', 'timestamp', 'type',
390
            'md5',
391 48
        ]);
392
393 48
        foreach ($contents as $path => $object) {
394
            if (is_array($object)) {
395 48
                $contents[$this->pathCase($path)] = array_intersect_key($object, $cachedProperties);
396 12
            }
397 12
        }
398 12
399 12
        return $contents;
400 48
    }
401
402
    /**
403
     * {@inheritdoc}
404
     */
405
    public function flush()
406
    {
407
        $this->cache = [];
408
        $this->complete = [];
409
        $this->autosave();
410 18
    }
411
412 18
    /**
413
     * {@inheritdoc}
414
     */
415
    public function autosave()
416
    {
417
        if ($this->autosave) {
418
            $this->save();
419
        }
420
    }
421
422
    /**
423
     * Retrieve serialized cache data.
424
     *
425
     * @return string serialized data
426
     */
427
    public function getForStorage()
428
    {
429
        $cleaned = $this->cleanContents($this->cache);
430
431
        return json_encode([$cleaned, $this->complete]);
432
    }
433
434
    /**
435
     * Load from serialized cache data.
436
     *
437
     * @param string $json
438
     */
439
    public function setFromStorage($json)
440
    {
441
        list($cache, $complete) = json_decode($json, true);
442
443
        if (json_last_error() === JSON_ERROR_NONE && is_array($cache) && is_array($complete)) {
444
            $this->cache = $cache;
445
            $this->complete = $complete;
446
        }
447
    }
448
449
    /**
450
     * Ensure parent directories of an object.
451
     *
452
     * @param string $path object path
453
     */
454
    public function ensureParentDirectories($path)
455
    {
456
        $object = $this->cache[$this->pathCase($path)];
457
458
        while ($object['dirname'] !== '' && ! isset($this->cache[$this->pathCase($object['dirname'])])) {
459
            $object = Util::pathinfo($object['dirname']);
460
            $object['type'] = 'dir';
461
            $this->cache[$this->pathCase($object['path'])] = $object;
462
        }
463
    }
464
465
    /**
466
     * Determines if the path is inside the directory.
467
     *
468
     * @param string $directory
469
     * @param string $path
470
     *
471
     * @return bool
472
     */
473
    protected function pathIsInDirectory($directory, $path)
474
    {
475
        return $directory === '' || strpos($this->pathCase($path), $this->pathCase($directory) . '/') === 0;
476
    }
477
478
    /**
479
     * Return the path string checking case_sensitive config value
480
     *
481
     * @param string $path
482
     *
483
     * @return string
484
     */
485
    protected function pathCase($path)
486
    {
487
        if ($this->config && $this->config->get('case_sensitive', true) === false) {
488
            $path = strtolower($path);
489
        }
490
491
        return $path;
492
    }
493
}
494