Completed
Pull Request — master (#101)
by
unknown
02:57
created

View::getLayout()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
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
    public function __construct(Config $config, Router $router, Request $request, Container $container)
79
    {
80
        $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
        $this->router = $router;
82
        $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
        $this->container = $container;
84
85
        $this->pathToView = $this->configuration['viewPath'];
86
        $this->pathToLayout = $this->configuration['layoutPath'];
87
    }
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
    public function render($view = false, $layout = false)
107
    {
108
        if ($layout !== false) {
109
            $this->setLayout($layout);
110
        }
111
112
        if ($view !== false) {
113
            $this->setView($view);
114
        }
115
116
        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
    public function setView($viewName)
126
    {
127
        $view = $this->pathToView . DIRECTORY_SEPARATOR . strtolower($viewName) . '.php';
128
129
        if (!file_exists($view)) {
130
            throw new Exception\LookupException('View: "' . $view . '" could not be found.');
131
        }
132
133
        $this->viewQueue[$viewName] = $view;
134
    }
135
136
    public function getView($view = null)
137
    {
138
        if ($view !== null) {
139
            return $this->viewQueue[$view];
140
        } else {
141
            return $this->viewQueue;
142
        }
143
    }
144
145
    public function setProperty(string $key, $value)
146
    {
147
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
148
        $container[$key] = $value;
149
        $this->container->set('view_properties', $container);
150
    }
151
152
    public function getProperty(string $key = null, $default = null)
153
    {
154
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
155
156
        if ($key === null) {
157
            return $container;
158
        }
159
160
        return $this->container->get('view_properties')[$key] ?? $default;
161
    }
162
163
    public function unsetProperty(string $key)
164
    {
165
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
166
        if (!empty($container[$key])) {
167
            unset($container[$key]);
168
            $this->container->set('view_properties', $container);
169
        }
170
    }
171
172
    public function setLayout($layout = null)
173
    {
174
        if ($layout === null) {
175
            $this->layout = null;
176
            return;
177
        }
178
179
        $layout = $this->pathToLayout . DIRECTORY_SEPARATOR . strtolower($layout) . '.php';
180
181
        if (!file_exists($layout)) {
182
            throw new Exception\LookupException('Layout: "' . $layout . '" could not be found.');
183
        }
184
185
        $this->layout = $layout;
186
187
        return;
188
    }
189
190
    public function getLayout()
191
    {
192
        return $this->layout;
193
    }
194
195
    private function renderViews() : string
196
    {
197
        $views = "";
198
199
        foreach ($this->viewQueue as $view) {
200
            //if not end.. otherwise include \r\n
201
            $views .= $this->buffer($view);
202
        }
203
204
        return $views;
205
    }
206
207
    private function bufferResponse() : string
208
    {
209
        $this->view = $response = $this->renderViews();
210
211
        if ($this->layout !== null) {
212
            $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
        return $response;
216
    }
217
218
    private function buffer(string $path) : string
219
    {
220
        $container = $this->container->has('view_properties') ? $this->container->get('view_properties') : [];
221
222
        ob_start();
223
        if (!empty($container)) {
224
            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
        include $path;
229
230
        $result = ob_get_contents();
231
        ob_end_clean();
232
233
        return $result;
234
    }
235
236
    /**
237
     * Helper method for grabbing aggregated css files
238
     *
239
     * @access protected
240
     * @return string css includes
241
     */
242
    public function fetchCSS()
243
    {
244
        $string = "";
245
246
        if (empty($this->queuedCSS)) {
247
            return $string;
248
        }
249
250
        foreach ($this->queuedCSS as $sheet) {
251
            $string .= '<link rel="stylesheet" href="' . $sheet .'">' . "\r\n";
252
        }
253
254
        return $string;
255
    }
256
257
    /**
258
     * Helper method for grabbing aggregated JS files
259
     *
260
     * @access protected
261
     * @return string JS includes
262
     */
263
    public function fetchJS()
264
    {
265
        $string = "<script>baseURL = '" . $this->router->baseURL() . "/'</script>\r\n";
266
267
        if (empty($this->queuedJS)) {
268
            return $string;
269
        }
270
271
        foreach ($this->queuedJS as $script) {
272
            $string .= '<script type="javascript/text" src="' . $script . '"></script>' . "\r\n";
273
        }
274
275
        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 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
        if ($place === 'prepend') {
288
            $this->queuedCSS = array_merge($files, $this->queuedCSS);
289
        } else {
290
            $this->queuedCSS = array_merge($this->queuedCSS, $files);
291
        }
292
    }
293
294 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
        if ($place === 'prepend') {
297
            $this->queuedJS = array_merge($files, $this->queuedJS);
298
        } else {
299
            $this->queuedJS = array_merge($this->queuedJS, $files);
300
        }
301
    }
302
303
    /**
304
     * Set 404 header, and return 404 view contents
305
     *
306
     * @access public
307
     * @return string
308
     */
309
    public function render404()
310
    {
311
        header('HTTP/1.1 404 Not Found');
312
        $this->setLayout('404');
313
        return $this->render();
314
    }
315
}
316