Completed
Push — master ( a7eafe...12a2e2 )
by Nicolas
03:02
created

src/MenuItem.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Nwidart\Menus;
4
5
use Closure;
6
use Collective\Html\HtmlFacade as HTML;
7
use Illuminate\Contracts\Support\Arrayable as ArrayableContract;
8
use Illuminate\Support\Facades\Request;
9
10
/**
11
 * @property string url
12
 * @property string route
13
 * @property string title
14
 * @property string name
15
 * @property string icon
16
 * @property int parent
17
 * @property array attributes
18
 * @property bool active
19
 * @property int order
20
 */
21
class MenuItem implements ArrayableContract
22
{
23
    /**
24
     * Array properties.
25
     *
26
     * @var array
27
     */
28
    protected $properties = [];
29
30
    /**
31
     * The child collections for current menu item.
32
     *
33
     * @var array
34
     */
35
    protected $childs = array();
36
37
    /**
38
     * The fillable attribute.
39
     *
40
     * @var array
41
     */
42
    protected $fillable = array(
43
        'url',
44
        'route',
45
        'title',
46
        'name',
47
        'icon',
48
        'parent',
49
        'attributes',
50
        'active',
51
        'order',
52
        'hideWhen',
53
    );
54
55
    /**
56
     * The hideWhen callback.
57
     *
58
     * @var Closure
59
     */
60
    protected $hideWhen;
61
62
    /**
63
     * Constructor.
64
     *
65
     * @param array $properties
66
     */
67 23
    public function __construct($properties = array())
68
    {
69 23
        $this->properties = $properties;
70 23
        $this->fill($properties);
71 23
    }
72
73
    /**
74
     * Set the icon property when the icon is defined in the link attributes.
75
     *
76
     * @param array $properties
77
     *
78
     * @return array
79
     */
80 23
    protected static function setIconAttribute(array $properties)
81
    {
82 23
        $icon = array_get($properties, 'attributes.icon');
83 23
        if (!is_null($icon)) {
84 1
            $properties['icon'] = $icon;
85
86 1
            array_forget($properties, 'attributes.icon');
87
88 1
            return $properties;
89
        }
90
91 22
        return $properties;
92
    }
93
94
    /**
95
     * Get random name.
96
     *
97
     * @param array $attributes
98
     *
99
     * @return string
100
     */
101
    protected static function getRandomName(array $attributes)
102
    {
103
        return substr(md5(array_get($attributes, 'title', str_random(6))), 0, 5);
104
    }
105
106
    /**
107
     * Create new static instance.
108
     *
109
     * @param array $properties
110
     *
111
     * @return static
112
     */
113 23
    public static function make(array $properties)
114
    {
115 23
        $properties = self::setIconAttribute($properties);
116
117 23
        return new static($properties);
118
    }
119
120
    /**
121
     * Fill the attributes.
122
     *
123
     * @param array $attributes
124
     */
125 23
    public function fill($attributes)
126
    {
127 23
        foreach ($attributes as $key => $value) {
128 22
            if (in_array($key, $this->fillable)) {
129 22
                $this->{$key} = $value;
130
            }
131
        }
132 23
    }
133
134
    /**
135
     * Create new menu child item using array.
136
     *
137
     * @param $attributes
138
     *
139
     * @return $this
140
     */
141 2
    public function child($attributes)
142
    {
143 2
        $this->childs[] = static::make($attributes);
144
145 2
        return $this;
146
    }
147
148
    /**
149
     * Register new child menu with dropdown.
150
     *
151
     * @param $title
152
     * @param callable $callback
153
     *
154
     * @return $this
155
     */
156 8 View Code Duplication
    public function dropdown($title, \Closure $callback, $order = 0, array $attributes = array())
157
    {
158 8
        $properties = compact('title', 'order', 'attributes');
159
160 8
        if (func_num_args() === 3) {
161
            $arguments = func_get_args();
162
163
            $title = array_get($arguments, 0);
164
            $attributes = array_get($arguments, 2);
165
166
            $properties = compact('title', 'attributes');
167
        }
168
169 8
        $child = static::make($properties);
170
171 8
        call_user_func($callback, $child);
172
173 8
        $this->childs[] = $child;
174
175 8
        return $child;
176
    }
177
178
    /**
179
     * Create new menu item and set the action to route.
180
     *
181
     * @param $route
182
     * @param $title
183
     * @param array $parameters
184
     * @param array $attributes
185
     *
186
     * @return MenuItem
187
     */
188 3
    public function route($route, $title, $parameters = array(), $order = 0, $attributes = array())
189
    {
190 3
        if (func_num_args() === 4) {
191
            $arguments = func_get_args();
192
193
            return $this->add([
194
                'route' => [array_get($arguments, 0), array_get($arguments, 2)],
195
                'title' => array_get($arguments, 1),
196
                'attributes' => array_get($arguments, 3),
197
            ]);
198
        }
199
200 3
        $route = array($route, $parameters);
201
202 3
        return $this->add(compact('route', 'title', 'order', 'attributes'));
203
    }
204
205
    /**
206
     * Create new menu item  and set the action to url.
207
     *
208
     * @param $url
209
     * @param $title
210
     * @param array $attributes
211
     *
212
     * @return MenuItem
213
     */
214 5
    public function url($url, $title, $order = 0, $attributes = array())
215
    {
216 5 View Code Duplication
        if (func_num_args() === 3) {
217
            $arguments = func_get_args();
218
219
            return $this->add([
220
                'url' => array_get($arguments, 0),
221
                'title' => array_get($arguments, 1),
222
                'attributes' => array_get($arguments, 2),
223
            ]);
224
        }
225
226 5
        return $this->add(compact('url', 'title', 'order', 'attributes'));
227
    }
228
229
    /**
230
     * Add new child item.
231
     *
232
     * @param array $properties
233
     *
234
     * @return $this
235
     */
236 8
    public function add(array $properties)
237
    {
238 8
        $item = static::make($properties);
239
240 8
        $this->childs[] = $item;
241
242 8
        return $item;
243
    }
244
245
    /**
246
     * Add new divider.
247
     *
248
     * @param int $order
249
     *
250
     * @return self
251
     */
252 1
    public function addDivider($order = null)
253
    {
254 1
        $item = static::make(array('name' => 'divider', 'order' => $order));
255
256 1
        $this->childs[] = $item;
257
258 1
        return $item;
259
    }
260
261
    /**
262
     * Alias method instead "addDivider".
263
     *
264
     * @return MenuItem
265
     */
266 1
    public function divider()
267
    {
268 1
        return $this->addDivider();
269
    }
270
271
    /**
272
     * Add dropdown header.
273
     *
274
     * @param $title
275
     *
276
     * @return $this
277
     */
278 1
    public function addHeader($title)
279
    {
280 1
        $item = static::make(array(
281 1
            'name' => 'header',
282 1
            'title' => $title,
283
        ));
284
285 1
        $this->childs[] = $item;
286
287 1
        return $item;
288
    }
289
290
    /**
291
     * Same with "addHeader" method.
292
     *
293
     * @param $title
294
     *
295
     * @return $this
296
     */
297 1
    public function header($title)
298
    {
299 1
        return $this->addHeader($title);
300
    }
301
302
    /**
303
     * Get childs.
304
     *
305
     * @return array
306
     */
307 10
    public function getChilds()
308
    {
309 10
        if (config('menus.ordering')) {
310 1
            return collect($this->childs)->sortBy('order')->all();
311
        }
312
313 9
        return $this->childs;
314
    }
315
316
    /**
317
     * Get url.
318
     *
319
     * @return string
320
     */
321 3
    public function getUrl()
322
    {
323 3
        if ($this->route !== null) {
324 1
            return route($this->route[0], $this->route[1]);
0 ignored issues
show
$this->route[1] is of type string, but the function expects a array.

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...
325
        }
326
327 2
        return url($this->url);
328
    }
329
330
    /**
331
     * Get request url.
332
     *
333
     * @return string
334
     */
335 1
    public function getRequest()
336
    {
337 1
        return ltrim(str_replace(url('/'), '', $this->getUrl()), '/');
338
    }
339
340
    /**
341
     * Get icon.
342
     *
343
     * @param null|string $default
344
     *
345
     * @return string
346
     */
347 3
    public function getIcon($default = null)
348
    {
349 3
        if ($this->icon !== null && $this->icon !== '') {
350 1
            return '<i class="' . $this->icon . '"></i>';
351
        }
352 2
        if ($default === null) {
353 1
            return $default;
354
        }
355
356 1
        return '<i class="' . $default . '"></i>';
357
    }
358
359
    /**
360
     * Get properties.
361
     *
362
     * @return array
363
     */
364 2
    public function getProperties()
365
    {
366 2
        return $this->properties;
367
    }
368
369
    /**
370
     * Get HTML attribute data.
371
     *
372
     * @return mixed
373
     */
374 1
    public function getAttributes()
375
    {
376 1
        $attributes = $this->attributes ? $this->attributes : [];
377
378 1
        array_forget($attributes, ['active', 'icon']);
379
380 1
        return HTML::attributes($attributes);
381
    }
382
383
    /**
384
     * Check is the current item divider.
385
     *
386
     * @return bool
387
     */
388
    public function isDivider()
389
    {
390
        return $this->is('divider');
391
    }
392
393
    /**
394
     * Check is the current item divider.
395
     *
396
     * @return bool
397
     */
398
    public function isHeader()
399
    {
400
        return $this->is('header');
401
    }
402
403
    /**
404
     * Check is the current item divider.
405
     *
406
     * @param $name
407
     *
408
     * @return bool
409
     */
410
    public function is($name)
411
    {
412
        return $this->name == $name;
413
    }
414
415
    /**
416
     * Check is the current item has sub menu .
417
     *
418
     * @return bool
419
     */
420
    public function hasSubMenu()
421
    {
422
        return !empty($this->childs);
423
    }
424
425
    /**
426
     * Same with hasSubMenu.
427
     *
428
     * @return bool
429
     */
430
    public function hasChilds()
431
    {
432
        return $this->hasSubMenu();
433
    }
434
435
    /**
436
     * Check the active state for current menu.
437
     *
438
     * @return mixed
439
     */
440
    public function hasActiveOnChild()
441
    {
442
        if ($this->inactive()) {
443
            return false;
444
        }
445
446
        return $this->hasChilds() ? $this->getActiveStateFromChilds() : false;
447
    }
448
449
    /**
450
     * Get active state from child menu items.
451
     *
452
     * @return bool
453
     */
454
    public function getActiveStateFromChilds()
455
    {
456
        foreach ($this->getChilds() as $child) {
457
            if ($child->inactive()) {
458
                continue;
459
            } elseif ($child->hasChilds()) {
460
                if ($child->getActiveStateFromChilds()) {
461
                    return true;
462
                }
463
            } elseif ($child->isActive()) {
464
                return true;
465
            } elseif ($child->hasRoute() && $child->getActiveStateFromRoute()) {
466
                return true;
467
            } elseif ($child->getActiveStateFromUrl()) {
468
                return true;
469
            }
470
        }
471
472
        return false;
473
    }
474
475
    /**
476
     * Get inactive state.
477
     *
478
     * @return bool
479
     */
480
    public function inactive()
481
    {
482
        $inactive = $this->getInactiveAttribute();
483
484
        if (is_bool($inactive)) {
485
            return $inactive;
486
        }
487
488
        if ($inactive instanceof \Closure) {
489
            return call_user_func($inactive);
490
        }
491
492
        return false;
493
    }
494
495
    /**
496
     * Get active attribute.
497
     *
498
     * @return string
499
     */
500
    public function getActiveAttribute()
501
    {
502
        return array_get($this->attributes, 'active');
503
    }
504
505
    /**
506
     * Get inactive attribute.
507
     *
508
     * @return string
509
     */
510
    public function getInactiveAttribute()
511
    {
512
        return array_get($this->attributes, 'inactive');
513
    }
514
515
    /**
516
     * Get active state for current item.
517
     *
518
     * @return mixed
519
     */
520
    public function isActive()
521
    {
522
        if ($this->inactive()) {
523
            return false;
524
        }
525
526
        $active = $this->getActiveAttribute();
527
528
        if (is_bool($active)) {
529
            return $active;
530
        }
531
532
        if ($active instanceof \Closure) {
533
            return call_user_func($active);
534
        }
535
536
        if ($this->hasRoute()) {
537
            return $this->getActiveStateFromRoute();
538
        } else {
539
            return $this->getActiveStateFromUrl();
540
        }
541
    }
542
543
    /**
544
     * Determine the current item using route.
545
     *
546
     * @return bool
547
     */
548
    protected function hasRoute()
549
    {
550
        return !empty($this->route);
551
    }
552
553
    /**
554
     * Get active status using route.
555
     *
556
     * @return bool
557
     */
558
    protected function getActiveStateFromRoute()
559
    {
560
        return Request::is(str_replace(url('/') . '/', '', $this->getUrl()));
561
    }
562
563
    /**
564
     * Get active status using request url.
565
     *
566
     * @return bool
567
     */
568
    protected function getActiveStateFromUrl()
569
    {
570
        return Request::is($this->url);
571
    }
572
573
    /**
574
     * Set order value.
575
     *
576
     * @param  int $order
577
     * @return self
578
     */
579
    public function order($order)
580
    {
581
        $this->order = $order;
582
583
        return $this;
584
    }
585
586
    /**
587
     * Set hide condition for current menu item.
588
     *
589
     * @param  Closure
590
     * @return boolean
591
     */
592
    public function hideWhen(Closure $callback)
593
    {
594
        $this->hideWhen = $callback;
595
596
        return $this;
597
    }
598
599
    /**
600
     * Determine whether the menu item is hidden.
601
     *
602
     * @return boolean
603
     */
604
    public function hidden()
605
    {
606
        if (is_null($this->hideWhen)) {
607
            return false;
608
        }
609
610
        return call_user_func($this->hideWhen) == true;
611
    }
612
613
    /**
614
     * Get the instance as an array.
615
     *
616
     * @return array
617
     */
618
    public function toArray()
619
    {
620
        return $this->getProperties();
621
    }
622
623
    /**
624
     * Get property.
625
     *
626
     * @param string $key
627
     *
628
     * @return string|null
629
     */
630 4
    public function __get($key)
631
    {
632 4
        return isset($this->$key) ? $this->$key : null;
633
    }
634
}
635