Passed
Pull Request — master (#178)
by
unknown
04:06
created

QtView   A

Complexity

Total Complexity 27

Size/Duplication

Total Lines 240
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 54
c 1
b 0
f 0
dl 0
loc 240
rs 10
wmc 27

14 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A flushParams() 0 3 1
A getLayout() 0 3 1
A getParams() 0 3 1
A setLayout() 0 4 1
A setParam() 0 3 1
A getParam() 0 3 1
A setParams() 0 4 2
A cleaner() 0 6 2
A renderFile() 0 16 3
A getView() 0 3 1
A xssFilter() 0 10 2
A renderPartial() 0 7 2
B render() 0 29 7
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.0
13
 */
14
15
namespace Quantum\Mvc;
16
17
use Quantum\Libraries\ResourceCache\ViewCache;
18
use Quantum\Libraries\Asset\AssetManager;
19
use Quantum\Exceptions\DatabaseException;
20
use Quantum\Exceptions\SessionException;
21
use Quantum\Exceptions\ConfigException;
22
use Quantum\Exceptions\AssetException;
23
use Quantum\Exceptions\LangException;
24
use Quantum\Exceptions\ViewException;
25
use Quantum\Renderer\DefaultRenderer;
26
use Quantum\Exceptions\DiException;
27
use Quantum\Renderer\TwigRenderer;
28
use Quantum\Factory\ViewFactory;
29
use Quantum\Debugger\Debugger;
30
use Twig\Error\RuntimeError;
31
use Twig\Error\LoaderError;
32
use Twig\Error\SyntaxError;
33
use ReflectionException;
34
use Psr\Log\LogLevel;
35
36
/**
37
 * Class QtView
38
 * @package Quantum\Mvc
39
 */
40
class QtView
41
{
42
43
    /**
44
     * Layout file
45
     * @var string
46
     */
47
    private $layout = null;
48
49
    /**
50
     * Rendered view
51
     * @var string
52
     */
53
    private $view = null;
54
55
    /**
56
     * Assets to be included
57
     * @var array
58
     */
59
    private $assets = [];
60
61
    /**
62
     * View params
63
     * @var array
64
     */
65
    private $params = [];
66
67
    /**
68
     * QtView constructor.
69
     * @throws ViewException
70
     */
71
    public function __construct()
72
    {
73
        if (get_caller_class() != ViewFactory::class) {
74
            throw ViewException::directInstantiation(ViewFactory::class);
75
        }
76
    }
77
78
    /**
79
     * Sets a layout
80
     * @param string|null $layout
81
     * @param array $assets
82
     */
83
    public function setLayout(?string $layout, array $assets = [])
84
    {
85
        $this->layout = $layout;
86
        $this->assets = $assets;
87
    }
88
89
    /**
90
     * Gets the layout
91
     * @return string|null
92
     */
93
    public function getLayout(): ?string
94
    {
95
        return $this->layout;
96
    }
97
98
    /**
99
     * Sets view parameter
100
     * @param string $key
101
     * @param mixed $value
102
     */
103
    public function setParam(string $key, $value)
104
    {
105
        $this->params[$key] = $value;
106
    }
107
108
    /**
109
     * Gets the view parameter
110
     * @param string $key
111
     * @return mixed|null
112
     */
113
    public function getParam(string $key)
114
    {
115
        return $this->params[$key] ?? null;
116
    }
117
118
    /**
119
     * Sets multiple view parameters
120
     * @param array $params
121
     */
122
    public function setParams(array $params)
123
    {
124
        foreach ($params as $key => $value) {
125
            $this->setParam($key, $value);
126
        }
127
    }
128
129
    /**
130
     * Gets all view parameters
131
     * @return array
132
     */
133
    public function getParams(): array
134
    {
135
        return $this->params;
136
    }
137
138
    /**
139
     * Flushes the view params
140
     */
141
    public function flushParams()
142
    {
143
        $this->params = [];
144
    }
145
146
	/**
147
	 * @param string $view
148
	 * @param array $params
149
	 * @return string|null
150
	 * @throws AssetException
151
	 * @throws DiException
152
	 * @throws LangException
153
	 * @throws LoaderError
154
	 * @throws ReflectionException
155
	 * @throws RuntimeError
156
	 * @throws SyntaxError
157
	 * @throws ViewException
158
	 * @throws ConfigException
159
	 * @throws DatabaseException
160
	 * @throws SessionException
161
	 */
162
    public function render(string $view, array $params = []): ?string
163
    {
164
        if (!$this->layout) {
165
            throw ViewException::noLayoutSet();
166
        }
167
168
        if (!empty($params)) {
169
            $this->params = array_merge($this->params, $params);
170
        }
171
172
        $this->view = $this->renderFile($view);
173
174
        if (filter_var(config()->get('debug'), FILTER_VALIDATE_BOOLEAN)) {
175
            Debugger::updateStoreCell(Debugger::ROUTES, LogLevel::INFO, ['View' => current_module() . '/Views/' . $view]);
176
        }
177
178
        if(!empty($this->assets)) {
179
            AssetManager::getInstance()->register($this->assets);
180
        }
181
182
		$content = $this->renderFile($this->layout);
183
184
	    if (($cacheSettings = route_cache_settings()) && session()->getId()){
185
		    $content = (new ViewCache())
186
			    ->set(route_uri(), $content, session()->getId())
0 ignored issues
show
Bug introduced by
It seems like session()->getId() can also be of type null; however, parameter $sessionId of Quantum\Libraries\ResourceCache\ViewCache::set() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

186
			    ->set(route_uri(), $content, /** @scrutinizer ignore-type */ session()->getId())
Loading history...
187
			    ->get(route_uri(), session()->getId(), $cacheSettings['ttl']);
0 ignored issues
show
Bug introduced by
It seems like session()->getId() can also be of type null; however, parameter $sessionId of Quantum\Libraries\ResourceCache\ViewCache::get() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

187
			    ->get(route_uri(), /** @scrutinizer ignore-type */ session()->getId(), $cacheSettings['ttl']);
Loading history...
188
	    }
189
190
        return $content;
191
    }
192
193
    /**
194
     * Renders partial view
195
     * @param string $view
196
     * @param array $params
197
     * @return string|null
198
     * @throws DiException
199
     * @throws ViewException
200
     * @throws ReflectionException
201
     * @throws LoaderError
202
     * @throws RuntimeError
203
     * @throws SyntaxError
204
     */
205
    public function renderPartial(string $view, array $params = []): ?string
206
    {
207
        if (!empty($params)) {
208
            $this->params = array_merge($this->params, $params);
209
        }
210
211
        return $this->renderFile($view);
212
    }
213
214
    /**
215
     * Gets the rendered view
216
     * @return string|null
217
     */
218
    public function getView(): ?string
219
    {
220
        return $this->view;
221
    }
222
223
    /**
224
     * Renders the view
225
     * @param string $view
226
     * @return string
227
     * @throws DiException
228
     * @throws ViewException
229
     * @throws ReflectionException
230
     * @throws LoaderError
231
     * @throws RuntimeError
232
     * @throws SyntaxError
233
     */
234
    private function renderFile(string $view): string
235
    {
236
        $params = $this->xssFilter($this->params);
237
238
        $templateEngine = config()->get('template_engine');
239
240
        if ($templateEngine) {
241
            $configs = config()->get('template_engine.' . key($templateEngine));
242
243
            if (!$configs) {
244
                throw ViewException::missingTemplateEngineConfigs();
245
            }
246
247
            return (new TwigRenderer())->render($view, $params, $configs);
248
        } else {
249
            return (new DefaultRenderer())->render($view, $params);
250
        }
251
    }
252
253
    /**
254
     * XSS Filter
255
     * @param mixed $params
256
     * @return mixed
257
     */
258
    private function xssFilter($params)
259
    {
260
        if (is_string($params)) {
261
            $this->cleaner($params);
262
            $params = [$params];
263
        } else {
264
            array_walk_recursive($params, [$this, 'cleaner']);
265
        }
266
267
        return $params;
268
    }
269
270
    /**
271
     * Cleaner
272
     * @param mixed $value
273
     */
274
    private function cleaner(&$value)
275
    {
276
        if (is_object($value)) {
277
            $this->xssFilter($value);
278
        } else {
279
            $value = htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
280
        }
281
    }
282
}
283