Completed
Push — master ( 27437d...683447 )
by Nikita
04:20
created

View::innerOutput()   B

Complexity

Conditions 6
Paths 8

Size

Total Lines 38
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 20
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 1
Metric Value
c 1
b 0
f 1
dl 0
loc 38
ccs 20
cts 20
cp 1
rs 8.439
cc 6
eloc 18
nc 8
nop 3
crap 6
1
<?php
2
/**
3
 * Created by Vitaly Iegorov <[email protected]>.
4
 * on 18.02.16 at 14:15
5
 */
6
namespace samsonframework\view;
7
8
use samsonframework\core\RenderInterface;
9
use samsonframework\core\ViewInterface;
10
use samsonframework\view\exception\VariableKeyNotFound;
11
use samsonframework\view\exception\ViewClassNotFound;
12
use samsonframework\view\exception\ViewFileNotFound;
13
14
/**
15
 * View class for rendering.
16
 * @package samsonframework\view
17
 */
18
class View implements ViewInterface
19
{
20
    /** Default view file extension */
21
    const DEFAULT_EXT = 'vphp';
22
23
    /** @var array Collection of $key => $value view data */
24
    protected $data = array();
25
26
    /** @var string Full path to view file */
27
    protected $file;
28
29
    /** @var string View source code */
30
    protected $source;
31
32
    /** @var string Rendered view contents */
33
    protected $output;
34
35
    /** @var string Parent view block name */
36
    protected $parentBlock;
37
38
    /** @var array Collection of view blocks */
39
    protected $blocks = array();
40
41
    /** @var array Blocks html list */
42
    protected $blocksHtml = array();
43
44
    /**
45
     * Set current view for rendering.
46
     * Method searches for the shortest matching view path by $pathPattern,
47
     * from loaded views.
48
     *
49
     * Module saves all view data that has been set to a specific view in appropriate
50
     * view data collection entry. By default module creates vied data entry - VD_POINTER_DEF,
51
     * and until any call of iModule::view() or iModule::output(), all data that is iModule::set(),
52
     * is stored to that location.
53
     *
54
     * On the first call of iModule::view() or iModule::output(), this method changes the view data
55
     * pointer to actual relative view path, and copies(actually just sets view data pointer) all view
56
     * data set before to new view data pointer. This guarantees backward compatibility and gives
57
     * opportunity not to set the view path before setting view data to it.
58
     *
59
     * @param string $pathPattern Path pattern for view searching
60
     *
61
     * @return $this Chaining
62
     * @throws \Exception
63
     */
64 2
    public function view($pathPattern)
65
    {
66 2
        if (file_exists($pathPattern)) {
67 2
            $this->file = $pathPattern;
68 2
            return $this;
69
        }
70
71 1
        throw new ViewFileNotFound($pathPattern);
72
    }
73
74
    /**
75
     * Render current view.
76
     * Method uses current view context and outputs rendering
77
     * result.
78
     *
79
     * @param bool $onlyCurrent Render only current view without extends
80
     * @return string Rendered view
81
     */
82 3
    public function output($onlyCurrent = false)
83
    {
84 3
        $this->innerOutput($onlyCurrent);
85
86
        // Returned rendered view
87 3
        return $this->output;
88
    }
89
90
91
    /**
92
     * Render full views stack
93
     *
94
     * @param bool $onlyCurrent Render only current view without extends
95
     * @return string Rendered view
96
     */
97 3
    public function innerOutput($onlyCurrent = false ,$blocksList = array(), $data = array())
0 ignored issues
show
Coding Style introduced by
Expected 0 spaces between argument "$onlyCurrent" and comma; 1 found
Loading history...
Coding Style introduced by
Expected 1 space between comma and argument "$blocksList"; 0 found
Loading history...
98
    {
99
        //Set blocks html list
100 3
        $this->blocksHtml = $blocksList;
101
        // Merge current view's data with child view's data
102 3
        $data = array_merge($this->data, $data);
103
        // Start buffering
104 3
        ob_start();
105
106
        // Make variables accessible directly in view
107 3
        extract($data);
108
109
        // Render view from source
110 3
        if (!empty($this->source)) {
111 2
            eval(' ?>' . $this->source . '<?php ');
112 2
        } else { // Render view from file
113 1
            include($this->file);
114
        }
115
116
        // Store buffer output
117 3
        $this->output = ob_get_contents();
118
119
        // Clear buffer
120 3
        ob_end_clean();
121
122
        // Remove variables from context to free memory
123 3
        foreach ($this->data as $key => $value) {
124 3
            unset($key);
125 3
        }
126
127
        // Render parent view stack
128 3
        $parentClass = get_parent_class($this);
129 3
        if ($parentClass && !empty($this->parentBlock) && !$onlyCurrent) {
130 1
            $blocksList = array_merge($blocksList, array($this->parentBlock=>$this->output));
131 1
            $this->output = (new $parentClass())->innerOutput($onlyCurrent, $blocksList, $data);
132 1
        }
133 3
        return $this->output;
134
    }
135
136
    /**
137
     * Magic method for getting view variables.
138
     *
139
     * @param string $name Variable key
140
     *
141
     * @return mixed Value
142
     * @throws VariableKeyNotFound
143
     */
144 5
    public function __get($name)
145
    {
146 5
        if (array_key_exists($name, $this->data)) {
147 5
            return $this->data[$name];
148
        }
149
150 1
        throw new VariableKeyNotFound($name);
151
    }
152
153
    /**
154
     * Set current view parent rendering view and block.
155
     *
156
     * @param string $parent Fully qualified parent view name
157
     * @param string $block  View block for rendering in parent view
158
     *
159
     * @throws ViewClassNotFound
160
     */
161 1
    public function extend($parent, $block)
0 ignored issues
show
Unused Code introduced by
The parameter $parent is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $block is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
162
    {
163
        //$parent = new $parent();
164
        //$parent->output();
165
166
        //throw new ViewClassNotFound($parent);
167 1
    }
168
169
    /**
170
     * Set current view nested block rendering view.
171
     *
172
     * @param string $blockName Nested view block container
173
     */
174 1
    public function block($blockName)
175
    {
176 1
        if (isset($this->blocksHtml[$blockName])) {
177 1
            echo $this->blocksHtml[$blockName];
178 1
        }
179 1
    }
180
181
    /**
182
     * Magic method for setting view variables.
183
     *
184
     * @param string $name      Variable key
185
     * @param array  $arguments Variable value
186
     *
187
     * @return $this Chaining
188
     * @throws VariableKeyNotFound
189
     */
190 1
    public function __call($name, $arguments)
191
    {
192 1
        if (count($arguments)) {
193 1
            $this->set($arguments[0], $name);
194 1
        }
195
196 1
        return $this;
197
    }
198
199
    /**
200
     * Set view variable.
201
     *
202
     * Passing an array as $value will add array key => values into current
203
     * view data collection. If $key is passed then an array variable with this
204
     * key will be added to view data collection beside adding array key => values.
205
     *
206
     * @param mixed       $value Variable value
207
     * @param string|null $key   Variable key\prefix for objects and arrays
208
     *
209
     * @return $this Chaining
210
     */
211 7
    public function set($value, $key = null)
212
    {
213
        // RenderInterface implementation
214 7
        if (is_object($value) && is_a($value, RenderInterface::class)) {
215 3
            $this->setRenderableObject($value, $key);
216 7
        } elseif (is_array($value)) { // Merge array into view data
217 3
            $this->data = array_merge($this->data, $value);
218 3
        }
219
220
        // Store key value
221 7
        $this->data[$key] = $value;
222
223 7
        return $this;
224
    }
225
226
227
    /**
228
     * Set renderable object as view variable.
229
     *
230
     * @param mixed       $object Object instance for rendering
231
     * @param string|null $key    Variable key\prefix for objects and arrays
232
     */
233 3
    protected function setRenderableObject($object, $key)
234
    {
235
        /** @var RenderInterface $object */
236
        // Generate objects view array data and merge it with view data
237 3
        $this->data = array_merge(
238 3
            $this->data,
239 3
            $object->toView(null !== $key ? $key : get_class($object))
240 3
        );
241 3
    }
242
}
243