Completed
Push — master ( 242e65...f5b54f )
by
unknown
04:49 queued 02:03
created

View::render()   B

Complexity

Conditions 6
Paths 12

Size

Total Lines 28
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 4
Bugs 1 Features 0
Metric Value
c 4
b 1
f 0
dl 0
loc 28
ccs 0
cts 23
cp 0
rs 8.439
cc 6
eloc 16
nc 12
nop 2
crap 42
1
<?php
2
namespace Zewa;
3
use Zewa\HTTP\Request;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Zewa\Request.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
4
5
/**
6
 * View management
7
 *
8
 * @author Zechariah Walden<zech @ zewadesign.com>
9
 */
10
class View
11
{
12
    /**
13
     * Active layout for view
14
     *
15
     * @var string|bool
16
     */
17
    protected $layout;
18
19
    private $pathToView;
20
21
    private $pathToLayout;
22
23
24
    /**
25
     * Rendered view content
26
     *
27
     * @var string
28
     */
29
    protected $view = false;
30
31
    /**
32
     * Data object for view
33
     *
34
     * @var object
35
     */
36
    protected $properties;
37
38
    /**
39
     * \Zewa\Config reference
40
     *
41
     * @var Config
42
     */
43
    protected $configuration;
44
45
    /**
46
     * \Zewa\Router reference
47
     *
48
     * @var Router
49
     */
50
    protected $router;
51
52
    /**
53
     * \Zewa\Router reference
54
     *
55
     * @var Router
56
     */
57
    protected $request;
58
59
    /**
60
     * @var array
61
     */
62
    private $queuedJS = [];
63
64
    /**
65
     * @var array
66
     */
67
    private $queuedCSS = [];
68
69
    /**
70
     * Load up some basic configuration settings.
71
     */
72
    public function __construct(Config $config, Router $router, Request $request)
73
    {
74
        $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...
75
        $this->router = $router;
76
        $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...
77
78
        $this->pathToView = $this->configuration['viewPath'];
79
        $this->pathToLayout = $this->configuration['layoutPath'];
80
    }
81
82
    /**
83
     * Returns base URL for app
84
     * @return string
85
     */
86
    private function baseURL($path = '')
87
    {
88
        return $this->router->baseURL($path);
89
    }
90
91
    /*
92
     * @todo create method for returning
93
     * a valid json string with header..
94
     * view shouldn't set header logic,
95
     * and the framework doesn't care what returns the string
96
     * ..but view should handle the json_encode...
97
     * seems overkill to call header() with returning a $view->json;
98
     * thoughts?*/
99
100
    /**
101
     * Loads a view
102
     *
103
     * @access public
104
     * @param string|bool $view view to load
105
     * @param string|bool $layout
106
     * @return string
107
     */
108
    public function render($view = false, $layout = false)
109
    {
110
        if ($layout !== false) {
111
            $this->setLayout($layout);
112
        }
113
114
        if ($view !== false) {
115
            $view = $this->prepareView($view);
116
117
            $this->view = $return = $this->process($view);
118
119
            if (! is_null($this->layout)) {
120
                $return = $this->process($this->layout);
121
            }
122
123
            return $return;
124
        } else {
125
            if ($this->view !== false) {
126
                $this->view = $this->process($this->view);
127
            }
128
129
            if (! is_null($this->layout)) {
130
                return $this->process($this->layout);
131
            } else {
132
                return $this->view;
133
            }
134
        }
135
    }
136
137
    /**
138
     * formats and prepares view for inclusion
139
     * @param $viewName
140
     * @return string
141
     * @throws Exception\LookupException
142
     */
143
    private function prepareView($viewName)
144
    {
145
        $view = $this->pathToView . DIRECTORY_SEPARATOR . strtolower($viewName) . '.php';
146
147
        if (!file_exists($view)) {
148
            throw new Exception\LookupException('View: "' . $view . '" could not be found.');
149
        }
150
151
        return $view;
152
    }
153
154
    public function setView($viewName, $layout = false)
155
    {
156
        if ($layout !== false) {
157
            $this->setLayout($layout);
158
        }
159
        $this->view = $this->prepareView($viewName);
160
    }
161
162
    public function setProperty($property, $value = false)
163
    {
164
        if ($value !== false) {
165
            $this->properties[$property] = $value;
166
        } elseif (!empty($property)) {
167
            $this->properties = $property;
168
        }
169
        return false;
170
    }
171
172
    public function setLayout($layout)
173
    {
174
        if ($layout === false) {
175
            $this->layout = null;
176
        } else {
177
            $layout = $this->pathToLayout . DIRECTORY_SEPARATOR . strtolower($layout) . '.php';
178
179
            if (!file_exists($layout)) {
180
                throw new Exception\LookupException('Layout: "' . $layout . '" could not be found.');
181
            }
182
183
            $this->layout = $layout;
184
185
            return true;
186
        }
187
    }
188
189
    /**
190
     * Processes view/layouts and exposes variables to the view/layout
191
     *
192
     * @access private
193
     * @param string $file file being rendered
194
     * @return string processed content
195
     */
196
    //@TODO: come back and clean up this and the way the view receives stuff
197
    private function process($file)
198
    {
199
        ob_start();
200
201
        if (is_array($this->properties)) {
202
            extract($this->properties); // yuck. could produce undeclared errors. hmm..
203
        }
204
        //should i set $this->data in abstract controller, and provide all access vars ? seems bad practice..
205
206
        include $file;
207
208
        $return = ob_get_contents();
209
210
        ob_end_clean();
211
212
        return $return;
213
    }
214
215
    /**
216
     * Helper method for grabbing aggregated css files
217
     *
218
     * @access protected
219
     * @return string css includes
220
     */
221
    protected function fetchCSS()
222
    {
223
        $string = "";
224
225
        if (empty($this->queuedCSS)) {
226
            return $string;
227
        }
228
229
        foreach ($this->queuedCSS as $sheet) {
230
            $string .= '<link rel="stylesheet" href="' . $sheet .'">' . "\r\n";
231
        }
232
233
        return $string;
234
    }
235
236
    /**
237
     * Helper method for grabbing aggregated JS files
238
     *
239
     * @access protected
240
     * @return string JS includes
241
     */
242
    protected function fetchJS()
243
    {
244
        $string = "<script>baseURL = '" . $this->baseURL() . "/'</script>\r\n";
245
246
        if (empty($this->queuedJS)) {
247
            return $string;
248
        }
249
250
        foreach ($this->queuedJS as $script) {
251
            $string .= '<script src="' . $script . '"></script>' . "\r\n";
252
        }
253
254
        return $string;
255
    }
256
257
    /**
258
     * Helper method for adding css files for aggregation/render
259
     *
260
     * @access public
261
     * @param $files array
262
     * @param $place string
263
     * @return string css includes
264
     * @throws Exception\LookupException
265
     */
266 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...
267
    {
268
        if ($place === 'append') {
269
            $this->queuedCSS = array_merge($files, $this->queuedCSS);
270
        } else {
271
            $this->queuedCSS = array_merge($this->queuedCSS, $files);
272
        }
273
    }
274
275 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...
276
    {
277
        if ($place === 'append') {
278
            $this->queuedJS = array_merge($files, $this->queuedJS);
279
        } else {
280
            $this->queuedJS = array_merge($this->queuedJS, $files);
281
        }
282
    }
283
284
    /**
285
     * Set 404 header, and return 404 view contents
286
     *
287
     * @access public
288
     * @param  $data array
289
     * @return string
290
     */
291
    public function render404($data = [])
292
    {
293
        header('HTTP/1.1 404 Not Found');
294
        $this->setProperty($data);
295
        $this->setLayout('404');
296
        return $this->render();
297
    }
298
}
299