Completed
Push — master ( 8c15b3...f8d4b2 )
by Arman
15s queued 11s
created

ViewCache::htmlMinifierExists()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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