This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | /* TODO: |
||
3 | - styling: |
||
4 | - dropdown: |
||
5 | fix hover bg color (is now set on entire submenu instead of single item) |
||
6 | add hover fg color |
||
7 | add normal fg color |
||
8 | */ |
||
9 | ar_pinp::allow('ar_html_menu'); |
||
10 | |||
11 | class ar_html_menu extends arBase { |
||
12 | |||
13 | public static function bar( $options = array() ) { |
||
14 | $options += array( |
||
15 | 'filter' => 'object.implements="pdir"' |
||
16 | ); |
||
17 | $parent = $options['top']; |
||
18 | if (!$parent) { |
||
19 | $parent = ar::context()->getPath(); |
||
20 | } |
||
21 | $query = "object.priority>=0 and object.parent = '$parent'"; |
||
22 | if ( $options['filter'] ) { |
||
23 | $query .= ' and ( '.$options['filter'].' )'; |
||
24 | } |
||
25 | |||
26 | return ar::get( $parent )->find( $query ); |
||
27 | } |
||
28 | |||
29 | public static function tree( $options = array() ) { |
||
30 | $current = $options['current']; |
||
31 | if (!$current) { |
||
32 | $current = ar::context()->getPath(); |
||
33 | } |
||
34 | $top = $options['top']; |
||
35 | if (!$top) { |
||
36 | $top = ar_store::currentSite( $current ); |
||
37 | } |
||
38 | $options += array( |
||
39 | 'siblings' => true, |
||
40 | 'children' => true, |
||
41 | 'current' => null, |
||
42 | 'skipTop' => false, |
||
43 | 'filter' => 'object.implements="pdir"', |
||
44 | 'maxDepth' => 0 |
||
45 | ); |
||
46 | $query = ""; |
||
47 | if ($top[strlen($top)-1] != '/') { |
||
48 | $top = $top.'/'; |
||
49 | } |
||
50 | if ($options['siblings'] && !$options['children']) { |
||
51 | $current = dirname($current).'/'; |
||
52 | } else if (!$options['siblings'] && $options['children'] ) { |
||
53 | $query .= "object.parent='".$current."' or "; |
||
54 | } |
||
55 | while ( |
||
56 | ( substr( $current, 0, strlen( $top ) ) === $top ) |
||
57 | && ar::exists( $current ) |
||
58 | ) { |
||
59 | if ($options['siblings']) { |
||
60 | $query .= "object.parent='$current' or "; |
||
61 | } else { |
||
62 | $query .= "object.path='$current' or "; |
||
63 | } |
||
64 | $current = dirname($current).'/'; |
||
65 | } |
||
66 | if ( !$options['skipTop'] ) { |
||
67 | $query .= "object.path='$top' or "; |
||
68 | } |
||
69 | if ($query) { |
||
70 | $query = " and ( " . substr($query, 0, -4) . " )"; |
||
71 | } |
||
72 | $maxDepth = (int)$options['maxDepth']; |
||
73 | View Code Duplication | if ($maxDepth>0) { |
|
74 | $query .= " and object.path !~ '" . $top . str_repeat( '%/', $maxDepth + 1 ) . "'"; |
||
75 | } |
||
76 | if ( $options['filter'] ) { |
||
77 | $query .= ' and ( '.$options['filter'].' )'; |
||
78 | } |
||
79 | return ar::get($top)->find("object.priority>=0".$query); |
||
80 | } |
||
81 | |||
82 | public static function sitemap( $options = array() ) { |
||
83 | $top = $options['top']; |
||
84 | if (!$top) { |
||
85 | $top = ar_store::currentSite( ar::context()->getPath() ); |
||
86 | } |
||
87 | $options += array( |
||
88 | 'skipTop' => true, |
||
89 | 'filter' => 'object.implements="pdir"', |
||
90 | 'maxDepth' => 0 |
||
91 | ); |
||
92 | $query = "object.priority>=0"; |
||
93 | if ($options['skipTop']) { |
||
94 | $query .= " and object.path != '".$top."'"; |
||
95 | } |
||
96 | $maxDepth = (int)$options['maxDepth']; |
||
97 | View Code Duplication | if ($maxDepth>0) { |
|
98 | $query .= " and object.path !~ '" . $top . str_repeat( '%/', $maxDepth + 1 ) . "'"; |
||
99 | } |
||
100 | if ( $options['filter'] ) { |
||
101 | $query .= ' and ( '.$options['filter'].' )'; |
||
102 | } |
||
103 | return ar::get( $top )->find( $query ); |
||
104 | } |
||
105 | |||
106 | public static function crumbs( $options = array() ) { |
||
107 | $current = $options['current']; |
||
108 | if (!$current) { |
||
109 | $current = ar::context()->getPath(); |
||
110 | } |
||
111 | $top = $options['top']; |
||
112 | if (!$top) { |
||
113 | $top = ar_store::currentSite( $current ); |
||
114 | } |
||
115 | $options += array( |
||
116 | 'current' => $current, |
||
117 | 'top' => $top, |
||
118 | 'filter' => '' |
||
119 | ); |
||
120 | $current = $options['current']; |
||
121 | if (!$current) { |
||
122 | $current = $top; |
||
123 | } |
||
124 | |||
125 | if ( $options['filter'] ) { |
||
126 | $query .= ' and ( '.$options['filter'].' )'; |
||
0 ignored issues
–
show
|
|||
127 | } |
||
128 | return ar::get( $current )->parents()->top( $top ); |
||
129 | } |
||
130 | |||
131 | public static function el() { |
||
132 | $args = func_get_args(); |
||
133 | $name = array_shift($args); |
||
134 | $attributes = array(); |
||
135 | $content = array(); |
||
136 | foreach ($args as $arg) { |
||
137 | if ( is_array( $arg ) && !is_a( $arg, 'ar_xmlNodes' ) ) { |
||
138 | $attributes = array_merge($attributes, $arg); |
||
139 | } else if ($arg instanceof ar_xmlNodes) { |
||
140 | $content = array_merge( $content, (array) $arg); |
||
141 | } else { |
||
142 | $content[] = $arg; |
||
143 | } |
||
144 | } |
||
145 | if ( !count( $content ) ) { |
||
146 | $content = null; |
||
147 | } else { |
||
148 | $content = new ar_htmlNodes( $content ); |
||
149 | } |
||
150 | $el = new ar_html_menuElement( $name, $attributes, $content ); |
||
151 | $el->setAttribute('class', ['menuRoot' => 'menuRoot'] ); |
||
152 | return $el; |
||
153 | } |
||
154 | |||
155 | public static function element() { |
||
156 | $args = func_get_args(); |
||
157 | return call_user_func_array( array( 'self', 'el' ), $args ); |
||
158 | } |
||
159 | |||
160 | } |
||
161 | |||
162 | class ar_html_menuElement extends ar_htmlElement { |
||
163 | |||
164 | private $items = null; |
||
165 | private $root = ''; |
||
166 | private $current = ''; |
||
167 | private $rooturl = ''; |
||
168 | private $filled = false; |
||
169 | private $stripeOptions = false; |
||
170 | private $levelOptions = false; |
||
171 | private $autoIDOptions = false; |
||
172 | private $styleType = 'bar'; |
||
173 | private $options = array( |
||
174 | 'skipOrphans' => false, |
||
175 | 'itemTag' => 'li', |
||
176 | 'listTag' => 'ul' |
||
177 | ); |
||
178 | private $prefix = ''; |
||
179 | public $viewmode = 'list'; |
||
180 | public $template = 'system.get.link.phtml'; |
||
181 | public $css = null; |
||
182 | |||
183 | public function __construct( $tagName = 'ul', $attributes = array(), $childNodes = null, $parentNode = null ) { |
||
184 | if (!$attributes['class'] && !$attributes['id']) { |
||
185 | $attributes['class'] = 'menu'; |
||
186 | } |
||
187 | if (!$tagName) { |
||
188 | $tagName = 'ul'; |
||
189 | } |
||
190 | $this->options['listTag'] = $tagName; |
||
191 | switch ($tagName) { |
||
192 | case 'ul': |
||
193 | case 'ol': |
||
194 | $this->options['itemTag'] = 'li'; |
||
195 | break; |
||
196 | case 'dl': |
||
197 | $this->options['itemTag'] = 'dt'; |
||
198 | break; |
||
199 | default: |
||
200 | $this->options['itemTag'] = $tagName; |
||
201 | break; |
||
202 | } |
||
203 | if ( ! ( $childNodes instanceof ar_htmlNodes ) ) { |
||
204 | $childNodes = null; |
||
205 | } |
||
206 | parent::__construct( $tagName, $attributes, $childNodes, $parentNode ); |
||
207 | $this->items['[root]'] = $this; |
||
208 | $context = ar::context(); |
||
209 | $me = $context->getObject(); |
||
210 | if ( $me ) { |
||
211 | $this->root = $me->currentsite(); |
||
212 | $this->rooturl = $me->make_local_url( $this->root ); |
||
213 | } |
||
214 | if ( !isset($this->root) ) { |
||
215 | $this->root = '/'; |
||
216 | $this->rooturl = '/'; |
||
217 | } |
||
218 | $this->current = $this->root; |
||
219 | $listTag = $this->options['listTag']; |
||
220 | $itemTag = $this->options['itemTag']; |
||
221 | if ($this->attributes['id']) { |
||
222 | $prefix = '#'.$this->attributes['id']; |
||
223 | } else { |
||
224 | $prefix = $listTag . '.' . $this->attributes['class']; |
||
225 | } |
||
226 | $this->prefix = $prefix; |
||
227 | $this->css = ar_css::stylesheet() |
||
228 | ->import(" |
||
229 | $prefix, $prefix $listTag { |
||
230 | list-style: none; |
||
231 | margin: 0px; |
||
232 | padding: 0px; |
||
233 | } |
||
234 | |||
235 | $prefix $itemTag { |
||
236 | margin: 0px; |
||
237 | padding: 0px; |
||
238 | } |
||
239 | |||
240 | $prefix $itemTag a { |
||
241 | text-decoration: none; |
||
242 | } |
||
243 | "); |
||
244 | } |
||
245 | |||
246 | public function setAttribute( $attribute, $value ) { |
||
247 | parent::setAttribute( $attribute, $value ); |
||
248 | if ($this->attributes['id']) { |
||
249 | $this->prefix = '#'.$this->attributes['id']; |
||
250 | } else { |
||
251 | $this->prefix = $this->options['listTag'] . '.' . $this->attributes['class']; |
||
252 | } |
||
253 | return $this; |
||
254 | } |
||
255 | |||
256 | public function script( $type = '', $matches = array() ) { |
||
257 | $script = ''; |
||
258 | switch ($type) { |
||
259 | case 'pulldown' : |
||
260 | case 'dropdown' : |
||
261 | $listTagUp = strtoupper( $this->options['listTag'] ); |
||
262 | $itemTagUp = strtoupper( $this->options['itemTag'] ); |
||
263 | $script = <<<EOF |
||
264 | function arMenuHover( list ) { |
||
265 | if ( list ) { |
||
266 | if ( list[0]=='#' ) { |
||
267 | var lis = document.getElementById( list.substring(1) ).getElementsByTagName("{$itemTagUp}"); |
||
268 | } else { |
||
269 | if ( list[0] == '.') { |
||
270 | list = list.substring(1); |
||
271 | } |
||
272 | var uls = document.getElementsByTagName( '{$listTagUp}' ); |
||
273 | var lis = []; |
||
274 | var re = new RegExp('\\\\b' + list + '\\\\b' ); |
||
275 | for ( var i = uls.length-1; i>=0; i-- ) { |
||
276 | if ( re.test(uls[i].className) ) { |
||
277 | var newlis = uls[i].getElementsByTagName( '{$itemTagUp}' ); |
||
278 | for (var ii=newlis.length-1; ii>=0; ii--) { |
||
279 | lis = lis.concat( newlis[ii] ); |
||
280 | } |
||
281 | } |
||
282 | } |
||
283 | } |
||
284 | for (var i=lis.length-1; i>=0; i--) { |
||
285 | lis[i].onmouseover = function() { |
||
286 | this.className += " menuHover"; |
||
287 | } |
||
288 | lis[i].onmouseout = function() { |
||
289 | this.className = this.className.replace(/ menuHover\b/, ''); |
||
290 | } |
||
291 | } |
||
292 | } |
||
293 | } |
||
294 | |||
295 | EOF; |
||
296 | if ( is_string($matches) ) { |
||
297 | $matches = array( $matches ); |
||
298 | } |
||
299 | if ( is_array($matches) && count($matches) ) { |
||
300 | $script .= "if (window.attachEvent && ( !document.documentMode || document.documentMode<8) ) {\n"; |
||
301 | foreach ( $matches as $match ) { |
||
302 | $script .= " arMenuHover( '$match' );\n"; |
||
303 | } |
||
304 | $script .= "}\n"; |
||
305 | } |
||
306 | break; |
||
307 | } |
||
308 | return $script; |
||
309 | } |
||
310 | |||
311 | public function style( $type = '' ) { |
||
312 | if (!$type) { |
||
313 | $type = $this->styleType; |
||
314 | } |
||
315 | $itemTag = $this->options['itemTag']; |
||
316 | $listTag = $this->options['listTag']; |
||
317 | $prefix = $this->prefix; |
||
318 | switch ($type) { |
||
319 | case 'bar' : |
||
320 | $this->css->import(" |
||
321 | $prefix $itemTag { |
||
322 | float : left; |
||
323 | padding : 0px 10px; |
||
324 | } |
||
325 | $prefix $listTag $listTag { |
||
326 | float : left; |
||
327 | padding : 0px; |
||
328 | margin : 0px; |
||
329 | } |
||
330 | $prefix { |
||
331 | overflow : hidden; |
||
332 | padding-right : 20px; |
||
333 | }"); |
||
334 | break; |
||
335 | case 'sitemap' : |
||
336 | $this->css->import(" |
||
337 | $prefix $itemTag { |
||
338 | margin-left: 0px; |
||
339 | padding-left: 0px; |
||
340 | } |
||
341 | $prefix $listTag { |
||
342 | margin-left: 20px; |
||
343 | padding-left: 0px; |
||
344 | } |
||
345 | "); |
||
346 | break; |
||
347 | case 'tree' : |
||
348 | $this->css->import(" |
||
349 | $prefix $itemTag { |
||
350 | padding: 0px; |
||
351 | } |
||
352 | $prefix $itemTag a { |
||
353 | padding-left: 20px; |
||
354 | } |
||
355 | $prefix $itemTag $itemTag a { |
||
356 | padding-left: 40px; |
||
357 | } |
||
358 | $prefix $itemTag $itemTag $itemTag a { |
||
359 | padding-left: 60px; |
||
360 | } |
||
361 | $prefix $itemTag $itemTag $itemTag $itemTag a { |
||
362 | padding-left: 80px; |
||
363 | } |
||
364 | "); |
||
365 | break; |
||
366 | case 'crumbs' : |
||
367 | $this->css->import(" |
||
368 | $prefix $listTag { |
||
369 | display : inline; |
||
370 | } |
||
371 | $prefix $itemTag { |
||
372 | padding-left : 0px; |
||
373 | list-style : none; |
||
374 | display : inline; |
||
375 | } |
||
376 | $prefix $itemTag $itemTag:before { |
||
377 | content : \"\\0020 \\00BB \\0020\" /* >> or » character */ |
||
378 | } |
||
379 | "); |
||
380 | break; |
||
381 | case 'pulldown' : |
||
382 | case 'dropdown' : |
||
383 | $this->css |
||
384 | ->bind('menuHeight', '1.5em') |
||
385 | ->bind('menuItemWidth', 'auto') |
||
386 | ->bind('menuSubItemWidth', '10em') |
||
387 | ->bind('menuHoverItemBgColor', '#E4E4E4') |
||
388 | ->bind('menuItemBgColor', 'transparent') |
||
389 | ->bind('menuSubItemBgColor', 'white') |
||
390 | ->bind('menuBorderColor', 'transparent') |
||
391 | ->import(" |
||
392 | $prefix { |
||
393 | display : block; |
||
394 | height : var(menuHeight); |
||
395 | } |
||
396 | $prefix $itemTag { |
||
397 | width : var(menuItemWidth); |
||
398 | float : left; |
||
399 | position : relative; |
||
400 | background-color : var(menuItemBgColor); |
||
401 | } |
||
402 | $prefix $itemTag a { |
||
403 | width : var(menuItemWidth); |
||
404 | padding : 0px 10px 0px 0px; |
||
405 | } |
||
406 | $prefix $itemTag $itemTag a { |
||
407 | width : var(menuSubItemWidth); |
||
408 | display : block; |
||
409 | } |
||
410 | $prefix $itemTag:hover a { |
||
411 | background-color : var(menuHoverItemBgColor); |
||
412 | } |
||
413 | $prefix $itemTag.menuHover a { |
||
414 | background-color : var(menuHoverItemBgColor); |
||
415 | } |
||
416 | $prefix $itemTag $listTag { |
||
417 | width : var(menuSubItemWidth); |
||
418 | position : absolute; |
||
419 | left : -999em; |
||
420 | background-color : var(menuSubItemBgColor); |
||
421 | border : 1px solid var(menuBorderColor); |
||
422 | } |
||
423 | $prefix $itemTag $itemTag a { |
||
424 | width : var(menuSubItemWidth); |
||
425 | padding : 0px; |
||
426 | } |
||
427 | $prefix $itemTag:hover $listTag { |
||
428 | left : auto; |
||
429 | } |
||
430 | $prefix $itemTag.menuHover $listTag { |
||
431 | left : 0px; |
||
432 | top : 1em; |
||
433 | } |
||
434 | $prefix $itemTag $listTag $listTag { |
||
435 | margin : -1em 0 0 var(menuSubItemWidth); |
||
436 | } |
||
437 | $prefix $itemTag:hover .$listTag $listTag { |
||
438 | left : -999em; |
||
439 | } |
||
440 | $prefix $itemTag.menuHover $listTag $listTag { |
||
441 | left : -999em; |
||
442 | } |
||
443 | $prefix $itemTag $itemTag:hover $listTag { |
||
444 | left : auto |
||
445 | } |
||
446 | $prefix $itemTag $itemTag.menuHover $listTag { |
||
447 | left : var(menuSubItemWidth); |
||
448 | top : 0px; |
||
449 | } |
||
450 | $prefix $itemTag:hover $listTag $listTag $listTag { |
||
451 | left : -999em; |
||
452 | } |
||
453 | $prefix $itemTag.menuHover $listTag $listTag $listTag { |
||
454 | left : -999em; |
||
455 | } |
||
456 | $prefix $itemTag $itemTag $itemTag:hover $listTag { |
||
457 | left : auto; |
||
458 | } |
||
459 | $prefix $itemTag $itemTag $itemTag.menuHover $listTag { |
||
460 | left : auto; |
||
461 | ) |
||
462 | "); |
||
463 | break; |
||
464 | case 'tabs' : |
||
465 | $this->css |
||
466 | ->bind('menuBgColor', 'transparent') |
||
467 | ->bind('menuItemBgColor', '#E4E4E4') |
||
468 | ->bind('menuActiveItemBgColor', 'white') |
||
469 | ->bind('menuBorderColor', 'black') |
||
470 | ->import(" |
||
471 | $prefix $itemTag { |
||
472 | float : left; |
||
473 | background-color : var(menuItemBgColor); |
||
474 | border : 1px solid var(menuBorderColor); |
||
475 | margin : 0px 5px -1px 5px; |
||
476 | padding : 0px 5px; |
||
477 | height : 1.5em; |
||
478 | } |
||
479 | $prefix $itemTag.menuCurrent { |
||
480 | background-color : var(menuActiveItemBgColor); |
||
481 | border-bottom : 1px solid var(menuActiveItemBgColor); |
||
482 | } |
||
483 | $prefix { |
||
484 | height : 1.5em; |
||
485 | padding : 0px 20px 1px 0px; |
||
486 | border-bottom : 1px solid var(menuBorderColor); |
||
487 | } |
||
488 | "); |
||
489 | break; |
||
490 | } |
||
491 | return $this->css; |
||
492 | } |
||
493 | |||
494 | public function root( $url, $path='/' ) { |
||
495 | if ($this->root == $this->current) { // FIXME: this looks like nonsense |
||
496 | $this->current = $path; |
||
497 | } |
||
498 | $this->rooturl = $url; |
||
499 | $this->root = $path; |
||
500 | return $this; |
||
501 | } |
||
502 | |||
503 | public function template( $template ) { |
||
504 | $this->template = $template; |
||
505 | return $this; |
||
506 | } |
||
507 | |||
508 | public function toString( $indent = '', $current = 0 ) { |
||
509 | if ( !$this->filled ) { |
||
510 | // do a default menu. |
||
511 | $this->bar(); |
||
512 | } |
||
513 | if ( $this->stripeOptions ) { |
||
514 | $this->stripe( $this->stripeOptions ); |
||
515 | } |
||
516 | if ( $this->levelOptions ) { |
||
517 | $this->levels( $this->levelOptions ); |
||
518 | } |
||
519 | if ( $this->autoIDOptions ) { |
||
520 | $this->autoID( $this->autoIDOptions ); |
||
521 | } |
||
522 | return parent::toString( $indent, $current ); |
||
523 | } |
||
524 | |||
525 | private function _makeURL( $path, $parent ) { |
||
526 | /* |
||
527 | - ?bla=bla -> parent url + arguments |
||
528 | - #bla -> parent url + fragment |
||
529 | - /path -> absolute path -> append to root url |
||
530 | - http://.../ -> url |
||
531 | ftp:// |
||
532 | mailto: |
||
533 | [a-z]+: |
||
534 | - rest is a path -> append to parent path |
||
535 | */ |
||
536 | if ($parent=='[root]') { |
||
537 | $parent = ''; |
||
538 | } |
||
539 | switch( $path[0] ) { |
||
540 | case '?' : |
||
541 | $qpos = ($parent) ? strpos( '?', $parent ) : false; |
||
542 | if (false!==$qpos) { |
||
543 | $url = substr($parent, $qpos); |
||
544 | $query = substr($parent, $qpos+1); |
||
545 | $fpos = strpos( '#', $query ); |
||
546 | if (false!==$fpos) { |
||
547 | $fragment = substr($query, $fpos); |
||
0 ignored issues
–
show
$fragment is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
548 | $query = substr($query, 0, $fpos); |
||
549 | } else { |
||
550 | $fragment = ''; |
||
0 ignored issues
–
show
$fragment is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
551 | } |
||
552 | parse_str($query, $params); |
||
553 | parse_str(substr($path, 1), $newparams); |
||
554 | $params = array_merge_recursive( $params, $newparams ); |
||
555 | $url .= '?' . http_build_query( $params ); |
||
556 | } else { |
||
557 | $url = $parent . $path; |
||
558 | } |
||
559 | break; |
||
560 | case '#' : |
||
561 | $fpos = ($parent) ? strpos( '#', $parent ) : false; |
||
562 | if ( false !== $fpos ) { |
||
563 | $url = substr($parent, $fpos); |
||
564 | } else { |
||
565 | $url = $parent; |
||
566 | } |
||
567 | $url .= $path; |
||
568 | break; |
||
569 | case '/' : |
||
570 | if ( substr( $path, 0, strlen( $this->root ) ) == $this->root ) { |
||
571 | $path = substr($path, strlen($this->root)); |
||
572 | } else if ( substr( $this->rooturl, -1 ) == '/' ) { |
||
573 | $path = substr($path, 1); |
||
574 | } |
||
575 | $url = $this->rooturl . $path; |
||
576 | break; |
||
577 | default : |
||
578 | if ( preg_match( '/^[a-z]+:/', $path ) ) { // url |
||
579 | $url = $path; |
||
580 | } else { // relative path |
||
581 | $url = $parent . $path; |
||
582 | } |
||
583 | break; |
||
584 | } |
||
585 | return $url; |
||
586 | } |
||
587 | |||
588 | private function _getItemInfo( $item, $key, $parent, $current ) { |
||
589 | if ( $item instanceof ar_htmlElement ) { |
||
590 | if ($item->attributes['href']) { |
||
591 | $url = $item->attributes['href']; |
||
592 | } else { |
||
593 | $url = null; |
||
594 | } |
||
595 | $item = array( 'node' => $item, 'url' => $url ); |
||
596 | } |
||
597 | if (!is_array($item)) { |
||
598 | $item = array( 'name' => $item ); |
||
599 | } |
||
600 | $path = $item['path']; |
||
601 | if ( !isset($path) ) { |
||
602 | $path = $key; |
||
603 | $item['path'] = ( ( $parent!='[root]' ) ? $parent : '' ) . $key; |
||
604 | } |
||
605 | if ( !isset($item['url']) ) { |
||
606 | $item['url'] = $this->_makeURL( $path, $parent ); |
||
607 | } |
||
608 | if ( !isset($item['node']) ) { |
||
609 | if ( !isset($item['tagName']) ) { |
||
610 | $item['tagName'] = $this->options['itemTag']; |
||
611 | } |
||
612 | if ( !isset($item['attributes']) ) { |
||
613 | //FIXME: ['attributes']['a'] / ['li'] / ['ul'] |
||
614 | // rest of ['attributes'] = ['attributes']['a'] |
||
615 | $item['attributes'] = array(); |
||
616 | } |
||
617 | $linkAttributes = array( 'href' => $item['url'] ); |
||
618 | if ( isset($item['title']) ) { |
||
619 | $linkAttributes['title'] = $item['title']; |
||
620 | } |
||
621 | if ( isset($item['class']) ) { |
||
622 | $linkAttributes['class'][] = $item['class']; |
||
623 | } |
||
624 | if ( isset($item['id']) ) { |
||
625 | $linkAttributes['id'] = $item['id']; |
||
626 | } |
||
627 | if ( ($item['path']==$current) || ($item['url'] == $current) ) { |
||
628 | $linkAttributes['class']['menuCurrent'] = 'menuCurrent'; |
||
629 | View Code Duplication | if (!is_array($item['attributes']['class'])) { |
|
630 | $item['attributes']['class'] = array( $item['attributes']['class'] ); |
||
631 | } |
||
632 | $item['attributes']['class']['menuCurrent'] = 'menuCurrent'; |
||
633 | } else if ( ( strpos( $current, $item['path'] ) === 0 ) || |
||
634 | ( strpos( $current, $item['url'] ) === 0 ) ) { |
||
635 | View Code Duplication | if (!is_array($item['attributes']['class'])) { |
|
636 | $item['attributes']['class'] = array( $item['attributes']['class'] ); |
||
637 | } |
||
638 | $item['attributes']['class']['menuParent'] = 'menuParent'; |
||
639 | } |
||
640 | $item['node'] = ar_html::tag( $item['tagName'], $item['attributes'], |
||
641 | ar_html::tag( 'a', $linkAttributes, $item['name']) |
||
642 | ); |
||
643 | } else { |
||
644 | $link = $item['node']->a[0]; |
||
645 | if ( ($item['path']==$current) || ($item['url'] == $current) || ( $link && $link->attributes['href']==$current ) ) { |
||
646 | if ($link) { |
||
647 | $link->setAttribute('class', array( 'menuCurrent' => 'menuCurrent') ); |
||
648 | } |
||
649 | $item['node']->setAttribute('class', array( 'menuCurrent' => 'menuCurrent') ); |
||
650 | } else if ( ( strpos( $current, $item['path'] ) === 0 ) || |
||
651 | ( strpos( $current, $item['url'] ) === 0 ) || |
||
652 | ( $link && strpos( $current, $link->attributes['href'] ) === 0 ) ) { |
||
653 | $item['node']->setAttribute('class', array( 'menuParent' => 'menuParent' ) ); |
||
654 | } |
||
655 | |||
656 | } |
||
657 | return $item; |
||
658 | } |
||
659 | |||
660 | private function _fillFromArray( $list, $current, $parent = '[root]' ) { |
||
661 | // first enter all nodes into the items list |
||
662 | // then rearrange them into parent/child relations |
||
663 | // otherwise you must always have the parent in the list before any child |
||
664 | |||
665 | foreach ( $list as $key => $item ) { |
||
666 | if ( !$item ) { |
||
667 | continue; |
||
668 | } |
||
669 | $itemInfo = $this->_getItemInfo( $item, $key, $parent, $current ); |
||
670 | $itemNode = $itemInfo['node']; |
||
671 | $this->items[$itemInfo['url']] = $itemNode; |
||
672 | |||
673 | if ( $parent != '[root]') { |
||
674 | $parentNode = $this->items[$parent]; |
||
675 | if ($parentNode) { |
||
676 | $uls = $parentNode->getElementsByTagName( $this->options['listTag'], true ); |
||
677 | if (!$uls || !$uls[0]) { |
||
678 | $ul = $parentNode->appendChild( ar_html::el( $this->options['listTag'] ) ); |
||
679 | } else { |
||
680 | $ul = $uls[0]; |
||
681 | } |
||
682 | $ul->appendChild($itemNode); |
||
683 | } |
||
684 | } |
||
685 | if ($itemInfo['children']) { |
||
686 | $this->_fillFromArray( $itemInfo['children'], $current, $itemInfo['url'] ); |
||
687 | } |
||
688 | } |
||
689 | foreach ( $this->items as $url => $itemNode ) { |
||
690 | if ( $url != '[root]' ) { // do not remove, prevents infinite loop |
||
691 | if ( $parent == '[root]' ) { |
||
692 | if ($url == $this->rooturl) { |
||
693 | $parentNode = $this; |
||
694 | } else { |
||
695 | $oldparent = ''; |
||
696 | $newparent = dirname( $url ).'/'; |
||
697 | if ( !$this->options['skipOrphans'] ) { |
||
698 | while ($newparent!=$oldparent && !isset($this->items[$newparent]) && $newparent!=$this->rooturl) { |
||
699 | $oldparent = $newparent; |
||
700 | $newparent = dirname( $newparent ).'/'; |
||
701 | } |
||
702 | } |
||
703 | |||
704 | if ( isset($this->items[$newparent]) ) { |
||
705 | $parentNode = current( $this->items[$newparent]->getElementsByTagName( $this->options['listTag'] ) ); |
||
706 | if (!$parentNode || !isset($parentNode)) { |
||
707 | $parentNode = $this->items[$newparent]->appendChild( ar_html::el( $this->options['listTag'] ) ); |
||
708 | } |
||
709 | } else if ($newparent == $this->rooturl) { |
||
710 | $parentNode = $this; |
||
711 | } else if (!$this->options['skipOrphans']) { |
||
712 | $parentNode = $this; |
||
713 | } else { |
||
714 | $parentNode = null; |
||
715 | } |
||
716 | } |
||
717 | } else if ( isset($this->items[$parent]) ) { |
||
718 | $parentNode = $this->items[$parent]; |
||
719 | } else if ( !$this->options['skipOrphans'] ) { |
||
720 | $parentNode = $this; |
||
721 | } else { |
||
722 | $parentNode = null; |
||
723 | } |
||
724 | |||
725 | if ($parentNode && ($parentNode !== $itemNode)) { // itemNode should not be parentNode to prevent loops |
||
726 | $temp = $parentNode; |
||
727 | $ok = true; |
||
728 | while( $temp ) { |
||
729 | if ( $temp === $itemNode ) { |
||
730 | $ok = false; |
||
731 | break; |
||
732 | } |
||
733 | $temp = $temp->parentNode; |
||
734 | } |
||
735 | if ( $ok ) { |
||
736 | $parentNode->appendChild( $itemNode ); |
||
737 | } |
||
738 | } |
||
739 | } |
||
740 | } |
||
741 | } |
||
742 | |||
743 | public function fill() { |
||
744 | $args = func_get_args(); |
||
745 | foreach( $args as $list) { |
||
746 | if ( ($list instanceof ar_storeFind) || ($list instanceof ar_storeParents) ) { |
||
747 | $list = $list->call( $this->template, array( 'current' => $this->current, 'root' => $this->root ) ); |
||
748 | } |
||
749 | if ( is_array($list) ) { |
||
750 | $this->_fillFromArray( $list, $this->current ); |
||
751 | } |
||
752 | } |
||
753 | $this->filled = true; |
||
754 | return $this; |
||
755 | } |
||
756 | |||
757 | public function stripe( $options = array() ) { |
||
758 | $options += array( |
||
759 | 'striping' => ar::listPattern( 'menuFirst .*', '(menuOdd menuEven?)*', '.* menuLast' ), |
||
760 | 'stripingContinue' => false |
||
761 | ); |
||
762 | if ( $options['striping'] ) { |
||
763 | if ( $options['stripingContinue'] ) { |
||
764 | $this->getElementsByTagName( $this->options['itemTag'] )->setAttribute('class', array( |
||
765 | 'menuStriping' => $options['striping'] |
||
766 | ) ); |
||
767 | } else { |
||
768 | $this->childNodes->setAttribute( 'class', array( |
||
769 | 'menuStriping' => $options['striping'] |
||
770 | ) ); |
||
771 | $uls = $this->getElementsByTagName( $this->options['listTag'] ); |
||
772 | foreach( $uls as $ul ) { |
||
773 | $ul->childNodes->setAttribute( 'class', array( |
||
774 | 'menuStriping' => $options['striping'] |
||
775 | ) ); |
||
776 | } |
||
777 | } |
||
778 | } |
||
779 | $this->stripeOptions = $options; |
||
0 ignored issues
–
show
It seems like
$options of type array is incompatible with the declared type boolean of property $stripeOptions .
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.. ![]() |
|||
780 | return $this; |
||
781 | } |
||
782 | |||
783 | public function levels( $options = array() ) { |
||
784 | $options += array( |
||
785 | 'maxDepth' => 5, |
||
786 | 'startLevel' => 0 |
||
787 | ); |
||
788 | |||
789 | // add level classes to the ul/li tags, level-0, level-1, etc. |
||
790 | if ( $options['maxDepth'] == 0 ) { |
||
791 | return $this; |
||
792 | } |
||
793 | if (!isset($options['rootNode'])) { |
||
794 | $options['rootNode'] = $this; |
||
795 | } |
||
796 | if ( $options['rootNode'] instanceof ar_htmlElement ) { |
||
797 | $options['rootNode'] = ar_html::nodes( $options['rootNode'] ); |
||
798 | } |
||
799 | if ($options['rootNode'] instanceof ar_htmlNodes && count($options['rootNode']) ) { |
||
800 | $options['rootNode']->setAttribute( 'class', array('menuLevels' => 'menuLevel-'.$options['startLevel']) ); |
||
801 | foreach( $options['rootNode'] as $element ) { |
||
802 | $element->childNodes->setAttribute( 'class', array( 'menuLevels' => 'menuLevel-'.$options['startLevel'] ) ); |
||
803 | $this->levels( array( |
||
804 | 'maxDepth' => $options['maxDepth'] - 1, |
||
805 | 'startLevel' => $options['startLevel'] + 1, |
||
806 | 'rootNode' => $element->getElementsByTagName( $this->options['itemTag'], true )->getElementsByTagName( $this->options['listTag'], true ) |
||
807 | ) ); |
||
808 | } |
||
809 | } |
||
810 | $this->levelOptions = $options; |
||
0 ignored issues
–
show
It seems like
$options of type array<string,?> is incompatible with the declared type boolean of property $levelOptions .
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.. ![]() |
|||
811 | return $this; |
||
812 | } |
||
813 | |||
814 | public function autoID( $options = array() ) { |
||
815 | $options += array( |
||
816 | 'rootID' => 'menu', |
||
817 | 'rootNode' => $element |
||
0 ignored issues
–
show
The variable
$element 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, ![]() |
|||
818 | ); |
||
819 | // create unique id's per list item |
||
820 | if (!isset($options['rootNode']) ) { |
||
821 | $options['rootNode'] = $this; |
||
822 | } |
||
823 | $element = $options['rootNode']; |
||
824 | if (!$element->attributes['id']) { |
||
825 | $element->setAttribute( 'id', $options['rootID'] . '-ul' ); |
||
826 | } |
||
827 | $list = $element->li; |
||
828 | $counter = 0; |
||
829 | foreach ($list as $li) { |
||
830 | $id = $options['rootID'] . '-' . $counter++; |
||
831 | if ( !$li->attributes['id'] ) { |
||
832 | $li->setAttribute( 'id', $id ); |
||
833 | } |
||
834 | $ul = $li->getElementsByTagName( $this->options['listTag'], true ); |
||
835 | if (count($ul)) { |
||
836 | $this->autoID( array( |
||
837 | 'rootID' => $id, |
||
838 | 'rootNode' => $ul[0] |
||
839 | ) ); |
||
840 | } |
||
841 | } |
||
842 | $this->autoIDOptions = $options; |
||
0 ignored issues
–
show
It seems like
$options of type array<string,?,{"rootNode":"?"}> is incompatible with the declared type boolean of property $autoIDOptions .
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.. ![]() |
|||
843 | return $this; |
||
844 | } |
||
845 | |||
846 | public function childIndicators() { |
||
847 | $list = $this->getElementsByTagName( $this->options['listTag'] ); |
||
848 | foreach( $list as $ul) { |
||
849 | $ul->parentNode->setAttribute('class', array('menuChildIndicator' => 'menuHasChildren')); |
||
850 | } |
||
851 | return $this; |
||
852 | } |
||
853 | |||
854 | public function current( $path ) { |
||
855 | $this->current = $path; |
||
856 | return $this; |
||
857 | } |
||
858 | |||
859 | public function configure( $options ) { |
||
860 | if ($options['top']) { |
||
861 | $this->root( ar('loader')->makeURL($options['top']), $options['top'] ); |
||
862 | } else { |
||
863 | $options['top'] = $this->root; |
||
864 | } |
||
865 | if ($options['current']) { |
||
866 | $this->current( $options['current'] ); |
||
867 | } else { |
||
868 | $options['current'] = $this->current; |
||
869 | } |
||
870 | $this->options = array_merge( $this->options, $options ); |
||
871 | return $this; |
||
872 | } |
||
873 | |||
874 | View Code Duplication | public function bar( $options = array() ) { |
|
875 | $this->configure( $options ); |
||
876 | $this->fill( ar_html_menu::bar( $this->options ) ); |
||
877 | $this->styleType = 'bar'; |
||
878 | return $this; |
||
879 | } |
||
880 | |||
881 | View Code Duplication | public function tree( $options = array() ) { |
|
882 | $this->configure( $options ); |
||
883 | $this->fill( ar_html_menu::tree( $this->options ) ); |
||
884 | $this->styleType = 'tree'; |
||
885 | return $this; |
||
886 | } |
||
887 | |||
888 | View Code Duplication | public function crumbs( $options = array() ) { |
|
889 | $this->configure( $options ); |
||
890 | $this->fill( ar_html_menu::crumbs( $this->options ) ); |
||
891 | $this->styleType = 'crumbs'; |
||
892 | return $this; |
||
893 | } |
||
894 | |||
895 | View Code Duplication | public function sitemap( $options = array() ) { |
|
896 | $this->configure( $options ); |
||
897 | $this->fill( ar_html_menu::sitemap( $this->options ) ); |
||
898 | $this->styleType = 'sitemap'; |
||
899 | return $this; |
||
900 | } |
||
901 | |||
902 | } |
||
903 |
This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.