View::renderViews()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 11
ccs 5
cts 5
cp 1
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
crap 2
1
<?php
2
namespace Zewa;
3
4
use Zewa\HTTP\Request;
5
6
/**
7
 * View management
8
 *
9
 * @author Zechariah Walden<zech @ zewadesign.com>
10
 */
11
class View
12
{
13
    /**
14
     * Active layout for view
15
     *
16
     * @var string|bool
17
     */
18
    protected $layout;
19
20
    private $pathToView;
21
22
    private $pathToLayout;
23
24
    /** @var  array */
25
    protected $viewQueue = [];
26
27
    /**
28
     * Rendered view content
29
     *
30
     * @var string
31
     */
32
    protected $view = false;
33
34
    /**
35
     * Data object for view
36
     *
37
     * @var object
38
     */
39
    protected $properties;
40
41
    /**
42
     * \Zewa\Config reference
43
     *
44
     * @var Config
45
     */
46
    protected $configuration;
47
48
    /**
49
     * \Zewa\Router reference
50
     *
51
     * @var Router
52
     */
53
    protected $router;
54
55
    /**
56
     * \Zewa\Router reference
57
     *
58
     * @var Router
59
     */
60
    protected $request;
61
62
    /** @var Container  */
63
    protected $container;
64
65
    /**
66
     * @var array
67
     */
68
    private $queuedJS = [];
69
70
    /**
71
     * @var array
72
     */
73
    private $queuedCSS = [];
74
75
    /**
76
     * Load up some basic configuration settings.
77
     */
78 11
    public function __construct(Config $config, Router $router, Request $request, Container $container)
79
    {
80 11
        $this->configuration = $config->get('view');
0 ignored issues
show
Documentation Bug introduced by
It seems like $config->get('view') of type object<stdClass> is incompatible with the declared type object<Zewa\Config> of property $configuration.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
81 11
        $this->router = $router;
82 11
        $this->request = $request;
0 ignored issues
show
Documentation Bug introduced by
It seems like $request of type object<Zewa\HTTP\Request> is incompatible with the declared type object<Zewa\Router> of property $request.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
83 11
        $this->container = $container;
84
85 11
        $this->pathToView = $this->configuration['viewPath'];
86 11
        $this->pathToLayout = $this->configuration['layoutPath'];
87 11
    }
88
89
    /*
90
     * @todo create method for returning
91
     * a valid json string with header..
92
     * view shouldn't set header logic,
93
     * and the framework doesn't care what returns the string
94
     * ..but view should handle the json_encode...
95
     * seems overkill to call header() with returning a $view->json;
96
     * thoughts?*/
97
98
    /**
99
     * Loads a view
100
     *
101
     * @access public
102
     * @param string|bool $view view to load
103
     * @param string|bool $layout
104
     * @return string
105
     */
106 6
    public function render($view = false, $layout = false)
107
    {
108 6
        if ($layout !== false) {
109 2
            $this->setLayout($layout);
110
        }
111
112 5
        if ($view !== false) {
113 3
            $this->setView($view);
114
        }
115
116 4
        return $this->bufferResponse();
117
    }
118
119
    /**
120
     * formats and prepares view for inclusion
121
     * @param $viewName
122
     * @return string
123
     * @throws Exception\LookupException
124
     */
125 5
    public function setView($viewName)
126
    {
127 5
        $view = $this->pathToView . DIRECTORY_SEPARATOR . strtolower($viewName) . '.php';
128
129 5
        if (!file_exists($view)) {
130 1
            throw new Exception\LookupException('View: "' . $view . '" could not be found.');
131
        }
132
133 4
        $this->viewQueue[$viewName] = $view;
134 4
    }
135
136 1
    public function getView($view = null)
137
    {
138 1
        if ($view !== null) {
139 1
            return $this->viewQueue[$view];
140
        } else {
141 1
            return $this->viewQueue;
142
        }
143
    }
144
145 2
    public function setProperty($value, $primitive = null)
146
    {
147 2
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
148
149 2
        if ($primitive === null) {
150 1
            $container = $value;
151
        } else {
152 2
            $container[$value] = $primitive;
153
        }
154
155 2
        $this->container->set('view_properties', $container);
156 2
    }
157
158 1
    public function getProperty(string $key = null, $default = null)
159
    {
160 1
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
161
162 1
        if ($key === null) {
163 1
            return $container;
164
        }
165
166 1
        return $this->container->get('view_properties')[$key] ?? $default;
167
    }
168
169 1
    public function unsetProperty(string $key)
170
    {
171 1
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
172 1
        if (!empty($container[$key])) {
173 1
            unset($container[$key]);
174 1
            $this->container->set('view_properties', $container);
175
        }
176 1
    }
177
178 5
    public function setLayout($layout = null)
179
    {
180 5
        if ($layout === null) {
181 1
            $this->layout = null;
182 1
            return;
183
        }
184
185 5
        $layout = $this->pathToLayout . DIRECTORY_SEPARATOR . strtolower($layout) . '.php';
186
187 5
        if (!file_exists($layout)) {
188 1
            throw new Exception\LookupException('Layout: "' . $layout . '" could not be found.');
189
        }
190
191 4
        $this->layout = $layout;
192
193 4
        return;
194
    }
195
196 1
    public function getLayout()
197
    {
198 1
        return $this->layout;
199
    }
200
201 4
    private function renderViews() : string
202
    {
203 4
        $views = "";
204
205 4
        foreach ($this->viewQueue as $view) {
206
            //if not end.. otherwise include \r\n
207 3
            $views .= $this->buffer($view);
208
        }
209
210 4
        return $views;
211
    }
212
213 4
    private function bufferResponse() : string
214
    {
215 4
        $this->view = $this->renderViews();
216
217 4
        if ($this->layout !== null) {
218 3
            return $this->buffer($this->layout);
0 ignored issues
show
Bug introduced by
It seems like $this->layout can also be of type boolean; however, Zewa\View::buffer() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
219
        }
220
221 1
        return $this->view;
222
    }
223
224 4
    private function buffer(string $path)
225
    {
226
227 4
        ob_start();
228
229 4
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
230
231 4
        if (!empty($container)) {
232 1
            extract($container); // yuck. could produce undeclared errors. hmm..
233
        }
234
        //should i set $this->data in abstract controller, and provide all access vars ? seems bad practice..
235
236 4
        include $path;
237 4
        $response = ob_get_contents();
238 4
        ob_end_clean();
239
240 4
        return $response;
241
    }
242
243
    /**
244
     * Helper method for grabbing aggregated css files
245
     *
246
     * @access protected
247
     * @return string css includes
248
     */
249 2
    public function fetchCSS()
250
    {
251 2
        $string = "";
252
253 2
        if (empty($this->queuedCSS)) {
254 1
            return $string;
255
        }
256
257 1
        foreach ($this->queuedCSS as $sheet) {
258 1
            $string .= '<link rel="stylesheet" href="' . $sheet .'">' . "\r\n";
259
        }
260
261 1
        return $string;
262
    }
263
264
    /**
265
     * Helper method for grabbing aggregated JS files
266
     *
267
     * @access protected
268
     * @return string JS includes
269
     */
270 2
    public function fetchJS()
271
    {
272 2
        $string = "<script>baseURL = '" . $this->router->baseURL() . "/'</script>\r\n";
273
274 2
        if (empty($this->queuedJS)) {
275 1
            return $string;
276
        }
277
278 1
        foreach ($this->queuedJS as $script) {
279 1
            $string .= '<script src="' . $script . '"></script>' . "\r\n";
280
        }
281
282 1
        return $string;
283
    }
284
285
    /**
286
     * Helper method for adding css files for aggregation/render
287
     *
288
     * @access public
289
     * @param $files array
290
     */
291 1
    public function addCSS($files = [])
292
    {
293 1
        $this->queuedCSS = array_merge($files, $this->queuedCSS);
294 1
    }
295
296 1
    public function addJS($files = [])
297
    {
298 1
        $this->queuedJS = array_merge($files, $this->queuedJS);
299 1
    }
300
301
    /**
302
     * Set 404 header, and return 404 view contents
303
     *
304
     * @access public
305
     * @return string
306
     */
307 1
    public function render404()
308
    {
309 1
        header('HTTP/1.1 404 Not Found');
310 1
        $this->setLayout('404');
311 1
        return $this->render();
312
    }
313
}
314