|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace luya\web; |
|
4
|
|
|
|
|
5
|
|
|
use Yii; |
|
6
|
|
|
use Exception; |
|
7
|
|
|
use luya\helpers\FileHelper; |
|
8
|
|
|
use Twig_Loader_Filesystem; |
|
9
|
|
|
|
|
10
|
|
|
/** |
|
11
|
|
|
* Ability to register small html elements via closure function and run those |
|
12
|
|
|
* parts an every part of the page. |
|
13
|
|
|
* |
|
14
|
|
|
* ```php |
|
15
|
|
|
* Yii::$app->element->addElement('foo', function($param) { |
|
16
|
|
|
* return '<button>' . $param . '</button>'; |
|
17
|
|
|
* }); |
|
18
|
|
|
* ``` |
|
19
|
|
|
* |
|
20
|
|
|
* The above example can be execute like this: |
|
21
|
|
|
* |
|
22
|
|
|
* ```php |
|
23
|
|
|
* echo Yii::$app->element->foo('Hello World'); |
|
24
|
|
|
* ``` |
|
25
|
|
|
* |
|
26
|
|
|
* or in Twig |
|
27
|
|
|
* |
|
28
|
|
|
* ```twig |
|
29
|
|
|
* {{ element('foo', 'Hello World') }} |
|
30
|
|
|
* ``` |
|
31
|
|
|
* |
|
32
|
|
|
* By default the Element-Component will lookup for an `elements.php` file returning an array |
|
33
|
|
|
* where the key is the element name and value the closure to be execute. |
|
34
|
|
|
* |
|
35
|
|
|
* Example elements.php |
|
36
|
|
|
* |
|
37
|
|
|
* ```php |
|
38
|
|
|
* <?php |
|
39
|
|
|
* return [ |
|
40
|
|
|
* 'button' => function($value, $link) { |
|
41
|
|
|
* return '<a class="btn btn-primary" href="'.$link.'">'.$value.'</a>'; |
|
42
|
|
|
* }, |
|
43
|
|
|
* 'teaserbox' => function($title, $text, $buttonValue, $buttonLink) { |
|
44
|
|
|
* return '<div class="teaser-box" style="padding:10px; border:1px solid red;"><h1>'.$title.'</h1><p>'.$text.'</p>'.$this->button($buttonValue, $buttonLink).'</div>'; |
|
45
|
|
|
* }, |
|
46
|
|
|
* ]; |
|
47
|
|
|
* ``` |
|
48
|
|
|
* |
|
49
|
|
|
* @author nadar |
|
50
|
|
|
*/ |
|
51
|
|
|
class Element extends \yii\base\Component |
|
52
|
|
|
{ |
|
53
|
|
|
/** |
|
54
|
|
|
* @var string The path to the default element file. Alias names will be parsed by Yii::getAlias. |
|
55
|
|
|
*/ |
|
56
|
|
|
public $configFile = '@app/elements.php'; |
|
57
|
|
|
|
|
58
|
|
|
/** |
|
59
|
|
|
* @var string The path to the folder where the view files to render can be found. |
|
60
|
|
|
*/ |
|
61
|
|
|
public $viewsFolder = '@app/views/elements/'; |
|
62
|
|
|
|
|
63
|
|
|
/** |
|
64
|
|
|
* @var array Contains all registered elements. |
|
65
|
|
|
*/ |
|
66
|
|
|
private $_elements = []; |
|
67
|
|
|
|
|
68
|
|
|
/** |
|
69
|
|
|
* @var string Parsed path of the folder where the view files are stored. |
|
70
|
|
|
*/ |
|
71
|
|
|
private $_folder = null; |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* Yii intializer, is loading the default elements.php if existing. |
|
75
|
|
|
*/ |
|
76
|
|
|
public function init() |
|
77
|
|
|
{ |
|
78
|
|
|
$path = Yii::getAlias($this->configFile); |
|
79
|
|
|
if (file_exists($path)) { |
|
80
|
|
|
$config = (include($path)); |
|
81
|
|
|
foreach ($config as $name => $closure) { |
|
82
|
|
|
$this->addElement($name, $closure); |
|
83
|
|
|
} |
|
84
|
|
|
} |
|
85
|
|
|
} |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* Magic method to run an closre directly from the Element-Object, for convincience. Example use. |
|
89
|
|
|
* |
|
90
|
|
|
* ```php |
|
91
|
|
|
* $element = new Element(); |
|
92
|
|
|
* $element->name($param1); |
|
93
|
|
|
* ``` |
|
94
|
|
|
* |
|
95
|
|
|
* @param string $name access method name |
|
96
|
|
|
* @param array $params access method params |
|
97
|
|
|
*/ |
|
98
|
|
|
public function __call($name, $params) |
|
99
|
|
|
{ |
|
100
|
|
|
return $this->run($name, $params); |
|
101
|
|
|
} |
|
102
|
|
|
|
|
103
|
|
|
/** |
|
104
|
|
|
* Add an element with a closure to the elements array. |
|
105
|
|
|
* |
|
106
|
|
|
* @param string $name The identifier of the element where the close is binde to. |
|
107
|
|
|
* @param callable $closure The closure function to registered, for instance: |
|
108
|
|
|
* |
|
109
|
|
|
* ```php |
|
110
|
|
|
* function() { |
|
111
|
|
|
* return 'foobar'; |
|
112
|
|
|
* } |
|
113
|
|
|
* ``` |
|
114
|
|
|
*/ |
|
115
|
|
|
public function addElement($name, $closure) |
|
116
|
|
|
{ |
|
117
|
|
|
$this->_elements[$name] = $closure; |
|
118
|
|
|
} |
|
119
|
|
|
|
|
120
|
|
|
/** |
|
121
|
|
|
* Checks whether an elemnt exists in the elements list or not |
|
122
|
|
|
* |
|
123
|
|
|
* @param string $name The name of the element |
|
124
|
|
|
* @return boolean |
|
125
|
|
|
*/ |
|
126
|
|
|
public function hasElement($name) |
|
127
|
|
|
{ |
|
128
|
|
|
return array_key_exists($name, $this->_elements); |
|
129
|
|
|
} |
|
130
|
|
|
|
|
131
|
|
|
/** |
|
132
|
|
|
* Returns an array with all registered Element-Names. |
|
133
|
|
|
* |
|
134
|
|
|
* @return array Value is the name of the element |
|
135
|
|
|
*/ |
|
136
|
|
|
public function getNames() |
|
137
|
|
|
{ |
|
138
|
|
|
return array_keys($this->_elements); |
|
139
|
|
|
} |
|
140
|
|
|
|
|
141
|
|
|
/** |
|
142
|
|
|
* Return all elements as an array where the key is the name and the value the closure. |
|
143
|
|
|
* |
|
144
|
|
|
* @return array Key is the Name of the Element, value the Closure. |
|
145
|
|
|
*/ |
|
146
|
|
|
public function getElements() |
|
147
|
|
|
{ |
|
148
|
|
|
return $this->_elements; |
|
149
|
|
|
} |
|
150
|
|
|
|
|
151
|
|
|
/** |
|
152
|
|
|
* Run an element and return the closures return value. |
|
153
|
|
|
* |
|
154
|
|
|
* @param string $name The name of the elemente to execute. |
|
155
|
|
|
* @param array $params The params to pass to the closure methode. |
|
156
|
|
|
* |
|
157
|
|
|
* @return mixed The return value of the executed closure function. |
|
158
|
|
|
* |
|
159
|
|
|
* @throws Exception |
|
160
|
|
|
*/ |
|
161
|
|
|
public function run($name, array $params = []) |
|
162
|
|
|
{ |
|
163
|
|
|
if (!array_key_exists($name, $this->_elements)) { |
|
164
|
|
|
throw new Exception("The requested element '$name' does not exist in the list. You may register the element first with `addElement(name, closure)`."); |
|
165
|
|
|
} |
|
166
|
|
|
|
|
167
|
|
|
return call_user_func_array($this->_elements[$name], $params); |
|
168
|
|
|
} |
|
169
|
|
|
|
|
170
|
|
|
/** |
|
171
|
|
|
* Returns the path to the view files used for the render() method. Singleton method the return |
|
172
|
|
|
* the evaluated viewFolder path once. |
|
173
|
|
|
* |
|
174
|
|
|
* @return string Evaluated view foler path |
|
175
|
|
|
*/ |
|
176
|
|
|
public function getFolder() |
|
177
|
|
|
{ |
|
178
|
|
|
if ($this->_folder === null) { |
|
179
|
|
|
$this->_folder = Yii::getAlias($this->viewsFolder); |
|
|
|
|
|
|
180
|
|
|
} |
|
181
|
|
|
|
|
182
|
|
|
return $this->_folder; |
|
183
|
|
|
} |
|
184
|
|
|
|
|
185
|
|
|
/** |
|
186
|
|
|
* Method to render twig files with theyr specific arguments, can be used inside the element closure depending |
|
187
|
|
|
* on where the closure was registered. Otherwhise the use of the element variable must be provided. |
|
188
|
|
|
* |
|
189
|
|
|
* @param string $file The name of the file to render. |
|
190
|
|
|
* @param array $args The parameters to pass in the render file. |
|
191
|
|
|
* |
|
192
|
|
|
* @return string The render value of the view file. |
|
193
|
|
|
*/ |
|
194
|
|
|
public function render($file, array $args = []) |
|
195
|
|
|
{ |
|
196
|
|
|
$twig = Yii::$app->twig->env(new Twig_Loader_Filesystem($this->getFolder())); |
|
|
|
|
|
|
197
|
|
|
|
|
198
|
|
|
return $twig->render(FileHelper::appendExtensionToString($file, 'twig'), $args); |
|
199
|
|
|
} |
|
200
|
|
|
} |
|
201
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountIdthat can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theidproperty of an instance of theAccountclass. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.