Passed
Push — twig ( 58b23d )
by Arnaud
05:08
created

Cache::get()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 2
eloc 7
nc 2
nop 2
dl 0
loc 13
rs 10
c 1
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
        $key = $this->prepareKey($key);
49
50
        try {
51
            $data = unserialize(file_get_contents($this->getFilePathname($key)));
52
        } catch (Exception $e) {
53
            $this->builder->getLogger()->error($e->getMessage());
54
55
            return $default;
56
        }
57
58
        return $data['value'];
59
    }
60
61
    /**
62
     * {@inheritdoc}
63
     */
64
    public function set($key, $value, $ttl = null)
65
    {
66
        try {
67
            $key = $this->prepareKey($key);
68
            $data = serialize([
69
                'value'      => $value,
70
                'expiration' => time() + $ttl,
71
            ]);
72
73
            $this->prune($key);
74
            Util::getFS()->dumpFile($this->getFilePathname($key), $data);
75
        } catch (Exception $e) {
76
            $this->builder->getLogger()->error($e->getMessage());
77
78
            return false;
79
        }
80
81
        return true;
82
    }
83
84
    /**
85
     * {@inheritdoc}
86
     */
87
    public function delete($key)
88
    {
89
        try {
90
            $key = $this->prepareKey($key);
91
            Util::getFS()->remove($this->getFilePathname($key));
92
            $this->prune($key);
93
        } catch (Exception $e) {
94
            $this->builder->getLogger()->error($e->getMessage());
95
96
            return false;
97
        }
98
99
        return true;
100
    }
101
102
    /**
103
     * {@inheritdoc}
104
     */
105
    public function clear()
106
    {
107
        try {
108
            Util::getFS()->remove($this->cacheDir);
109
        } catch (Exception $e) {
110
            $this->builder->getLogger()->error($e->getMessage());
111
112
            return false;
113
        }
114
115
        return true;
116
    }
117
118
    /**
119
     * {@inheritdoc}
120
     */
121
    public function getMultiple($keys, $default = null)
122
    {
123
        throw new Exception(sprintf('%s::%s not yet implemented.', __CLASS__, __FUNCTION__));
124
    }
125
126
    /**
127
     * {@inheritdoc}
128
     */
129
    public function setMultiple($values, $ttl = null)
130
    {
131
        throw new Exception(sprintf('%s::%s not yet implemented.', __CLASS__, __FUNCTION__));
132
    }
133
134
    /**
135
     * {@inheritdoc}
136
     */
137
    public function deleteMultiple($keys)
138
    {
139
        throw new Exception(sprintf('%s::%s not yet implemented.', __CLASS__, __FUNCTION__));
140
    }
141
142
    /**
143
     * {@inheritdoc}
144
     */
145
    public function has($key)
146
    {
147
        $key = $this->prepareKey($key);
148
        if (!Util::getFS()->exists($this->getFilePathname($key))) {
149
            return false;
150
        }
151
152
        return true;
153
    }
154
155
    /**
156
     * Creates a cache key from a value (MD5 hash).
157
     *
158
     * @param string $value
159
     *
160
     * @return string
161
     */
162
    public function createKeyFromValue(string $value): string
163
    {
164
        return hash('md5', $value);
165
    }
166
167
    /**
168
     * Creates a cache key from a file (with MD5 hash).
169
     *
170
     * @param string $file
171
     * @param string $path
172
     *
173
     * @return string
174
     */
175
    public function createKeyFromFile(string $file, string $path): string
176
    {
177
        $content = file_get_contents($file);
178
179
        return \sprintf('%s__%s', $path, $content !== false ? $this->createKeyFromValue($content) : '');
180
    }
181
182
    /**
183
     * Creates a cache key from an Asset (with MD5 hash).
184
     *
185
     * @param Asset $asset
186
     *
187
     * @return string
188
     */
189
    public function createKeyFromAsset(Asset $asset): string
190
    {
191
        return \sprintf('%s__%s', $asset['path'], $this->createKeyFromValue($asset['content'] ?? ''));
192
    }
193
194
    /**
195
     * Returns cache file pathname.
196
     *
197
     * @param string $key
198
     *
199
     * @return string
200
     */
201
    private function getFilePathname(string $key): string
202
    {
203
        return Util::joinFile($this->cacheDir, $key);
204
    }
205
206
    /**
207
     * Removes previous cache files.
208
     *
209
     * @param string $key
210
     *
211
     * @return bool
212
     */
213
    private function prune(string $key): bool
214
    {
215
        try {
216
            $key = $this->prepareKey($key);
217
            $pattern = Util::joinFile($this->cacheDir, explode('__', $key)[0]).'*';
218
            foreach (glob($pattern) as $filename) {
219
                Util::getFS()->remove($filename);
220
            }
221
        } catch (Exception $e) {
222
            $this->builder->getLogger()->error($e->getMessage());
223
224
            return false;
225
        }
226
227
        return true;
228
    }
229
230
    /**
231
     * $key must be a string.
232
     *
233
     * @param string $key
234
     *
235
     * @return string
236
     */
237
    private function prepareKey(string $key): string
238
    {
239
        $key = str_replace(['https://', 'http://'], '', $key);
240
        $key = Page::slugify($key);
241
        $key = trim($key, '/');
242
        $key = str_replace(['\\', '/'], ['-', '-'], $key);
243
244
        return $key;
245
    }
246
}
247