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 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace Rinvex\Menus\Models; |
||
6 | |||
7 | use Countable; |
||
8 | use Illuminate\Support\Collection; |
||
9 | use Illuminate\View\Factory as ViewFactory; |
||
10 | use Rinvex\Menus\Presenters\NavbarPresenter; |
||
11 | use Rinvex\Menus\Contracts\PresenterContract; |
||
12 | use Illuminate\Contracts\View\View as ViewContract; |
||
13 | |||
14 | class MenuGenerator implements Countable |
||
15 | { |
||
16 | /** |
||
17 | * The items collection. |
||
18 | * |
||
19 | * @var \Illuminate\Support\Collection |
||
20 | */ |
||
21 | protected $items; |
||
22 | |||
23 | /** |
||
24 | * The presenter class. |
||
25 | * |
||
26 | * @var string |
||
27 | */ |
||
28 | protected $presenter = NavbarPresenter::class; |
||
29 | |||
30 | /** |
||
31 | * The URL prefix. |
||
32 | * |
||
33 | * @var string|null |
||
34 | */ |
||
35 | protected $urlPrefix; |
||
36 | |||
37 | /** |
||
38 | * The view name. |
||
39 | * |
||
40 | * @var string |
||
41 | */ |
||
42 | protected $view; |
||
43 | |||
44 | /** |
||
45 | * The laravel view factory instance. |
||
46 | * |
||
47 | * @var \Illuminate\View\Factory |
||
48 | */ |
||
49 | protected $views; |
||
50 | |||
51 | /** |
||
52 | * Resolved item binding map. |
||
53 | * |
||
54 | * @var array |
||
55 | */ |
||
56 | protected $bindings = []; |
||
57 | |||
58 | /** |
||
59 | * Create a new MenuGenerator instance. |
||
60 | */ |
||
61 | public function __construct() |
||
62 | { |
||
63 | $this->items = collect(); |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Find menu item by given key and value. |
||
68 | * |
||
69 | * @param string $key |
||
70 | * @param string $value |
||
71 | * @param callable $callback |
||
0 ignored issues
–
show
|
|||
72 | * |
||
73 | * @return \Rinvex\Menus\Models\MenuItem|null |
||
74 | */ |
||
75 | public function findBy(string $key, string $value, callable $callback = null): ?MenuItem |
||
76 | { |
||
77 | $item = $this->items->filter(function ($item) use ($key, $value) { |
||
78 | return $item->{$key} === $value; |
||
79 | })->first(); |
||
80 | |||
81 | (! is_callable($callback) || ! $item) || call_user_func($callback, $item); |
||
82 | |||
83 | return $item; |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Find menu item by given key and value. |
||
88 | * |
||
89 | * @param string $title |
||
90 | * @param int $order |
||
0 ignored issues
–
show
Should the type for parameter
$order not be null|integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
91 | * @param string $icon |
||
0 ignored issues
–
show
Should the type for parameter
$icon not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
92 | * @param string $type |
||
0 ignored issues
–
show
Should the type for parameter
$type not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
93 | * @param array $attributes |
||
94 | * @param callable $callback |
||
0 ignored issues
–
show
Should the type for parameter
$callback not be null|callable ? Also, consider making the array more specific, something like array<String> , or String[] .
This check looks for It makes a suggestion as to what type it considers more descriptive. In addition it
looks for parameters that have the generic type Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
95 | * |
||
96 | * @return \Rinvex\Menus\Models\MenuItem|null |
||
97 | */ |
||
98 | public function findByTitleOrAdd(string $title, int $order = null, string $icon = null, string $type = null, array $attributes = [], callable $callback = null): ?MenuItem |
||
99 | { |
||
100 | if (! ($item = $this->findBy('title', $title, $callback))) { |
||
101 | $item = $this->add(compact('type', 'title', 'order', 'icon', 'attributes')); |
||
102 | ! is_callable($callback) || call_user_func($callback, $item); |
||
103 | } |
||
104 | |||
105 | return $item; |
||
106 | } |
||
107 | |||
108 | /** |
||
109 | * Set view factory instance. |
||
110 | * |
||
111 | * @param \Illuminate\View\Factory $views |
||
112 | * |
||
113 | * @return $this |
||
114 | */ |
||
115 | public function setViewFactory(ViewFactory $views) |
||
116 | { |
||
117 | $this->views = $views; |
||
118 | |||
119 | return $this; |
||
120 | } |
||
121 | |||
122 | /** |
||
123 | * Set view. |
||
124 | * |
||
125 | * @param string $view |
||
126 | * |
||
127 | * @return $this |
||
128 | */ |
||
129 | public function setView(string $view) |
||
130 | { |
||
131 | $this->view = $view; |
||
132 | |||
133 | return $this; |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * Set Prefix URL. |
||
138 | * |
||
139 | * @param string $prefixUrl |
||
0 ignored issues
–
show
There is no parameter named
$prefixUrl . Was it maybe removed?
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. Consider the following example. The parameter /**
* @param array $germany
* @param array $island
* @param array $italy
*/
function finale($germany, $island) {
return "2:1";
}
The most likely cause is that the parameter was removed, but the annotation was not. ![]() |
|||
140 | * |
||
141 | * @return $this |
||
142 | */ |
||
143 | public function setUrlPrefix(string $urlPrefix) |
||
144 | { |
||
145 | $this->urlPrefix = $urlPrefix; |
||
146 | |||
147 | return $this; |
||
148 | } |
||
149 | |||
150 | /** |
||
151 | * Set new presenter class. |
||
152 | * |
||
153 | * @param string $presenter |
||
154 | * |
||
155 | * @return $this |
||
156 | */ |
||
157 | public function setPresenter(string $presenter) |
||
158 | { |
||
159 | $this->presenter = app('rinvex.menus.presenters')->get($presenter); |
||
160 | |||
161 | return $this; |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * Get presenter instance. |
||
166 | * |
||
167 | * @return \Rinvex\Menus\Contracts\PresenterContract |
||
168 | */ |
||
169 | public function getPresenter(): PresenterContract |
||
170 | { |
||
171 | return new $this->presenter(); |
||
172 | } |
||
173 | |||
174 | /** |
||
175 | * Determine if the given name in the presenter style. |
||
176 | * |
||
177 | * @param string $presenter |
||
178 | * |
||
179 | * @return bool |
||
180 | */ |
||
181 | public function presenterExists(string $presenter): bool |
||
182 | { |
||
183 | return app('rinvex.menus.presenters')->has($presenter); |
||
184 | } |
||
185 | |||
186 | /** |
||
187 | * Set the resolved item bindings. |
||
188 | * |
||
189 | * @param array $bindings |
||
190 | * |
||
191 | * @return $this |
||
192 | */ |
||
193 | public function setBindings(array $bindings) |
||
194 | { |
||
195 | $this->bindings = $bindings; |
||
196 | |||
197 | return $this; |
||
198 | } |
||
199 | |||
200 | /** |
||
201 | * Resolves a key from the bindings array. |
||
202 | * |
||
203 | * @param string|array $key |
||
204 | * |
||
205 | * @return mixed |
||
0 ignored issues
–
show
|
|||
206 | */ |
||
207 | public function resolve($key) |
||
208 | { |
||
209 | if (is_array($key)) { |
||
210 | foreach ($key as $k => $v) { |
||
211 | $key[$k] = $this->resolve($v); |
||
212 | } |
||
213 | } elseif (is_string($key)) { |
||
214 | $matches = []; |
||
215 | |||
216 | // Search for any {placeholders} and replace with their replacement values |
||
217 | preg_match_all('/{[\s]*?([^\s]+)[\s]*?}/i', $key, $matches, PREG_SET_ORDER); |
||
218 | |||
219 | foreach ($matches as $match) { |
||
0 ignored issues
–
show
The expression
$matches of type null|array<integer,array<integer,string>> is not guaranteed to be traversable. How about adding an additional type check?
There are different options of fixing this problem.
![]() |
|||
220 | if (array_key_exists($match[1], $this->bindings)) { |
||
221 | $key = preg_replace('/'.$match[0].'/', $this->bindings[$match[1]], $key, 1); |
||
222 | } |
||
223 | } |
||
224 | } |
||
225 | |||
226 | return $key; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * Resolves an array of menu items properties. |
||
231 | * |
||
232 | * @param \Illuminate\Support\Collection &$items |
||
233 | * |
||
234 | * @return void |
||
235 | */ |
||
236 | protected function resolveItems(Collection &$items): void |
||
237 | { |
||
238 | $resolver = function ($property) { |
||
239 | return $this->resolve($property) ?: $property; |
||
240 | }; |
||
241 | |||
242 | $items->each(function (MenuItem $item) use ($resolver) { |
||
243 | $item->fill(array_map($resolver, $item->properties)); |
||
244 | }); |
||
245 | } |
||
246 | |||
247 | /** |
||
248 | * Add new child menu. |
||
249 | * |
||
250 | * @param array $properties |
||
251 | * |
||
252 | * @return \Rinvex\Menus\Models\MenuItem |
||
253 | */ |
||
254 | protected function add(array $properties = []): MenuItem |
||
255 | { |
||
256 | $properties['attributes']['id'] = $properties['attributes']['id'] ?? md5(json_encode($properties)); |
||
257 | $this->items->push($item = new MenuItem($properties)); |
||
258 | |||
259 | return $item; |
||
260 | } |
||
261 | |||
262 | /** |
||
263 | * Create new menu with dropdown. |
||
264 | * |
||
265 | * @param callable $callback |
||
266 | * @param string $title |
||
267 | * @param int $order |
||
0 ignored issues
–
show
Should the type for parameter
$order not be null|integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
268 | * @param string $icon |
||
0 ignored issues
–
show
Should the type for parameter
$icon not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
269 | * @param array $attributes |
||
270 | * |
||
271 | * @return \Rinvex\Menus\Models\MenuItem |
||
272 | */ |
||
273 | public function dropdown(callable $callback, string $title, int $order = null, string $icon = null, array $attributes = []): MenuItem |
||
274 | { |
||
275 | $type = 'dropdown'; |
||
276 | |||
277 | call_user_func($callback, $item = $this->add(compact('type', 'title', 'order', 'icon', 'attributes'))); |
||
278 | |||
279 | return $item; |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * Register new menu item using registered route. |
||
284 | * |
||
285 | * @param string $route |
||
0 ignored issues
–
show
Should the type for parameter
$route not be array ? Also, consider making the array more specific, something like array<String> , or String[] .
This check looks for It makes a suggestion as to what type it considers more descriptive. In addition it
looks for parameters that have the generic type Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
286 | * @param string $title |
||
287 | * @param int $order |
||
0 ignored issues
–
show
Should the type for parameter
$order not be null|integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
288 | * @param string $icon |
||
0 ignored issues
–
show
Should the type for parameter
$icon not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
289 | * @param array $attributes |
||
290 | * |
||
291 | * @return \Rinvex\Menus\Models\MenuItem |
||
292 | */ |
||
293 | public function route(array $route, string $title, int $order = null, string $icon = null, array $attributes = []): MenuItem |
||
294 | { |
||
295 | $type = 'route'; |
||
296 | |||
297 | return $this->add(compact('type', 'route', 'title', 'order', 'icon', 'attributes')); |
||
298 | } |
||
299 | |||
300 | /** |
||
301 | * Register new menu item using url. |
||
302 | * |
||
303 | * @param string $url |
||
304 | * @param string $title |
||
305 | * @param int $order |
||
0 ignored issues
–
show
Should the type for parameter
$order not be null|integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
306 | * @param string $icon |
||
0 ignored issues
–
show
Should the type for parameter
$icon not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
307 | * @param array $attributes |
||
308 | * |
||
309 | * @return \Rinvex\Menus\Models\MenuItem |
||
310 | */ |
||
311 | public function url(string $url, string $title, int $order = null, string $icon = null, array $attributes = []): MenuItem |
||
312 | { |
||
313 | $type = 'url'; |
||
314 | ! $this->urlPrefix || $url = $this->formatUrl($url); |
||
0 ignored issues
–
show
The expression
$this->urlPrefix 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
![]() |
|||
315 | |||
316 | return $this->add(compact('type', 'url', 'title', 'order', 'icon', 'attributes')); |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Add new header item. |
||
321 | * |
||
322 | * @param string $title |
||
323 | * @param int $order |
||
0 ignored issues
–
show
Should the type for parameter
$order not be null|integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
324 | * @param string $icon |
||
0 ignored issues
–
show
Should the type for parameter
$icon not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
325 | * @param array $attributes |
||
326 | * |
||
327 | * @return \Rinvex\Menus\Models\MenuItem |
||
328 | */ |
||
329 | public function header(string $title, int $order = null, string $icon = null, array $attributes = []): MenuItem |
||
330 | { |
||
331 | $type = 'header'; |
||
332 | |||
333 | return $this->add(compact('type', 'title', 'order', 'icon', 'attributes')); |
||
334 | } |
||
335 | |||
336 | /** |
||
337 | * Add new divider item. |
||
338 | * |
||
339 | * @param int $order |
||
0 ignored issues
–
show
Should the type for parameter
$order not be null|integer ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
340 | * @param array $attributes |
||
341 | * |
||
342 | * @return \Rinvex\Menus\Models\MenuItem |
||
343 | */ |
||
344 | public function divider(int $order = null, array $attributes = []): MenuItem |
||
345 | { |
||
346 | $type = 'divider'; |
||
347 | |||
348 | return $this->add(compact('type', 'order', 'attributes')); |
||
349 | } |
||
350 | |||
351 | /** |
||
352 | * Get items count. |
||
353 | * |
||
354 | * @return int |
||
355 | */ |
||
356 | public function count(): int |
||
357 | { |
||
358 | return $this->items->count(); |
||
359 | } |
||
360 | |||
361 | /** |
||
362 | * Empty the current menu items. |
||
363 | * |
||
364 | * @return $this |
||
365 | */ |
||
366 | public function destroy() |
||
367 | { |
||
368 | $this->items = collect(); |
||
369 | |||
370 | return $this; |
||
371 | } |
||
372 | |||
373 | /** |
||
374 | * Get menu items and order it by 'order' key. |
||
375 | * |
||
376 | * @return \Illuminate\Support\Collection |
||
377 | */ |
||
378 | protected function getOrderedItems(): Collection |
||
379 | { |
||
380 | return $this->items->sortBy('properties.order')->each(function (MenuItem $parent) { |
||
381 | $parent->hideWhen(function () use ($parent) { |
||
382 | return in_array($parent->properties['type'], ['dropdown', 'header']) && ! $parent->getChilds()->reduce(function ($carry, MenuItem $child) { |
||
383 | return $carry || ! $child->isHidden(); |
||
384 | }, false); |
||
385 | }); |
||
386 | }); |
||
387 | } |
||
388 | |||
389 | /** |
||
390 | * Render the menu to HTML tag. |
||
391 | * |
||
392 | * @param string $presenter |
||
0 ignored issues
–
show
Should the type for parameter
$presenter not be null|string ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
393 | * @param bool $specialSidebar |
||
394 | * |
||
395 | * @return string |
||
396 | */ |
||
397 | public function render(string $presenter = null, bool $specialSidebar = false): string |
||
398 | { |
||
399 | $this->resolveItems($this->items); |
||
400 | |||
401 | if (! is_null($this->view)) { |
||
402 | return $this->renderView($presenter, $specialSidebar)->render(); |
||
403 | } |
||
404 | |||
405 | (! $presenter || ! $this->presenterExists($presenter)) || $this->setPresenter($presenter); |
||
0 ignored issues
–
show
The expression
$presenter of type null|string 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
![]() |
|||
406 | |||
407 | return $this->renderMenu($specialSidebar); |
||
408 | } |
||
409 | |||
410 | /** |
||
411 | * Render menu via view presenter. |
||
412 | * |
||
413 | * @param string $view |
||
414 | * @param bool $specialSidebar |
||
415 | * |
||
416 | * @return \Illuminate\Contracts\View\View |
||
417 | */ |
||
418 | protected function renderView(string $view, bool $specialSidebar = false): ViewContract |
||
419 | { |
||
420 | return $this->views->make($view, ['items' => $this->getOrderedItems(), 'specialSidebar' => $specialSidebar]); |
||
421 | } |
||
422 | |||
423 | /** |
||
424 | * Render the menu. |
||
425 | * |
||
426 | * @param bool $specialSidebar |
||
427 | * |
||
428 | * @return string |
||
429 | */ |
||
430 | protected function renderMenu(bool $specialSidebar = false): string |
||
431 | { |
||
432 | $presenter = $this->getPresenter(); |
||
433 | $menu = $presenter->getOpenTagWrapper(); |
||
434 | |||
435 | foreach ($this->getOrderedItems() as $item) { |
||
436 | if ($item->isHidden()) { |
||
437 | continue; |
||
438 | } |
||
439 | |||
440 | if ($item->hasChilds()) { |
||
441 | $menu .= $presenter->getMenuWithDropDownWrapper($item, $specialSidebar); |
||
442 | } elseif ($item->isHeader()) { |
||
443 | $menu .= $presenter->getHeaderWrapper($item); |
||
444 | } elseif ($item->isDivider()) { |
||
445 | $menu .= $presenter->getDividerWrapper(); |
||
446 | } else { |
||
447 | $menu .= $presenter->getMenuWithoutDropdownWrapper($item); |
||
448 | } |
||
449 | } |
||
450 | |||
451 | $menu .= $presenter->getCloseTagWrapper(); |
||
452 | |||
453 | return $menu; |
||
454 | } |
||
455 | |||
456 | /** |
||
457 | * Format URL. |
||
458 | * |
||
459 | * @param string $url |
||
460 | * |
||
461 | * @return string |
||
462 | */ |
||
463 | protected function formatUrl(string $url): string |
||
464 | { |
||
465 | $uri = $this->urlPrefix.$url; |
||
466 | |||
467 | return $uri === '/' ? '/' : ltrim(rtrim($uri, '/'), '/'); |
||
468 | } |
||
469 | } |
||
470 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive. In addition it looks for parameters that have the generic type
array
and suggests a stricter type likearray<String>
.Most often this is a case of a parameter that can be null in addition to its declared types.