View   A
last analyzed

Complexity

Total Complexity 22

Size/Duplication

Total Lines 228
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 2

Test Coverage

Coverage 100%

Importance

Changes 13
Bugs 2 Features 7
Metric Value
wmc 22
c 13
b 2
f 7
lcom 2
cbo 2
dl 0
loc 228
ccs 58
cts 58
cp 1
rs 10

9 Methods

Rating   Name   Duplication   Size   Complexity  
A view() 0 9 2
A output() 0 7 1
B innerOutput() 0 43 6
A __get() 0 8 2
A extend() 0 4 1
A block() 0 6 2
A __call() 0 8 2
A set() 0 14 4
A setRenderableObject() 0 9 2
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\ViewFileNotFound;
12
13
/**
14
 * View class for rendering.
15
 * @package samsonframework\view
16
 */
17
class View implements ViewInterface
18
{
19
    /** Default view file extension */
20
    const DEFAULT_EXT = 'vphp';
21
22
    /** @var array Collection of $key => $value view data */
23
    protected $data = array();
24
25
    /** @var string Full path to view file */
26
    protected $file;
27
28
    /** @var string View source code */
29
    protected $source;
30
31
    /** @var string Rendered view contents */
32
    protected $output;
33
34
    /** @var string Parent view block name */
35
    protected $parentBlock;
36
37
    /** @var array Collection of view blocks */
38
    protected $blocks = array();
39
40
    /** @var array Blocks html list */
41
    protected $blocksHtml = array();
42
43
    /**
44
     * Set current view for rendering.
45
     * Method searches for the shortest matching view path by $pathPattern,
46
     * from loaded views.
47
     *
48
     * Module saves all view data that has been set to a specific view in appropriate
49
     * view data collection entry. By default module creates vied data entry - VD_POINTER_DEF,
50
     * and until any call of iModule::view() or iModule::output(), all data that is iModule::set(),
51
     * is stored to that location.
52
     *
53
     * On the first call of iModule::view() or iModule::output(), this method changes the view data
54
     * pointer to actual relative view path, and copies(actually just sets view data pointer) all view
55
     * data set before to new view data pointer. This guarantees backward compatibility and gives
56
     * opportunity not to set the view path before setting view data to it.
57
     *
58
     * @param string $pathPattern Path pattern for view searching
59
     *
60
     * @return $this Chaining
61
     * @throws \Exception
62
     */
63 2
    public function view($pathPattern)
64
    {
65 2
        if (file_exists($pathPattern)) {
66 2
            $this->file = $pathPattern;
67 2
            return $this;
68
        }
69
70 1
        throw new ViewFileNotFound($pathPattern);
71
    }
72
73
    /**
74
     * Render current view.
75
     * Method uses current view context and outputs rendering
76
     * result.
77
     *
78
     * @param bool $onlyCurrent Render only current view without extends
79
     * @return string Rendered view
80
     */
81 3
    public function output($onlyCurrent = false)
82
    {
83 3
        $this->innerOutput($onlyCurrent);
84
85
        // Returned rendered view
86 3
        return $this->output;
87
    }
88
89
90
    /**
91
     * Render full views stack.
92
     *
93
     * @param bool  $onlyCurrent Render only current view without extends
94
     * @param array $blocksList Block for rendering in the view
95
     * @param array $data View data collection
96
     *
97
     * @return string Rendered view
98
     */
99 3
    public function innerOutput($onlyCurrent = false, array $blocksList = array(), array $data = array())
100
    {
101
        //Set blocks html list
102 3
        $this->blocksHtml = $blocksList;
103
104
        // Merge current view's data with child view's data
105 3
        $data = array_merge($this->data, $data);
106
107
        // Start buffering
108 3
        ob_start();
109
110
        // Make variables accessible directly in view
111 3
        extract($data);
112
113
        // Render view from source
114 3
        if (!empty($this->source)) {
115 2
            eval(' ?>' . $this->source . '<?php ');
116 2
        } else { // Render view from file
117 1
            include($this->file);
118
        }
119
120
        // Store buffer output
121 3
        $this->output = ob_get_contents();
122
123
        // Clear buffer
124 3
        ob_end_clean();
125
126
        // Remove variables from context to free memory
127 3
        foreach ($this->data as $key => $value) {
128 3
            unset($key);
129 3
        }
130
131
        // Render parent view stack
132 3
        $parentClass = get_parent_class($this);
133 3
        if ($parentClass && !empty($this->parentBlock) && !$onlyCurrent) {
134
            // Merge blocks mode
135 1
            $blocksList = array_merge($blocksList, array($this->parentBlock => $this->output));
136
            // Go deeper in recursion with parent view passing rendered blocks collection
137 1
            $this->output = (new $parentClass())->innerOutput($onlyCurrent, $blocksList, $data);
138 1
        }
139
140 3
        return $this->output;
141
    }
142
143
    /**
144
     * Magic method for getting view variables.
145
     *
146
     * @param string $name Variable key
147
     *
148
     * @return mixed Value
149
     * @throws VariableKeyNotFound
150
     */
151 5
    public function __get($name)
152
    {
153 5
        if (array_key_exists($name, $this->data)) {
154 5
            return $this->data[$name];
155
        }
156
157 1
        throw new VariableKeyNotFound($name);
158
    }
159
160
    /**
161
     * Set current view parent rendering view and block.
162
     *
163
     * @param string $parent Fully qualified parent view name
164
     * @param string $block  View block for rendering in parent view
165
     */
166 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...
167
    {
168
169 1
    }
170
171
    /**
172
     * Set current view nested block rendering view.
173
     *
174
     * @param string $blockName Nested view block container
175
     */
176 1
    public function block($blockName)
177
    {
178 1
        if (array_key_exists($blockName, $this->blocksHtml)) {
179 1
            echo $this->blocksHtml[$blockName];
180 1
        }
181 1
    }
182
183
    /**
184
     * Magic method for setting view variables.
185
     *
186
     * @param string $name      Variable key
187
     * @param array  $arguments Variable value
188
     *
189
     * @return $this Chaining
190
     * @throws VariableKeyNotFound
191
     */
192 1
    public function __call($name, $arguments)
193
    {
194 1
        if (count($arguments)) {
195 1
            $this->set($arguments[0], $name);
196 1
        }
197
198 1
        return $this;
199
    }
200
201
    /**
202
     * Set view variable.
203
     *
204
     * Passing an array as $value will add array key => values into current
205
     * view data collection. If $key is passed then an array variable with this
206
     * key will be added to view data collection beside adding array key => values.
207
     *
208
     * @param mixed       $value Variable value
209
     * @param string|null $key   Variable key\prefix for objects and arrays
210
     *
211
     * @return $this Chaining
212
     */
213 7
    public function set($value, $key = null)
214
    {
215
        // RenderInterface implementation
216 7
        if (is_object($value) && is_a($value, RenderInterface::class)) {
217 3
            $this->setRenderableObject($value, $key);
218 7
        } elseif (is_array($value)) { // Merge array into view data
219 3
            $this->data = array_merge($this->data, $value);
220 3
        }
221
222
        // Store key value
223 7
        $this->data[$key] = $value;
224
225 7
        return $this;
226
    }
227
228
229
    /**
230
     * Set renderable object as view variable.
231
     *
232
     * @param mixed       $object Object instance for rendering
233
     * @param string|null $key    Variable key\prefix for objects and arrays
234
     */
235 3
    protected function setRenderableObject($object, $key)
236
    {
237
        /** @var RenderInterface $object */
238
        // Generate objects view array data and merge it with view data
239 3
        $this->data = array_merge(
240 3
            $this->data,
241 3
            $object->toView(null !== $key ? $key : get_class($object))
242 3
        );
243 3
    }
244
}
245