These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /** |
||
3 | * A base class for all Visual objects in Agile Toolkit. The |
||
4 | * important distinctive property of all Views is abiltiy |
||
5 | * to render themselves (produce HTML) automatically and |
||
6 | * recursively. |
||
7 | */ |
||
8 | abstract class AbstractView extends AbstractObject |
||
9 | { |
||
10 | /** |
||
11 | * $template is an object containing indexed HTML template. |
||
12 | * |
||
13 | * Example: |
||
14 | * |
||
15 | * $view->template->set('title', $my_title); |
||
16 | * |
||
17 | * Assuming you have tag <?$title?> in template file associated |
||
18 | * with this view - will insert text into this tag. |
||
19 | * |
||
20 | * @see AbstractObject::add(); |
||
21 | * @see AbstractView::defaultTemplate(); |
||
22 | * |
||
23 | * @var Template |
||
24 | */ |
||
25 | public $template = false; |
||
26 | |||
27 | /** |
||
28 | * @internal |
||
29 | * |
||
30 | * $template_flush is set to a spot on the template, which |
||
31 | * should be flushed out. When using AJAX we want to show |
||
32 | * only certain region from our template. However several |
||
33 | * childs may want to put their data. This property will |
||
34 | * be set to region's name my call_ajax_render and if it's |
||
35 | * set, call_ajax_render will echo it and return false. |
||
36 | * |
||
37 | * @var string |
||
38 | */ |
||
39 | public $template_flush = false; |
||
40 | |||
41 | /** |
||
42 | * $spot defines a place on a parent's template where render() will |
||
43 | * output() resulting HTML. |
||
44 | * |
||
45 | * @see output() |
||
46 | * @see render() |
||
47 | * @see AbstractObject::add(); |
||
48 | * @see defaultSpot(); |
||
49 | * |
||
50 | * @var string |
||
51 | */ |
||
52 | public $spot; |
||
53 | |||
54 | /** |
||
55 | * When using setModel() with Views some views will want to populate |
||
56 | * fields, columns etc corresponding to models meta-data. That is the |
||
57 | * job of Controller. When you create a custom controller for your view |
||
58 | * set this property to point at your controller and it will be used. |
||
59 | * automatically. |
||
60 | * |
||
61 | * @var string |
||
62 | */ |
||
63 | public $default_controller = null; |
||
64 | |||
65 | /** |
||
66 | * @var boolean |
||
67 | */ |
||
68 | public $auto_track_element = true; |
||
69 | |||
70 | |||
71 | |||
72 | // {{{ Basic Operations |
||
73 | |||
74 | /** |
||
75 | * For safety, you can't clone views. Use $view->newInstance instead. |
||
76 | */ |
||
77 | public function __clone() |
||
78 | { |
||
79 | throw $this->exception('Can\'t clone Views'); |
||
80 | } |
||
81 | /** |
||
82 | * Associate view with a model. Additionally may initialize a controller |
||
83 | * which would copy fields from the model into the View. |
||
84 | * |
||
85 | * @param object|string $model Class without "Model_" prefix or object |
||
86 | * @param array|string|null $actual_fields List of fields in order to populate |
||
87 | * |
||
88 | * @return AbstractModel object |
||
89 | */ |
||
90 | public function setModel($model, $actual_fields = UNDEFINED) |
||
91 | { |
||
92 | parent::setModel($model); |
||
93 | |||
94 | // Some models will want default controller to be associated |
||
95 | if ($this->model->default_controller) { |
||
96 | $this->controller |
||
97 | = $this->model->setController($this->model->default_controller); |
||
98 | } |
||
99 | |||
100 | // Use our default controller if present |
||
101 | if ($this->default_controller) { |
||
102 | $this->controller = $this->setController($this->default_controller); |
||
103 | } |
||
104 | |||
105 | if ($this->controller) { |
||
106 | if ($this->controller->hasMethod('setActualFields')) { |
||
107 | $this->controller->setActualFields($actual_fields); |
||
108 | } |
||
109 | if ($this->controller->hasMethod('_bindView')) { |
||
110 | $this->controller->_bindView(); |
||
111 | } |
||
112 | } |
||
113 | |||
114 | if ($this->model instanceof SQL_Model) { |
||
115 | $this->dq = $this->model->_dsql(); // compatibility |
||
0 ignored issues
–
show
|
|||
116 | } |
||
117 | |||
118 | return $this->model; |
||
119 | } |
||
120 | |||
121 | /** @internal used by getHTML */ |
||
122 | public $_tsBuffer = ''; |
||
123 | /** @internal accumulates output for getHTML */ |
||
124 | public function _tsBuffer($t, $data) |
||
125 | { |
||
126 | $this->_tsBuffer .= $data; |
||
127 | } |
||
128 | |||
129 | /** |
||
130 | * Converting View into string will render recursively and produce HTML. |
||
131 | * If argument is passed, JavaScript will be added into on_ready section |
||
132 | * of your document like when rendered normally. Note that you might |
||
133 | * require to destroy object if you don't want it's HTML to appear normally. |
||
134 | * |
||
135 | * @param bool $destroy Destroy object preventing it from rendering |
||
136 | * @param bool $execute_js Also capture JavaScript chains of object |
||
137 | * |
||
138 | * @return string HTML |
||
139 | */ |
||
140 | public function getHTML($destroy = true, $execute_js = true) |
||
141 | { |
||
142 | $this->addHook('output', array($this, '_tsBuffer')); |
||
143 | $this->recursiveRender(); |
||
144 | $this->removeHook('output', array($this, '_tsBuffer')); |
||
145 | $ret = $this->_tsBuffer; |
||
146 | $this->_tsBuffer = ''; |
||
147 | if ($execute_js && @$this->app->jquery) { |
||
148 | $this->app->jquery->getJS($this); |
||
149 | } |
||
150 | if ($destroy) { |
||
151 | $this->destroy(); |
||
152 | } |
||
153 | |||
154 | return $ret; |
||
155 | } |
||
156 | // }}} |
||
157 | |||
158 | // {{{ Template Setup |
||
159 | |||
160 | /** |
||
161 | * Called automatically during init for template initalization. |
||
162 | * |
||
163 | * @param string $template_spot Where object's output goes |
||
164 | * @param string|array $template_branch Where objects gets it's template |
||
165 | * |
||
166 | * @return AbstractView $this |
||
167 | * |
||
168 | * @internal |
||
169 | */ |
||
170 | public function initializeTemplate($template_spot = null, $template_branch = null) |
||
171 | { |
||
172 | if (!$template_spot) { |
||
0 ignored issues
–
show
The expression
$template_spot of type string|null is loosely compared to false ; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
173 | $template_spot = $this->defaultSpot(); |
||
174 | } |
||
175 | $this->spot = $template_spot; |
||
176 | if (@$this->owner->template |
||
177 | && !$this->owner->template->is_set($this->spot) |
||
178 | ) { |
||
179 | throw $this->owner->template->exception( |
||
180 | 'Spot is not found in owner\'s template' |
||
181 | )->addMoreInfo('spot', $this->spot); |
||
182 | } |
||
183 | if (!isset($template_branch)) { |
||
184 | $template_branch = $this->defaultTemplate(); |
||
185 | } |
||
186 | if (isset($template_branch)) { |
||
187 | // template branch would tell us what kind of template we have to |
||
188 | // use. Let's look at several cases: |
||
189 | |||
190 | if (is_object($template_branch)) { |
||
191 | // it might be already template instance (object) |
||
192 | $this->template = $template_branch; |
||
193 | } elseif (is_array($template_branch)) { |
||
194 | // it might be array with [0]=template, [1]=tag |
||
195 | if (is_object($template_branch[0])) { |
||
196 | // if [0] is object, we'll use that |
||
197 | $this->template = $template_branch[0]; |
||
198 | } else { |
||
199 | $this->template = $this->app->add('Template'); |
||
200 | $this->template->loadTemplate($template_branch[0]); |
||
201 | } |
||
202 | // Now that we loaded it, let's see which tag we need to cut out |
||
203 | $this->template = $this->template->cloneRegion( |
||
204 | isset($template_branch[1]) ? $template_branch[1] : '_top' |
||
205 | ); |
||
206 | } else { |
||
207 | // brach could be just a string - a region to clone off parent |
||
208 | if (isset($this->owner->template)) { |
||
209 | $this->template |
||
210 | = $this->owner->template->cloneRegion($template_branch); |
||
211 | } else { |
||
212 | $this->template = $this->add('Template'); |
||
213 | } |
||
214 | } |
||
215 | $this->template->owner = $this; |
||
216 | } |
||
217 | |||
218 | // Now that the template is loaded, let's take care of parent's template |
||
219 | if ($this->owner |
||
220 | && (isset($this->owner->template)) |
||
221 | && (!empty($this->owner->template)) |
||
222 | ) { |
||
223 | $this->owner->template->del($this->spot); |
||
224 | } |
||
225 | |||
226 | // Cool, now let's set _name of this template |
||
227 | if ($this->template) { |
||
228 | $this->template->trySet('_name', $this->getJSID()); |
||
229 | } |
||
230 | } |
||
231 | |||
232 | /** |
||
233 | * This method is called to automatically fill in some of the tags in this |
||
234 | * view. Normally the call is bassed to $app->setTags(), however you can |
||
235 | * extend and add more tags to fill. |
||
236 | */ |
||
237 | public function initTemplateTags() |
||
238 | { |
||
239 | if ($this->template |
||
240 | && $this->app->hasMethod('setTags') |
||
241 | ) { |
||
242 | $this->app->setTags($this->template); |
||
243 | } |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * This method is commonly redefined to set a default template for an object. |
||
248 | * If you return string, object will try to clone specified region off the |
||
249 | * parent. If you specify array, it will load and parse a separate template. |
||
250 | * |
||
251 | * This is overriden by 4th argument in add() method |
||
252 | * |
||
253 | * @return array|string Template definition |
||
254 | */ |
||
255 | public function defaultTemplate() |
||
256 | { |
||
257 | return $this->spot; |
||
258 | } |
||
259 | |||
260 | /** |
||
261 | * Normally when you add a view, it's output is placed inside <?$Content?> |
||
262 | * tag of its parent view. You can specify a different tag as 3rd argument |
||
263 | * for the add() method. If you wish for object to use different tag by |
||
264 | * default, you can override this method. |
||
265 | * |
||
266 | * @return string Tag / Spot in $this->owner->template |
||
267 | */ |
||
268 | public function defaultSpot() |
||
269 | { |
||
270 | return 'Content'; |
||
271 | } |
||
272 | // }}} |
||
273 | |||
274 | // {{{ Rendering, see http://agiletoolkit.org/learn/understand/api/exec |
||
275 | /** |
||
276 | * Recursively renders all views. Calls render() for all or for the one |
||
277 | * being cut. In some cases you may want to redefine this function instead |
||
278 | * of render(). The difference is that this function is called before |
||
279 | * sub-views are rendered, but render() is called after. |
||
280 | * |
||
281 | * function recursiveRender(){ |
||
282 | * $this->add('Text')->set('test'); |
||
283 | * return parent::recursiveRender(); // will render Text also |
||
284 | * } |
||
285 | * |
||
286 | * When cut_object is specified in the GET arguments, then output |
||
287 | * of HTML would be limited to object with matching $name or $short_name. |
||
288 | * |
||
289 | * This method will be called instead of default render() and it will |
||
290 | * stop rendering process and output object's HTML once it finds |
||
291 | * a suitable object. Exception_StopRender is used to terminate |
||
292 | * rendering process and bubble up to the APP. This exception is |
||
293 | * not an error. |
||
294 | */ |
||
295 | public function recursiveRender() |
||
296 | { |
||
297 | if ($this->hook('pre-recursive-render')) { |
||
298 | return; |
||
299 | } |
||
300 | |||
301 | $cutting_here = false; |
||
302 | $cutting_output = ''; |
||
303 | |||
304 | $this->initTemplateTags(); |
||
305 | |||
306 | if (isset($_GET['cut_object']) |
||
307 | && ($_GET['cut_object'] == $this->name |
||
308 | || $_GET['cut_object'] == $this->short_name) |
||
309 | ) { |
||
310 | // If we are cutting here, render childs and then we are done |
||
311 | unset($_GET['cut_object']); |
||
312 | $cutting_here = true; |
||
313 | |||
314 | $this->addHook('output', function ($self, $output) use (&$cutting_output) { |
||
315 | $cutting_output .= $output; |
||
316 | }); |
||
317 | } |
||
318 | |||
319 | if ($this->model |
||
320 | && is_object($this->model) |
||
321 | && $this->model->loaded() |
||
0 ignored issues
–
show
The method
loaded does not exist on object<AbstractModel> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
Loading history...
|
|||
322 | ) { |
||
323 | $this->modelRender(); |
||
324 | } |
||
325 | |||
326 | foreach ($this->elements as $key => $obj) { |
||
327 | if ($obj instanceof self) { |
||
328 | $obj->recursiveRender(); |
||
329 | $obj->moveJStoParent(); |
||
330 | } |
||
331 | } |
||
332 | |||
333 | if (!isset($_GET['cut_object'])) { |
||
334 | if (isset($_GET['cut_region'])) { |
||
335 | $this->region_render(); |
||
336 | } else { |
||
337 | $this->render(); |
||
338 | } |
||
339 | } |
||
340 | |||
341 | if ($cutting_here) { |
||
342 | //$result=$this->owner->template->cloneRegion($this->spot)->render(); |
||
343 | if ($this->app->jquery) { |
||
344 | $this->app->jquery->getJS($this); |
||
345 | } |
||
346 | throw new Exception_StopRender($cutting_output); |
||
347 | } |
||
348 | // if template wasn't cut, we move all JS chains to parent |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * When model is specified for a view, values of the model is |
||
353 | * inserted inside the template if corresponding tags exist. |
||
354 | * This is used as default values and filled out before |
||
355 | * the actual render kicks in. |
||
356 | */ |
||
357 | public function modelRender() |
||
358 | { |
||
359 | $this->template->set($this->model->get()); |
||
0 ignored issues
–
show
The method
get does not exist on object<AbstractModel> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
Loading history...
|
|||
360 | } |
||
361 | /** |
||
362 | * Append our chains to owner's chains. JS chains bubble up to |
||
363 | * app, which plugs them into template. If the object is being |
||
364 | * "cut" then only relevant chains will be outputed. |
||
365 | */ |
||
366 | public function moveJStoParent() |
||
367 | { |
||
368 | $this->owner->js = array_merge_recursive($this->owner->js, $this->js); |
||
0 ignored issues
–
show
The property
js does not seem to exist in AbstractObject .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.
Loading history...
|
|||
369 | } |
||
370 | |||
371 | /** |
||
372 | * Default rendering method. Generates HTML presentation of $this view. |
||
373 | * For most views, rendering the $this->template would be sufficient. |
||
374 | * |
||
375 | * If your view requires to do some heavy-duty work, please be sure to do |
||
376 | * it inside render() method. This way would save some performance in cases |
||
377 | * when your object is not being rendered. |
||
378 | * |
||
379 | * render method relies on method output(), which appeends HTML chunks |
||
380 | * to the parent's template. |
||
381 | */ |
||
382 | public function render() |
||
383 | { |
||
384 | if (!($this->template)) { |
||
385 | throw $this->exception('You should specify template for this object') |
||
386 | ->addMoreInfo('object', $this->name) |
||
387 | ->addMoreInfo('spot', $this->spot); |
||
388 | } |
||
389 | $this->output(($render = $this->template->render())); |
||
390 | if (@$this->debug) { |
||
391 | echo '<font color="blue">'.htmlspecialchars($render).'</font>'; |
||
392 | } |
||
393 | } |
||
394 | |||
395 | /** |
||
396 | * Low level output function which append's to the parent object's |
||
397 | * template. For normal objects, you simply need to specify a suitable |
||
398 | * template. |
||
399 | * |
||
400 | * @param string $txt HTML chunk |
||
401 | */ |
||
402 | public function output($txt) |
||
403 | { |
||
404 | if (!is_null($this->hook('output', array($txt)))) { |
||
405 | if (isset($this->owner->template) |
||
406 | && !empty($this->owner->template) |
||
407 | ) { |
||
408 | $this->owner->template->append($this->spot, $txt, false); |
||
409 | } elseif ($this->owner instanceof App_CLI) { |
||
410 | echo $txt; |
||
411 | } |
||
412 | } |
||
413 | } |
||
414 | |||
415 | /** |
||
416 | * When "cut"-ing using cut_region we need to output only a specified |
||
417 | * tag. This method of cutting is mostly un-used now, and should be |
||
418 | * considered obsolete. |
||
419 | * |
||
420 | * @obsolete |
||
421 | */ |
||
422 | public function region_render() |
||
423 | { |
||
424 | throw $this->exception('cut_region is now obsolete'); |
||
425 | |||
426 | if ($this->template_flush) { |
||
0 ignored issues
–
show
if ($this->template_flus...te_flush)->render()); } does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last
Loading history...
The variable
$this seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case,
Loading history...
|
|||
427 | if ($this->app->jquery) { |
||
0 ignored issues
–
show
The variable
$this seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case,
Loading history...
|
|||
428 | $this->app->jquery->getJS($this); |
||
0 ignored issues
–
show
The property
jquery does not seem to exist in App_CLI .
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.
Loading history...
|
|||
429 | } |
||
430 | throw new Exception_StopRender( |
||
431 | $this->template->cloneRegion($this->template_flush)->render() |
||
0 ignored issues
–
show
The method
render does not exist on object<AbstractObject> ? Since you implemented __call , maybe consider adding a @method annotation.
If you implement This is often the case, when class ParentClass {
private $data = array();
public function __call($method, array $args) {
if (0 === strpos($method, 'get')) {
return $this->data[strtolower(substr($method, 3))];
}
throw new \LogicException(sprintf('Unsupported method: %s', $method));
}
}
/**
* If this class knows which fields exist, you can specify the methods here:
*
* @method string getName()
*/
class SomeClass extends ParentClass { }
Loading history...
|
|||
432 | ); |
||
433 | } |
||
434 | $this->render(); |
||
435 | if ($this->spot == $_GET['cut_region']) { |
||
0 ignored issues
–
show
The variable
$this seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?
This error can happen if you refactor code and forget to move the variable initialization. Let’s take a look at a simple example: function someFunction() {
$x = 5;
echo $x;
}
The above code is perfectly fine. Now imagine that we re-order the statements: function someFunction() {
echo $x;
$x = 5;
}
In that case,
Loading history...
|
|||
436 | $this->owner->template_flush = $_GET['cut_region']; |
||
0 ignored issues
–
show
The property
template_flush does not seem to exist. Did you mean template ?
An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name. If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.
Loading history...
|
|||
437 | } |
||
438 | } |
||
439 | // }}} |
||
440 | |||
441 | // {{{ Object JavaScript Interface |
||
442 | public $js = array(); |
||
443 | /** |
||
444 | * Views in Agile Toolkit can assign javascript actions to themselves. This |
||
445 | * is done by calling $view->js() method. |
||
446 | * |
||
447 | * Method js() will return jQuery_Chain object which would record all calls |
||
448 | * to it's non-existant methods and convert them into jQuery call chain. |
||
449 | * |
||
450 | * js([action], [other_chain]); |
||
451 | * |
||
452 | * Action can represent javascript event, such as "click" or "mouseenter". |
||
453 | * If you specify action = true, then the event will ALWAYS be executed on |
||
454 | * pageload. It will also be executed if respective view is being reloaded |
||
455 | * by js()->reload() |
||
456 | * |
||
457 | * (Do not make mistake by specifying "true" instead of true) |
||
458 | * |
||
459 | * action = false will still return jQuery chain but will not bind it. |
||
460 | * You can bind it by passing to a different object's js() call as 2nd |
||
461 | * argument or output the chain in response to AJAX-ec call by calling |
||
462 | * execute() method. |
||
463 | * |
||
464 | * 1. Calling with arguments: |
||
465 | * |
||
466 | * $view->js(); // does nothing |
||
467 | * $a = $view->js()->hide(); // creates chain for hiding $view but does not |
||
468 | * // bind to event yet. |
||
469 | * |
||
470 | * 2. Binding existing chains |
||
471 | * $img->js('mouseenter', $a); // binds previously defined chain to event on |
||
472 | * // event of $img. |
||
473 | * |
||
474 | * Produced code: $('#img_id').click(function(ev){ ev.preventDefault(); |
||
475 | * $('view1').hide(); }); |
||
476 | * |
||
477 | * 3. $button->js('click',$form->js()->submit()); |
||
478 | * // clicking button will result in form submit |
||
479 | * |
||
480 | * 4. $view->js(true)->find('.current')->text($text); |
||
481 | * |
||
482 | * Will convert calls to jQuery chain into JavaScript string: |
||
483 | * $('#view').find('.current').text('abc'); // The $text will be json-encoded |
||
484 | * // to avoid JS injection. |
||
485 | * |
||
486 | * 5. ON YOUR OWN RISK |
||
487 | * |
||
488 | * $view->js(true,'alert(123)'); |
||
489 | * |
||
490 | * Will inject javascript un-escaped portion of javascript into chain. |
||
491 | * If you need to have a custom script then put it into file instead, |
||
492 | * save into templates/js/myfile.js and then include: |
||
493 | * |
||
494 | * $view->js()->_load('myfile'); |
||
495 | * |
||
496 | * It's highly suggested to bind your libraries with jQuery namespace by |
||
497 | * registered them as plugins, this way you can call your function easily: |
||
498 | * |
||
499 | * $view->js(true)->_load('myfile')->myplugin('myfunc',array($arg,$arg)); |
||
500 | * |
||
501 | * This approach is compatible with jQuery UI Widget factory and will keep |
||
502 | * your code clean |
||
503 | * |
||
504 | * @param string|true|null $when Event when chain will be executed |
||
505 | * @param array|chain|string $code JavaScript chain(s) or code |
||
506 | * @param string $instance Obsolete |
||
507 | * |
||
508 | * @link http://agiletoolkit.org/doc/js |
||
509 | * |
||
510 | * @return jQuery_Chain |
||
511 | */ |
||
512 | public function js($when = null, $code = null, $instance = null) |
||
513 | { |
||
514 | // Create new jQuery_Chain object |
||
515 | if (!isset($this->app->jquery)) { |
||
516 | throw new BaseException('requires jQuery or jUI support'); |
||
517 | } |
||
518 | |||
519 | // Substitute $when to make it better work as a array key |
||
520 | if ($when === true) { |
||
521 | $when = 'always'; |
||
522 | } |
||
523 | if ($when === false || $when === null) { |
||
524 | $when = 'never'; |
||
525 | } |
||
526 | |||
527 | if ($instance && isset($this->js[$when][$instance])) { |
||
0 ignored issues
–
show
The expression
$instance of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
528 | $js = $this->js[$when][$instance]; |
||
529 | } else { |
||
530 | $js = $this->app->jquery->chain($this); |
||
531 | } |
||
532 | |||
533 | if ($code) { |
||
534 | $js->_prepend($code); |
||
535 | } |
||
536 | |||
537 | if ($instance) { |
||
0 ignored issues
–
show
The expression
$instance of type string|null is loosely compared to true ; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.
In PHP, under loose comparison (like For '' == false // true
'' == null // true
'ab' == false // false
'ab' == null // false
// It is often better to use strict comparison
'' === false // false
'' === null // false
Loading history...
|
|||
538 | $this->js[$when][$instance] = $js; |
||
539 | } else { |
||
540 | $this->js[$when][] = $js; |
||
541 | } |
||
542 | |||
543 | return $js; |
||
544 | } |
||
545 | |||
546 | public function getJSID() |
||
547 | { |
||
548 | return str_replace('/', '_', $this->name); |
||
549 | } |
||
550 | /** |
||
551 | * Views in Agile Toolkit can assign javascript actions to themselves. This |
||
552 | * is done by calling $view->js() or $view->on(). |
||
553 | * |
||
554 | * on() method implements implementation of jQuery on() method. |
||
555 | * |
||
556 | * on(event, [selector], [other_chain]) |
||
557 | * |
||
558 | * Returned is a javascript chain wich is executed when event is triggered |
||
559 | * on specified selector (or all of the view if selector is ommitted). |
||
560 | * Optional other_chain argument can contain one or more chains (in array) |
||
561 | * which will also be executed. |
||
562 | * |
||
563 | * The chain returned by on() will properly select affected element. For |
||
564 | * example if the following view would contain multiple <a> elements, then |
||
565 | * only the clicked-one will be hidden. |
||
566 | * |
||
567 | * on('click','a')->hide(); |
||
568 | * |
||
569 | * |
||
570 | * Other_chain can also be specified as a Callable. In this case the |
||
571 | * executable code you have specified here will be called with several |
||
572 | * arguments: |
||
573 | * |
||
574 | * function($js, $data){ |
||
575 | * $js->hide(); |
||
576 | * } |
||
577 | * |
||
578 | * |
||
579 | * In this case javascript method is executed on a clicked event but |
||
580 | * in a more AJAX-way |
||
581 | * |
||
582 | * If your method returns a javascript chain, it will be executed |
||
583 | * instead. You can execute both if you embed $js inside returned |
||
584 | * chain. |
||
585 | * |
||
586 | * The third argument passed to your method contains |
||
587 | */ |
||
588 | public function on($event, $selector = null, $js = null) |
||
589 | { |
||
590 | if (!is_string($selector) && is_null($js)) { |
||
591 | $js = $selector; |
||
592 | $selector = null; |
||
593 | } |
||
594 | |||
595 | if (is_callable($js)) { |
||
596 | $p = $this->add('VirtualPage'); |
||
597 | |||
598 | $p->set(function ($p) use ($js) { |
||
599 | // $js is an actual callable |
||
600 | $js2 = $p->js()->_selectorRegion(); |
||
601 | |||
602 | $js3 = call_user_func($js, $js2, $_POST); |
||
603 | |||
604 | // If method returns something, execute that instead |
||
605 | if ($js3) { |
||
606 | $p->js(null, $js3)->execute(); |
||
607 | } else { |
||
608 | $js2->execute(); |
||
609 | } |
||
610 | }); |
||
611 | |||
612 | $js = $this->js()->_selectorThis()->univ()->ajaxec($p->getURL(), true); |
||
613 | } |
||
614 | |||
615 | if ($js) { |
||
616 | $ret_js = $this->js(null, $js)->_selectorThis(); |
||
617 | } else { |
||
618 | $ret_js = $this->js()->_selectorThis(); |
||
619 | } |
||
620 | |||
621 | $on_chain = $this->js(true); |
||
0 ignored issues
–
show
true is of type boolean , but the function expects a string|object<true>|null .
It seems like the type of the argument is not accepted by the function/method which you are calling. In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug. We suggest to add an explicit type cast like in the following example: function acceptsInteger($int) { }
$x = '123'; // string "123"
// Instead of
acceptsInteger($x);
// we recommend to use
acceptsInteger((integer) $x);
Loading history...
|
|||
622 | $fired = false; |
||
623 | |||
624 | $this->app->jui->addHook( |
||
625 | 'pre-getJS', |
||
626 | function ($app) use ($event, $selector, $ret_js, $on_chain, &$fired) { |
||
627 | if ($fired) { |
||
628 | return; |
||
629 | } |
||
630 | $fired = true; |
||
631 | |||
632 | $on_chain->on($event, $selector, $ret_js->_enclose(null, true)); |
||
633 | } |
||
634 | ); |
||
635 | |||
636 | return $ret_js; |
||
637 | } |
||
638 | // }}} |
||
639 | } |
||
640 |
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: