Completed
Push — master ( bd6151...e9b616 )
by
unknown
30s
created

View::getLayout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
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(string $key, $value)
146
    {
147 2
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
148 2
        $container[$key] = $value;
149 2
        $this->container->set('view_properties', $container);
150 2
    }
151
152 1
    public function getProperty(string $key = null, $default = null)
153
    {
154 1
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
155
156 1
        if ($key === null) {
157 1
            return $container;
158
        }
159
160 1
        return $this->container->get('view_properties')[$key] ?? $default;
161
    }
162
163 1
    public function unsetProperty(string $key)
164
    {
165 1
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
166 1
        if (!empty($container[$key])) {
167 1
            unset($container[$key]);
168 1
            $this->container->set('view_properties', $container);
169
        }
170 1
    }
171
172 5
    public function setLayout($layout = null)
173
    {
174 5
        if ($layout === null) {
175 1
            $this->layout = null;
176 1
            return;
177
        }
178
179 5
        $layout = $this->pathToLayout . DIRECTORY_SEPARATOR . strtolower($layout) . '.php';
180
181 5
        if (!file_exists($layout)) {
182 1
            throw new Exception\LookupException('Layout: "' . $layout . '" could not be found.');
183
        }
184
185 4
        $this->layout = $layout;
186
187 4
        return;
188
    }
189
190 1
    public function getLayout()
191
    {
192 1
        return $this->layout;
193
    }
194
195 4
    private function renderViews() : string
196
    {
197 4
        $views = "";
198
199 4
        foreach ($this->viewQueue as $view) {
200
            //if not end.. otherwise include \r\n
201 3
            $views .= $this->buffer($view);
202
        }
203
204 4
        return $views;
205
    }
206
207 4
    private function bufferResponse() : string
208
    {
209 4
        $this->view = $response = $this->renderViews();
210
211 4
        if ($this->layout !== null) {
212 3
            $response = $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...
213
        }
214
215 4
        return $response;
216
    }
217
218 4
    private function buffer(string $path) : string
219
    {
220 4
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
221
222 4
        ob_start();
223 4
        if (!empty($container)) {
224 1
            extract($container); // yuck. could produce undeclared errors. hmm..
225
        }
226
        //should i set $this->data in abstract controller, and provide all access vars ? seems bad practice..
227
228 4
        include $path;
229
230 4
        $result = ob_get_contents();
231 4
        ob_end_clean();
232
233 4
        return $result;
234
    }
235
236
    /**
237
     * Helper method for grabbing aggregated css files
238
     *
239
     * @access protected
240
     * @return string css includes
241
     */
242 2
    public function fetchCSS()
243
    {
244 2
        $string = "";
245
246 2
        if (empty($this->queuedCSS)) {
247 1
            return $string;
248
        }
249
250 1
        foreach ($this->queuedCSS as $sheet) {
251 1
            $string .= '<link rel="stylesheet" href="' . $sheet .'">' . "\r\n";
252
        }
253
254 1
        return $string;
255
    }
256
257
    /**
258
     * Helper method for grabbing aggregated JS files
259
     *
260
     * @access protected
261
     * @return string JS includes
262
     */
263 2
    public function fetchJS()
264
    {
265 2
        $string = "<script>baseURL = '" . $this->router->baseURL() . "/'</script>\r\n";
266
267 2
        if (empty($this->queuedJS)) {
268 1
            return $string;
269
        }
270
271 1
        foreach ($this->queuedJS as $script) {
272 1
            $string .= '<script type="javascript/text" src="' . $script . '"></script>' . "\r\n";
273
        }
274
275 1
        return $string;
276
    }
277
278
    /**
279
     * Helper method for adding css files for aggregation/render
280
     *
281
     * @access public
282
     * @param $files array
283
     * @param $place string
284
     */
285 2 View Code Duplication
    public function addCSS($files = [], $place = 'append')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
286
    {
287 2
        if ($place === 'prepend') {
288 2
            $this->queuedCSS = array_merge($files, $this->queuedCSS);
289
        } else {
290 2
            $this->queuedCSS = array_merge($this->queuedCSS, $files);
291
        }
292 2
    }
293
294 2 View Code Duplication
    public function addJS($files = [], $place = 'append')
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
295
    {
296 2
        if ($place === 'prepend') {
297 2
            $this->queuedJS = array_merge($files, $this->queuedJS);
298
        } else {
299 2
            $this->queuedJS = array_merge($this->queuedJS, $files);
300
        }
301 2
    }
302
303
    /**
304
     * Set 404 header, and return 404 view contents
305
     *
306
     * @access public
307
     * @return string
308
     */
309 1
    public function render404()
310
    {
311 1
        header('HTTP/1.1 404 Not Found');
312 1
        $this->setLayout('404');
313 1
        return $this->render();
314
    }
315
}
316