Completed
Push — master ( 34ec74...fc4fa7 )
by Arman
20s queued 16s
created

QtView::setRawParam()   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 2
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.7
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\Config\Exceptions\ConfigException;
20
use Quantum\Libraries\Asset\Exceptions\AssetException;
21
use Quantum\Libraries\ResourceCache\ViewCache;
22
use Quantum\View\Exceptions\ViewException;
23
use Quantum\Libraries\Asset\AssetManager;
24
use Quantum\Di\Exceptions\DiException;
25
use Quantum\Exceptions\BaseException;
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
        $this->assets = $assets;
110
    }
111
112
    /**
113
     * Gets the layout
114
     * @return string|null
115
     */
116
    public function getLayout(): ?string
117
    {
118
        return $this->layoutFile;
119
    }
120
121
    /**
122
     * Sets view parameter
123
     * @param string $key
124
     * @param mixed $value
125
     */
126
    public function setParam(string $key, $value)
127
    {
128
        $this->params[$key] = $value;
129
    }
130
131
    /**
132
     * @param string $key
133
     * @param $value
134
     * @return void
135
     */
136
    public function setRawParam(string $key, $value)
137
    {
138
        $this->params[$key] = new RawParam($value);
139
    }
140
141
    /**
142
     * Gets the view parameter
143
     * @param string $key
144
     * @return mixed|null
145
     */
146
    public function getParam(string $key)
147
    {
148
        $param = $this->params[$key] ?? null;
149
150
        if ($param instanceof RawParam) {
151
            return $param->getValue();
152
        }
153
154
        return $param;
155
    }
156
157
    /**
158
     * Sets multiple view parameters
159
     * @param array $params
160
     */
161
    public function setParams(array $params)
162
    {
163
        foreach ($params as $key => $value) {
164
            $this->setParam($key, $value);
165
        }
166
    }
167
168
    /**
169
     * Gets all view parameters
170
     * @return array
171
     */
172
    public function getParams(): array
173
    {
174
        $params = [];
175
176
        foreach ($this->params as $key => $param) {
177
            $params[$key] = ($param instanceof RawParam) ? $param->getValue() : $param;
178
        }
179
180
        return $params;
181
    }
182
183
    /**
184
     * Flushes the view params
185
     */
186
    public function flushParams()
187
    {
188
        $this->params = [];
189
    }
190
191
    /**
192
     * Renders the view.
193
     * @param string $viewFile
194
     * @param array $params
195
     * @return string|null
196
     * @throws AssetException
197
     * @throws BaseException
198
     * @throws ConfigException
199
     * @throws DatabaseException
200
     * @throws DiException
201
     * @throws ReflectionException
202
     * @throws SessionException
203
     * @throws ViewException
204
     */
205
    public function render(string $viewFile, array $params = []): ?string
206
    {
207
        if (!$this->layoutFile) {
208
            throw ViewException::noLayoutSet();
209
        }
210
211
        if (!empty($params)) {
212
            $this->params = array_merge($this->params, $params);
213
        }
214
215
        $this->viewContent = $this->renderFile($viewFile);
216
217
        if (!empty($this->assets)) {
218
            $this->assetManager->register($this->assets);
219
        }
220
221
        if ($this->debugger->isEnabled()) {
222
            $this->updateDebugger($viewFile);
223
        }
224
225
        $layoutContent = $this->renderFile($this->layoutFile);
226
227
        if ($this->viewCache->isEnabled()) {
228
            $layoutContent = $this->viewCache
229
                ->set(route_uri(), $layoutContent)
230
                ->get(route_uri());
231
        }
232
233
        return $layoutContent;
234
    }
235
236
    /**
237
     * Renders partial view.
238
     * @param string $viewFile
239
     * @param array $params
240
     * @return string
241
     */
242
    public function renderPartial(string $viewFile, array $params = []): string
243
    {
244
        if (!empty($params)) {
245
            $this->params = array_merge($this->params, $params);
246
        }
247
248
        return $this->renderFile($viewFile);
249
    }
250
251
    /**
252
     * Gets the rendered view.
253
     * @return string|null
254
     * @throws ViewException
255
     */
256
    public function getView(): ?string
257
    {
258
        if ($this->viewContent === null) {
259
            throw ViewException::viewNotRendered();
260
        }
261
262
        return $this->viewContent;
263
    }
264
265
    /**
266
     * Renders the view
267
     * @param string $viewFile
268
     * @return string
269
     */
270
    private function renderFile(string $viewFile): string
271
    {
272
        $filteredParams = $this->xssFilter($this->params);
273
274
        return $this->renderer->render($viewFile, $filteredParams);
275
    }
276
277
    /**
278
     * XSS Filter
279
     * @param mixed $params
280
     * @return mixed
281
     */
282
    private function xssFilter($params)
283
    {
284
        if ($params instanceof RawParam) {
285
            return $params->getValue();
286
        }
287
288
        if (is_string($params)) {
289
            return $this->sanitizeHtml($params);
290
        }
291
292
        if (is_array($params)) {
293
            foreach ($params as $key => $value) {
294
                $params[$key] = $this->xssFilter($value);
295
            }
296
297
            return $params;
298
        }
299
300
        if (is_object($params)) {
301
            foreach (get_object_vars($params) as $property => $value) {
302
                $params->$property = $this->xssFilter($value);
303
            }
304
305
            return $params;
306
        }
307
308
        return $params;
309
    }
310
311
    /**
312
     * @param string $value
313
     * @return string
314
     */
315
    private function sanitizeHtml(string $value): string
316
    {
317
        return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
318
    }
319
320
    /**
321
     * @param string $viewFile
322
     * @return void
323
     */
324
    private function updateDebugger(string $viewFile)
325
    {
326
        $routesCell = $this->debugger->getStoreCell(Debugger::ROUTES);
327
        $currentData = current($routesCell)[LogLevel::INFO] ?? [];
328
        $additionalData = ['View' => current_module() . '/Views/' . $viewFile];
329
        $mergedData = array_merge($currentData, $additionalData);
330
        $this->debugger->clearStoreCell(Debugger::ROUTES);
331
        $this->debugger->addToStoreCell(Debugger::ROUTES, LogLevel::INFO, $mergedData);
332
    }
333
}