QtView::getLayout()   A
last analyzed

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.8
13
 */
14
15
namespace Quantum\View;
16
17
use Quantum\Libraries\Database\Exceptions\DatabaseException;
18
use Quantum\Libraries\Session\Exceptions\SessionException;
19
use Quantum\Libraries\Asset\Exceptions\AssetException;
20
use Quantum\Libraries\ResourceCache\ViewCache;
21
use Quantum\Config\Exceptions\ConfigException;
22
use Quantum\View\Exceptions\ViewException;
23
use Quantum\App\Exceptions\BaseException;
24
use Quantum\Libraries\Asset\AssetManager;
25
use Quantum\Di\Exceptions\DiException;
26
use Quantum\Renderer\Renderer;
27
use Quantum\Debugger\Debugger;
28
use ReflectionException;
29
use Psr\Log\LogLevel;
30
31
/**
32
 * Class QtView
33
 * @package Quantum\View
34
 */
35
class QtView
36
{
37
38
    /**
39
     * @var Renderer
40
     */
41
    private $renderer;
42
43
    /**
44
     * @var AssetManager
45
     */
46
    private $assetManager;
47
48
    /**
49
     * @var Debugger
50
     */
51
    private $debugger;
52
53
    /**
54
     * @var ViewCache
55
     */
56
    private $viewCache;
57
58
    /**
59
     * Layout file
60
     * @var string
61
     */
62
    private $layoutFile = null;
63
64
    /**
65
     * Rendered view
66
     * @var string
67
     */
68
    private $viewContent;
69
70
    /**
71
     * Assets to be included
72
     * @var array
73
     */
74
    private $assets = [];
75
76
    /**
77
     * View params
78
     * @var array
79
     */
80
    private $params = [];
81
82
    /**
83
     * @param Renderer $renderer
84
     * @param AssetManager $assetManager
85
     * @param Debugger $debugger
86
     * @param ViewCache $viewCache
87
     */
88
    public function __construct(
89
        Renderer $renderer,
90
        AssetManager $assetManager,
91
        Debugger $debugger,
92
        ViewCache $viewCache
93
    )
94
    {
95
        $this->renderer = $renderer;
96
        $this->assetManager = $assetManager;
97
        $this->debugger = $debugger;
98
        $this->viewCache = $viewCache;
99
    }
100
101
    /**
102
     * Sets a layout
103
     * @param string|null $layoutFile
104
     * @param array $assets
105
     */
106
    public function setLayout(?string $layoutFile, array $assets = [])
107
    {
108
        $this->layoutFile = $layoutFile;
109
110
        if(!empty($assets)) {
111
            $this->assets = array_merge($this->assets, $assets);
112
        }
113
    }
114
115
    /**
116
     * Gets the layout
117
     * @return string|null
118
     */
119
    public function getLayout(): ?string
120
    {
121
        return $this->layoutFile;
122
    }
123
124
    /**
125
     * Sets view parameter
126
     * @param string $key
127
     * @param mixed $value
128
     */
129
    public function setParam(string $key, $value)
130
    {
131
        $this->params[$key] = $value;
132
    }
133
134
    /**
135
     * @param string $key
136
     * @param $value
137
     * @return void
138
     */
139
    public function setRawParam(string $key, $value)
140
    {
141
        $this->params[$key] = new RawParam($value);
142
    }
143
144
    /**
145
     * Gets the view parameter
146
     * @param string $key
147
     * @return mixed|null
148
     */
149
    public function getParam(string $key)
150
    {
151
        $param = $this->params[$key] ?? null;
152
153
        if ($param instanceof RawParam) {
154
            return $param->getValue();
155
        }
156
157
        return $param;
158
    }
159
160
    /**
161
     * Sets multiple view parameters
162
     * @param array $params
163
     */
164
    public function setParams(array $params)
165
    {
166
        foreach ($params as $key => $value) {
167
            $this->setParam($key, $value);
168
        }
169
    }
170
171
    /**
172
     * Gets all view parameters
173
     * @return array
174
     */
175
    public function getParams(): array
176
    {
177
        $params = [];
178
179
        foreach ($this->params as $key => $param) {
180
            $params[$key] = ($param instanceof RawParam) ? $param->getValue() : $param;
181
        }
182
183
        return $params;
184
    }
185
186
    /**
187
     * Flushes the view params
188
     */
189
    public function flushParams()
190
    {
191
        $this->params = [];
192
    }
193
194
    /**
195
     * Renders the view.
196
     * @param string $viewFile
197
     * @param array $params
198
     * @return string|null
199
     * @throws AssetException
200
     * @throws BaseException
201
     * @throws ConfigException
202
     * @throws DatabaseException
203
     * @throws DiException
204
     * @throws ReflectionException
205
     * @throws SessionException
206
     * @throws ViewException
207
     */
208
    public function render(string $viewFile, array $params = []): ?string
209
    {
210
        if (!$this->layoutFile) {
211
            throw ViewException::noLayoutSet();
212
        }
213
214
        if (!empty($params)) {
215
            $this->params = array_merge($this->params, $params);
216
        }
217
218
        $this->viewContent = $this->renderFile($viewFile);
219
220
        if (!empty($this->assets)) {
221
            $this->assetManager->register($this->assets);
222
        }
223
224
        if ($this->debugger->isEnabled()) {
225
            $this->updateDebugger($viewFile);
226
        }
227
228
        $layoutContent = $this->renderFile($this->layoutFile);
229
230
        if ($this->viewCache->isEnabled()) {
231
            $layoutContent = $this->viewCache
232
                ->set(route_uri(), $layoutContent)
233
                ->get(route_uri());
234
        }
235
236
        return $layoutContent;
237
    }
238
239
    /**
240
     * Renders partial view.
241
     * @param string $viewFile
242
     * @param array $params
243
     * @return string
244
     */
245
    public function renderPartial(string $viewFile, array $params = []): string
246
    {
247
        if (!empty($params)) {
248
            $this->params = array_merge($this->params, $params);
249
        }
250
251
        return $this->renderFile($viewFile);
252
    }
253
254
    /**
255
     * Gets the rendered view.
256
     * @return string|null
257
     * @throws ViewException
258
     */
259
    public function getView(): ?string
260
    {
261
        if ($this->viewContent === null) {
262
            throw ViewException::viewNotRendered();
263
        }
264
265
        return $this->viewContent;
266
    }
267
268
    /**
269
     * Renders the view
270
     * @param string $viewFile
271
     * @return string
272
     */
273
    private function renderFile(string $viewFile): string
274
    {
275
        $filteredParams = $this->xssFilter($this->params);
276
277
        return $this->renderer->render($viewFile, $filteredParams);
278
    }
279
280
    /**
281
     * XSS Filter
282
     * @param mixed $params
283
     * @return mixed
284
     */
285
    private function xssFilter($params)
286
    {
287
        if ($params instanceof RawParam) {
288
            return $params->getValue();
289
        }
290
291
        if (is_string($params)) {
292
            return $this->sanitizeHtml($params);
293
        }
294
295
        if (is_array($params)) {
296
            foreach ($params as $key => $value) {
297
                $params[$key] = $this->xssFilter($value);
298
            }
299
300
            return $params;
301
        }
302
303
        if (is_object($params)) {
304
            foreach (get_object_vars($params) as $property => $value) {
305
                $params->$property = $this->xssFilter($value);
306
            }
307
308
            return $params;
309
        }
310
311
        return $params;
312
    }
313
314
    /**
315
     * @param string $value
316
     * @return string
317
     */
318
    private function sanitizeHtml(string $value): string
319
    {
320
        return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
321
    }
322
323
    /**
324
     * @param string $viewFile
325
     * @return void
326
     */
327
    private function updateDebugger(string $viewFile)
328
    {
329
        $routesCell = $this->debugger->getStoreCell(Debugger::ROUTES);
330
        $currentData = current($routesCell)[LogLevel::INFO] ?? [];
331
        $additionalData = ['View' => current_module() . '/Views/' . $viewFile];
332
        $mergedData = array_merge($currentData, $additionalData);
333
        $this->debugger->clearStoreCell(Debugger::ROUTES);
334
        $this->debugger->addToStoreCell(Debugger::ROUTES, LogLevel::INFO, $mergedData);
335
    }
336
}