Passed
Pull Request — master (#275)
by Arman
03:52
created

ViewCache::serveCachedView()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 4
nc 2
nop 2
dl 0
loc 8
rs 10
c 1
b 0
f 0
1
<?php
2
3
/**
4
 * Quantum PHP Framework
5
 *
6
 * An open source software development framework for PHP
7
 *
8
 * @package Quantum
9
 * @author Arman Ag. <[email protected]>
10
 * @copyright Copyright (c) 2018 Softberg LLC (https://softberg.org)
11
 * @link http://quantum.softberg.org/
12
 * @since 2.9.7
13
 */
14
15
namespace Quantum\Libraries\ResourceCache;
16
17
use Quantum\Libraries\Database\Exceptions\DatabaseException;
18
use Quantum\Libraries\Storage\Factories\FileSystemFactory;
19
use Quantum\Libraries\Session\Exceptions\SessionException;
20
use Quantum\Libraries\Config\Exceptions\ConfigException;
21
use Quantum\Di\Exceptions\DiException;
22
use Quantum\Exceptions\BaseException;
23
use Quantum\Http\Response;
24
use Quantum\Loader\Setup;
25
use ReflectionException;
26
use voku\helper\HtmlMin;
27
use Exception;
28
29
/**
30
 * ViewCache class
31
 * @package Quantum\Libraries\ResourceCache
32
 */
33
class ViewCache
34
{
35
36
    /**
37
     * @var string
38
     */
39
    private $cacheDir;
40
41
    /**
42
     * @var int
43
     */
44
    private $ttl = 300;
45
46
    /**
47
     * @var bool
48
     */
49
    private $isEnabled;
50
51
    /**
52
     * @var bool
53
     */
54
    private $minification = false;
55
56
    /**
57
     * @var object
58
     */
59
    private $fs;
60
61
    /**
62
     * @var ViewCache
63
     */
64
    private static $instance = null;
65
66
    public static function getInstance(): ViewCache
67
    {
68
        if (self::$instance === null) {
69
            self::$instance = new self();
70
        }
71
72
        return self::$instance;
73
    }
74
75
    /**
76
     * @throws DiException
77
     * @throws Exception
78
     */
79
    public function __construct()
80
    {
81
        $this->isEnabled = filter_var(config()->get('resource_cache'), FILTER_VALIDATE_BOOLEAN);
82
83
        $this->fs = FileSystemFactory::get();
84
    }
85
86
    /**
87
     * @throws ReflectionException
88
     * @throws ConfigException
89
     * @throws DiException
90
     */
91
    public function setup()
92
    {
93
        if (!config()->has('view_cache')) {
94
            config()->import(new Setup('config', 'view_cache'));
95
        }
96
97
        $this->cacheDir = $this->getCacheDir();
98
99
        $this->ttl = config()->get('view_cache.ttl', $this->ttl);
100
101
        $this->minification = filter_var(config()->get('view_cache.minify', $this->minification), FILTER_VALIDATE_BOOLEAN);
102
103
        if (!$this->fs->isDirectory($this->cacheDir)) {
104
            mkdir($this->cacheDir, 0777, true);
105
        }
106
    }
107
108
    /**
109
     * @param string $uri
110
     * @param Response $response
111
     * @return bool
112
     * @throws BaseException
113
     * @throws ConfigException
114
     * @throws DatabaseException
115
     * @throws DiException
116
     * @throws ReflectionException
117
     * @throws SessionException
118
     */
119
    public function serveCachedView(string $uri, Response $response): bool
120
    {
121
        if ($this->isEnabled() && $this->exists($uri)) {
122
            $response->html($this->get($uri));
123
            return true;
124
        }
125
126
        return false;
127
    }
128
129
    /**
130
     * @param string $key
131
     * @param string $content
132
     * @return $this
133
     * @throws BaseException
134
     * @throws ConfigException
135
     * @throws DiException
136
     * @throws ReflectionException
137
     */
138
    public function set(string $key, string $content): ViewCache
139
    {
140
        if ($this->minification) {
141
            $content = $this->minify($content);
142
        }
143
144
        $this->fs->put($this->getCacheFile($key), $content);
145
146
        return $this;
147
    }
148
149
    /**
150
     * @param string $key
151
     * @return string|null
152
     * @throws BaseException
153
     * @throws ConfigException
154
     * @throws DatabaseException
155
     * @throws DiException
156
     * @throws ReflectionException
157
     * @throws SessionException
158
     */
159
    public function get(string $key): ?string
160
    {
161
        if (!$this->exists($key)) {
162
            return null;
163
        }
164
165
        return $this->fs->get($this->getCacheFile($key));
166
    }
167
168
    /**
169
     * @param string $key
170
     * @return void
171
     * @throws BaseException
172
     * @throws ConfigException
173
     * @throws DiException
174
     * @throws ReflectionException
175
     */
176
    public function delete(string $key): void
177
    {
178
        $cacheFile = $this->getCacheFile($key);
179
180
        if ($this->fs->exists($cacheFile)) {
181
            $this->fs->remove($cacheFile);
182
        }
183
    }
184
185
    /**
186
     * @param string $key
187
     * @return bool
188
     * @throws BaseException
189
     * @throws ConfigException
190
     * @throws DiException
191
     * @throws ReflectionException
192
     */
193
    public function exists(string $key): bool
194
    {
195
        $cacheFile = $this->getCacheFile($key);
196
197
        if (!$this->fs->exists($cacheFile) || $this->isExpired($cacheFile)) {
198
            return false;
199
        }
200
201
        return true;
202
    }
203
204
    /**
205
     * @return bool
206
     */
207
    public function isEnabled(): bool
208
    {
209
        return $this->isEnabled;
210
    }
211
212
    /**
213
     * @param bool $state
214
     * @return void
215
     */
216
    public function enableCaching(bool $state): void
217
    {
218
        $this->isEnabled = $state;
219
    }
220
221
    /**
222
     * @param int $ttl
223
     * @return void
224
     */
225
    public function setTtl(int $ttl): void
226
    {
227
        $this->ttl = $ttl;
228
    }
229
230
    /**
231
     * @param bool $state
232
     * @return void
233
     */
234
    public function enableMinification(bool $state): void
235
    {
236
        $this->minification = $state;
237
    }
238
239
    /**
240
     * @param $cacheFile
241
     * @return bool
242
     */
243
    private function isExpired($cacheFile): bool
244
    {
245
        if (time() > ($this->fs->lastModified($cacheFile) + $this->ttl)) {
246
            $this->fs->remove($cacheFile);
247
            return true;
248
        }
249
250
        return false;
251
    }
252
253
    /**
254
     * @return string
255
     */
256
    private function getCacheDir(): string
257
    {
258
        $configCacheDir = config()->get('view_cache.cache_dir', 'cache');
259
260
        $viewCacheDir = base_dir() . DS . $configCacheDir . DS . 'views';
261
262
        if ($module = current_module()) {
263
            $viewCacheDir = base_dir() . DS . $configCacheDir . DS . 'views' . DS . strtolower($module);
264
        }
265
266
        return $viewCacheDir;
267
    }
268
269
    /**
270
     * @param string $key
271
     * @return string
272
     * @throws ConfigException
273
     * @throws DiException
274
     * @throws ReflectionException
275
     * @throws BaseException
276
     */
277
    private function getCacheFile(string $key): string
278
    {
279
        return $this->cacheDir . DS . md5($key . session()->getId());
280
    }
281
282
    /**
283
     * @param string $content
284
     * @return string
285
     */
286
    private function minify(string $content): string
287
    {
288
        if (class_exists(HtmlMin::class)) {
289
            return (new HtmlMin())->minify($content);
290
        }
291
292
        return $content;
293
    }
294
}