Passed
Push — analysis-gOJ73E ( 71f184 )
by Arnaud
08:35 queued 02:45
created

Cache::createKeyFromPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 2
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * This file is part of the Cecil/Cecil package.
4
 *
5
 * Copyright (c) Arnaud Ligny <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
11
namespace Cecil\Assets;
12
13
use Cecil\Builder;
14
use Cecil\Collection\Page\Page;
15
use Cecil\Config;
16
use Cecil\Util;
17
use Exception;
18
use Psr\SimpleCache\CacheInterface;
19
20
class Cache implements CacheInterface
21
{
22
    /** @var Builder */
23
    protected $builder;
24
    /** @var Config */
25
    protected $config;
26
    /** @var string */
27
    protected $pool;
28
    /** @var string */
29
    protected $cacheDir;
30
31
    /**
32
     * @param Builder $builder
33
     * @param string  $pool
34
     */
35
    public function __construct(Builder $builder, string $pool)
36
    {
37
        $this->builder = $builder;
38
        $this->config = $builder->getConfig();
39
        $this->pool = $pool;
40
        $this->cacheDir = Util::joinFile($this->config->getCachePath(), $pool);
41
    }
42
43
    /**
44
     * {@inheritdoc}
45
     */
46
    public function get($key, $default = null)
47
    {
48
        try {
49
            $key = $this->prepareKey($key);
50
            $data = unserialize(Util\File::fileGetContents($this->getFilePathname($key)));
0 ignored issues
show
Bug introduced by
It seems like Cecil\Util\File::fileGet...>getFilePathname($key)) can also be of type false; however, parameter $data of unserialize() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

50
            $data = unserialize(/** @scrutinizer ignore-type */ Util\File::fileGetContents($this->getFilePathname($key)));
Loading history...
51
        } catch (Exception $e) {
52
            $this->builder->getLogger()->error($e->getMessage());
53
54
            return $default;
55
        }
56
57
        return $data['value'];
58
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63
    public function set($key, $value, $ttl = null)
64
    {
65
        try {
66
            $key = $this->prepareKey($key);
67
            $data = serialize([
68
                'value'      => $value,
69
                'expiration' => time() + $ttl,
70
            ]);
71
72
            $this->prune($key);
73
            Util\File::getFS()->dumpFile($this->getFilePathname($key), $data);
74
        } catch (Exception $e) {
75
            $this->builder->getLogger()->error($e->getMessage());
76
77
            return false;
78
        }
79
80
        return true;
81
    }
82
83
    /**
84
     * {@inheritdoc}
85
     */
86
    public function delete($key)
87
    {
88
        try {
89
            $key = $this->prepareKey($key);
90
            Util\File::getFS()->remove($this->getFilePathname($key));
91
            $this->prune($key);
92
        } catch (Exception $e) {
93
            $this->builder->getLogger()->error($e->getMessage());
94
95
            return false;
96
        }
97
98
        return true;
99
    }
100
101
    /**
102
     * {@inheritdoc}
103
     */
104
    public function clear()
105
    {
106
        try {
107
            Util\File::getFS()->remove($this->cacheDir);
108
        } catch (Exception $e) {
109
            $this->builder->getLogger()->error($e->getMessage());
110
111
            return false;
112
        }
113
114
        return true;
115
    }
116
117
    /**
118
     * {@inheritdoc}
119
     */
120
    public function getMultiple($keys, $default = null)
121
    {
122
        throw new Exception(sprintf('%s::%s not yet implemented.', __CLASS__, __FUNCTION__));
123
    }
124
125
    /**
126
     * {@inheritdoc}
127
     */
128
    public function setMultiple($values, $ttl = null)
129
    {
130
        throw new Exception(sprintf('%s::%s not yet implemented.', __CLASS__, __FUNCTION__));
131
    }
132
133
    /**
134
     * {@inheritdoc}
135
     */
136
    public function deleteMultiple($keys)
137
    {
138
        throw new Exception(sprintf('%s::%s not yet implemented.', __CLASS__, __FUNCTION__));
139
    }
140
141
    /**
142
     * {@inheritdoc}
143
     */
144
    public function has($key)
145
    {
146
        $key = $this->prepareKey($key);
147
        if (!Util\File::getFS()->exists($this->getFilePathname($key))) {
148
            return false;
149
        }
150
151
        return true;
152
    }
153
154
    /**
155
     * Creates a cache key from a value.
156
     *
157
     * @param string $value
158
     *
159
     * @return string MD5 hash
160
     */
161
    public function createKeyFromValue(string $value): string
162
    {
163
        return hash('md5', $value);
164
    }
165
166
    /**
167
     * Creates a cache key from a path.
168
     *
169
     * @param string $path
170
     * @param string $relativePath
171
     *
172
     * @return string $relativePath + '__' + MD5 hash
173
     */
174
    public function createKeyFromPath(string $path, string $relativePath): string
175
    {
176
        if (false === $content = Util\File::fileGetContents($path)) {
177
            throw new Exception(sprintf('Can\'t create cache key for "%s"', $path));
178
        }
179
        $key = $this->prepareKey(\sprintf('%s__%s', $relativePath, $this->createKeyFromValue($content)));
180
181
        return $key;
182
    }
183
184
    /**
185
     * Creates a cache key from an Asset.
186
     *
187
     * @param Asset $asset
188
     *
189
     * @return string $path + '__' + MD5 hash
190
     */
191
    public function createKeyFromAsset(Asset $asset): string
192
    {
193
        $key = $this->prepareKey(\sprintf('%s__%s', $asset['path'], $this->createKeyFromValue($asset['source'])));
0 ignored issues
show
Bug introduced by
It seems like $asset['source'] can also be of type null; however, parameter $value of Cecil\Assets\Cache::createKeyFromValue() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

193
        $key = $this->prepareKey(\sprintf('%s__%s', $asset['path'], $this->createKeyFromValue(/** @scrutinizer ignore-type */ $asset['source'])));
Loading history...
194
195
        return $key;
196
    }
197
198
    /**
199
     * Returns cache file pathname from key.
200
     *
201
     * @param string $key
202
     *
203
     * @return string
204
     */
205
    private function getFilePathname(string $key): string
206
    {
207
        return Util::joinFile($this->cacheDir, $key);
208
    }
209
210
    /**
211
     * Removes previous cache files.
212
     *
213
     * @param string $key
214
     *
215
     * @return bool
216
     */
217
    private function prune(string $key): bool
218
    {
219
        try {
220
            $key = $this->prepareKey($key);
221
            $pattern = Util::joinFile($this->cacheDir, explode('__', $key)[0]).'*';
222
            foreach (glob($pattern) as $filename) {
223
                Util\File::getFS()->remove($filename);
224
            }
225
        } catch (Exception $e) {
226
            $this->builder->getLogger()->error($e->getMessage());
227
228
            return false;
229
        }
230
231
        return true;
232
    }
233
234
    /**
235
     * $key must be a string.
236
     *
237
     * @param string $key
238
     *
239
     * @return string
240
     */
241
    private function prepareKey(string $key): string
242
    {
243
        $key = str_replace(['https://', 'http://'], '', $key);
244
        $key = Page::slugify($key);
245
        $key = trim($key, '/');
246
        $key = str_replace(['\\', '/'], ['-', '-'], $key);
247
248
        return $key;
249
    }
250
}
251