Cache   A
last analyzed

Complexity

Total Complexity 29

Size/Duplication

Total Lines 194
Duplicated Lines 0 %

Test Coverage

Coverage 91.43%

Importance

Changes 0
Metric Value
eloc 64
dl 0
loc 194
ccs 64
cts 70
cp 0.9143
rs 10
c 0
b 0
f 0
wmc 29

11 Methods

Rating   Name   Duplication   Size   Complexity  
A generateDate() 0 16 5
A get() 0 15 5
A getBucket() 0 7 2
A __construct() 0 11 4
A delete() 0 13 4
A flush() 0 3 1
A forever() 0 4 1
A dataPath() 0 4 1
A ensureCacheDirectoryExists() 0 4 2
A path() 0 8 1
A put() 0 13 3
1
<?php
2
3
namespace Yiranzai\File;
4
5
use DateTime;
6
use DateInterval;
7
8
/**
9
 * Class Cache
10
 * @package Yiranzai\File
11
 */
12
class Cache
13
{
14
    public const DEFAULT_PATH = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'data'
15
    . DIRECTORY_SEPARATOR;
16
    /**
17
     * @var string
18
     */
19
    protected $dataPath = self::DEFAULT_PATH;
20
    /**
21
     * @var Filesystem
22
     */
23
    protected $file;
24
    /**
25
     * @var array
26
     */
27
    protected $guarded = ['file'];
28
29
    /**
30
     * Hash constructor.
31
     * @param array $config
32
     */
33 12
    public function __construct($config = [])
34
    {
35 12
        if (!empty($config)) {
36 3
            foreach ($config as $key => $item) {
37 3
                if (in_array($key, $this->guarded, true)) {
38 3
                    continue;
39
                }
40 3
                $this->$key = $item;
41
            }
42
        }
43 12
        $this->file = new Filesystem();
44 12
    }
45
46
    /**
47
     * 存储数据
48
     *
49
     * @param string                   $key
50
     * @param string                   $data
51
     * @param string|DateTime|int|null $minutes
52
     * @return Cache
53
     * @throws \Exception
54
     */
55 12
    public function put(string $key, string $data, $minutes = null): Cache
56
    {
57 12
        $this->ensureCacheDirectoryExists($path = $this->path($key));
58
59 12
        if ($this->file->exists($path = $this->path($key))) {
60
            if ($bucket = $this->getBucket($path)) {
61
                $bucket->putNode($key, $data, $this->generateDate($minutes));
62
            }
63
        } else {
64 12
            $bucket = new Bucket($key, $data, $this->generateDate($minutes));
65
        }
66 9
        $this->file->put($path, serialize($bucket));
67 9
        return $this;
68
    }
69
70
    /**
71
     * @param string $key
72
     * @param string $data
73
     * @return Cache
74
     * @throws \Exception
75
     */
76 3
    public function forever(string $key, string $data): Cache
77
    {
78 3
        $this->put($key, $data);
79 3
        return $this;
80
    }
81
82
    /**
83
     * @param $minutes
84
     * @return DateTime
85
     * @throws \Exception
86
     */
87 12
    protected function generateDate($minutes): ?DateTime
88
    {
89 12
        if ($minutes === null) {
90 9
            return null;
91
        }
92 6
        if ($minutes instanceof \DateTime) {
93 3
            return $minutes;
94
        }
95 6
        if (is_int($minutes)) {
96 3
            $date = new DateTime();
97 3
            return $date->add(new DateInterval('PT' . $minutes . 'M'));
98
        }
99
        try {
100 6
            return new DateTime($minutes);
101 3
        } catch (\Exception $exception) {
102 3
            throw new $exception;
103
        }
104
    }
105
106
    /**
107
     * @param  string $path
108
     * @return void
109
     */
110 12
    protected function ensureCacheDirectoryExists($path): void
111
    {
112 12
        if (!$this->file->exists(dirname($path))) {
113 12
            $this->file->makeDirectory(dirname($path), 0777, true, true);
114
        }
115 12
    }
116
117
    /**
118
     * @param string $key
119
     * @return string
120
     */
121 12
    protected function path(string $key): string
122
    {
123 12
        $parts = array_slice(str_split($hash = hash('sha256', $key), 2), 0, 2);
124
125 12
        return $this->dataPath . DIRECTORY_SEPARATOR . implode(
126 12
            DIRECTORY_SEPARATOR,
127 8
            $parts
128 12
        ) . DIRECTORY_SEPARATOR . $hash;
129
    }
130
131
    /**
132
     * @param string $path
133
     * @return Bucket|null
134
     */
135 9
    protected function getBucket(string $path): ?Bucket
136
    {
137 9
        $bucket = $this->file->get($path);
138 9
        if ($bucket) {
139 9
            $bucket = unserialize($bucket, ['allowed_classes' => [Node::class, Bucket::class, DateTime::class]]);
140
        }
141 9
        return $bucket;
142
    }
143
144
    /**
145
     * 获取数据
146
     *
147
     * @param string $key
148
     * @param null   $default
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $default is correct as it would always require null to be passed?
Loading history...
149
     * @return null|string
150
     * @throws \Exception
151
     */
152 9
    public function get(string $key, $default = null): ?string
153
    {
154 9
        if (!$this->file->exists($path = $this->path($key))) {
155 6
            return $default;
156
        }
157 6
        if (!$bucket = $this->getBucket($path)) {
158
            return $default;
159
        }
160 6
        if ($node = $bucket->findNode($key)) {
161 6
            if ($node->isExpired()) {
162 3
                $this->delete($key);
163
            }
164 6
            return $node->getData($default);
165
        }
166
        return $default;
167
    }
168
169
    /**
170
     * 删除一个数据
171
     *
172
     * @param string $key
173
     * @return bool
174
     */
175 6
    public function delete(string $key): bool
176
    {
177 6
        if (!$this->file->exists($path = $this->path($key))) {
178 3
            return true;
179
        }
180 6
        if (!($bucket = $this->getBucket($path))) {
181
            return true;
182
        }
183 6
        $bucket->delNode($key);
184 6
        if (!$bucket->isNull()) {
185
            $this->file->put($path, serialize($bucket));
186
        }
187 6
        return $this->file->delete($path);
188
    }
189
190
    /**
191
     *  删除所有的数据
192
     */
193 3
    public function flush(): void
194
    {
195 3
        $this->file->deleteDirectory($this->dataPath);
196 3
    }
197
198
    /**
199
     * @param string $path
200
     * @return $this
201
     */
202 3
    public function dataPath(string $path): self
203
    {
204 3
        $this->dataPath = $path;
205 3
        return $this;
206
    }
207
}
208