Test Failed
Pull Request — master (#952)
by Maxim
16:49 queued 07:48
created

FileStorage   A

Complexity

Total Complexity 26

Size/Duplication

Total Lines 137
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 26
eloc 50
dl 0
loc 137
ccs 62
cts 62
cp 1
rs 10
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Spiral\Cache\Storage;
6
7
use Psr\SimpleCache\CacheInterface;
8
use Spiral\Files\Exception\FileNotFoundException;
9
use Spiral\Files\FilesInterface;
10
11
final class FileStorage implements CacheInterface
12
{
13
    use InteractsWithTime;
14
15 21
    public function __construct(
16
        private readonly FilesInterface $files,
17
        private readonly string $path,
18
        private readonly int $ttl = 2_592_000
0 ignored issues
show
Bug introduced by
A parse error occurred: Syntax error, unexpected T_STRING, expecting ')' on line 18 at column 37
Loading history...
19
    ) {
20 21
    }
21
22 5
    public function get(string $key, mixed $default = null): mixed
23
    {
24 5
        return $this->getPayload($key)['value'] ?? $default;
25
    }
26
27 7
    public function set(string $key, mixed $value, null|int|\DateInterval|\DateTimeInterface $ttl = null): bool
28
    {
29 7
        return $this->files->write(
30 7
            $this->makePath($key),
31 7
            $this->ttlToTimestamp($ttl) . \serialize($value),
32 7
            null,
33 7
            true
34 7
        );
35
    }
36
37 7
    public function delete(string $key): bool
38
    {
39 7
        if ($this->has($key)) {
40 5
            return $this->files->delete($this->makePath($key));
41
        }
42
43 2
        return false;
44
    }
45
46 2
    public function clear(): bool
47
    {
48 2
        if (!$this->files->isDirectory($this->path)) {
49 1
            return false;
50
        }
51
52 1
        $this->files->deleteDirectory($this->path);
53
54 1
        return true;
55
    }
56
57 1
    public function getMultiple(iterable $keys, mixed $default = null): iterable
58
    {
59 1
        $result = [];
60
61 1
        foreach ($keys as $key) {
62 1
            $result[$key] = $this->get($key, $default);
63
        }
64
65 1
        return $result;
66
    }
67
68 3
    public function setMultiple(iterable $values, null|int|\DateInterval|\DateTimeInterface $ttl = null): bool
69
    {
70 3
        $state = null;
71
72 3
        foreach ($values as $key => $value) {
73 3
            $result = $this->set($key, $value, $ttl);
74 3
            $state = \is_null($state) ? $result : $result && $state;
75
        }
76
77 3
        return $state ?: false;
78
    }
79
80 2
    public function deleteMultiple(iterable $keys): bool
81
    {
82 2
        $state = null;
83 2
        foreach ($keys as $key) {
84 2
            $result = $this->delete($key);
85 2
            $state = \is_null($state) ? $result : $result && $state;
86
        }
87
88 2
        return $state ?: false;
89
    }
90
91 9
    public function has(string $key): bool
92
    {
93 9
        return $this->files->exists($this->makePath($key));
94
    }
95
96
    /**
97
     * Make the full path for the given cache key.
98
     */
99 18
    protected function makePath(string $key): string
100
    {
101 18
        $parts = \array_slice(\str_split($hash = \sha1($key), 2), 0, 2);
102
103 18
        return $this->path . '/' . \implode('/', $parts) . '/' . $hash;
104
    }
105
106
    /**
107
     * Retrieve an item and expiry time from the cache by key.
108
     */
109 5
    protected function getPayload(string $key): array
110
    {
111 5
        $path = $this->makePath($key);
112
113
        try {
114 5
            $expire = (int) \substr(
115 5
                $contents = $this->files->read($path),
116 5
                0,
117 5
                10
118 5
            );
119 1
        } catch (FileNotFoundException) {
120 1
            return $this->makeEmptyPayload();
121
        }
122
123 4
        if (\time() >= $expire) {
124 2
            $this->delete($key);
125
126 2
            return $this->makeEmptyPayload();
127
        }
128
129
        try {
130 3
            $data = \unserialize(\substr($contents, 10));
131 1
        } catch (\Exception) {
132 1
            $this->delete($key);
133
134 1
            return $this->makeEmptyPayload();
135
        }
136
137 2
        $time = $expire - \time();
138
139 2
        return ['value' => $data, 'timestamp' => $time];
140
    }
141
142
    /**
143
     * Make a default empty payload for the cache.
144
     */
145 4
    protected function makeEmptyPayload(): array
146
    {
147 4
        return ['value' => null, 'timestamp' => null];
148
    }
149
}
150