Completed
Push — master ( 14eaec...c0ed6e )
by Nicolas
06:58
created

MenuItem::dropdown()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 11

Duplication

Lines 21
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 2.2894

Importance

Changes 0
Metric Value
dl 21
loc 21
ccs 7
cts 12
cp 0.5833
rs 9.3142
c 0
b 0
f 0
cc 2
eloc 11
nc 2
nop 4
crap 2.2894
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 24
    public function __construct($properties = array())
68
    {
69 24
        $this->properties = $properties;
70 24
        $this->fill($properties);
71 24
    }
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 24
    protected static function setIconAttribute(array $properties)
81
    {
82 24
        $icon = array_get($properties, 'attributes.icon');
83 24
        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 23
        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 24
    public static function make(array $properties)
114
    {
115 24
        $properties = self::setIconAttribute($properties);
116
117 24
        return new static($properties);
118
    }
119
120
    /**
121
     * Fill the attributes.
122
     *
123
     * @param array $attributes
124
     */
125 24
    public function fill($attributes)
126
    {
127 24
        foreach ($attributes as $key => $value) {
128 23
            if (in_array($key, $this->fillable)) {
129 23
                $this->{$key} = $value;
130 23
            }
131 24
        }
132 24
    }
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 9 View Code Duplication
    public function dropdown($title, \Closure $callback, $order = 0, array $attributes = array())
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
157
    {
158 9
        $properties = compact('title', 'order', 'attributes');
159
160 9
        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 9
        $child = static::make($properties);
170
171 9
        call_user_func($callback, $child);
172
173 9
        $this->childs[] = $child;
174
175 9
        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 6
    public function url($url, $title, $order = 0, $attributes = array())
215
    {
216 6 View Code Duplication
        if (func_num_args() === 3) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
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 6
        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 9
    public function add(array $properties)
237
    {
238 9
        $item = static::make($properties);
239
240 9
        $this->childs[] = $item;
241
242 9
        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 2
    public function addHeader($title)
279
    {
280 2
        $item = static::make(array(
281 2
            'name' => 'header',
282 2
            'title' => $title,
283 2
        ));
284
285 2
        $this->childs[] = $item;
286
287 2
        return $item;
288
    }
289
290
    /**
291
     * Same with "addHeader" method.
292
     *
293
     * @param $title
294
     *
295
     * @return $this
296
     */
297 2
    public function header($title)
298
    {
299 2
        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
Documentation introduced by
$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 1
    public function isDivider()
389
    {
390 1
        return $this->is('divider');
391
    }
392
393
    /**
394
     * Check is the current item divider.
395
     *
396
     * @return bool
397
     */
398 1
    public function isHeader()
399
    {
400 1
        return $this->is('header');
401
    }
402
403
    /**
404
     * Check is the current item divider.
405
     *
406
     * @param $name
407
     *
408
     * @return bool
409
     */
410 2
    public function is($name)
411
    {
412 2
        return $this->name == $name;
413
    }
414
415
    /**
416
     * Check is the current item has sub menu .
417
     *
418
     * @return bool
419
     */
420 1
    public function hasSubMenu()
421
    {
422 1
        return !empty($this->childs);
423
    }
424
425
    /**
426
     * Same with hasSubMenu.
427
     *
428
     * @return bool
429
     */
430 1
    public function hasChilds()
431
    {
432 1
        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
            }
460
            if ($child->hasChilds()) {
461
                if ($child->getActiveStateFromChilds()) {
462
                    return true;
463
                }
464
            } elseif ($child->isActive()) {
465
                return true;
466
            } elseif ($child->hasRoute() && $child->getActiveStateFromRoute()) {
467
                return true;
468
            } elseif ($child->getActiveStateFromUrl()) {
469
                return true;
470
            }
471
        }
472
473
        return false;
474
    }
475
476
    /**
477
     * Get inactive state.
478
     *
479
     * @return bool
480
     */
481
    public function inactive()
482
    {
483
        $inactive = $this->getInactiveAttribute();
484
485
        if (is_bool($inactive)) {
486
            return $inactive;
487
        }
488
489
        if ($inactive instanceof \Closure) {
490
            return call_user_func($inactive);
491
        }
492
493
        return false;
494
    }
495
496
    /**
497
     * Get active attribute.
498
     *
499
     * @return string
500
     */
501
    public function getActiveAttribute()
502
    {
503
        return array_get($this->attributes, 'active');
504
    }
505
506
    /**
507
     * Get inactive attribute.
508
     *
509
     * @return string
510
     */
511
    public function getInactiveAttribute()
512
    {
513
        return array_get($this->attributes, 'inactive');
514
    }
515
516
    /**
517
     * Get active state for current item.
518
     *
519
     * @return mixed
520
     */
521
    public function isActive()
522
    {
523
        if ($this->inactive()) {
524
            return false;
525
        }
526
527
        $active = $this->getActiveAttribute();
528
529
        if (is_bool($active)) {
530
            return $active;
531
        }
532
533
        if ($active instanceof \Closure) {
534
            return call_user_func($active);
535
        }
536
537
        if ($this->hasRoute()) {
538
            return $this->getActiveStateFromRoute();
539
        }
540
541
        return $this->getActiveStateFromUrl();
542
    }
543
544
    /**
545
     * Determine the current item using route.
546
     *
547
     * @return bool
548
     */
549
    protected function hasRoute()
550
    {
551
        return !empty($this->route);
552
    }
553
554
    /**
555
     * Get active status using route.
556
     *
557
     * @return bool
558
     */
559
    protected function getActiveStateFromRoute()
560
    {
561
        return Request::is(str_replace(url('/') . '/', '', $this->getUrl()));
562
    }
563
564
    /**
565
     * Get active status using request url.
566
     *
567
     * @return bool
568
     */
569
    protected function getActiveStateFromUrl()
570
    {
571
        return Request::is($this->url);
572
    }
573
574
    /**
575
     * Set order value.
576
     *
577
     * @param  int $order
578
     * @return self
579
     */
580
    public function order($order)
581
    {
582
        $this->order = $order;
583
584
        return $this;
585
    }
586
587
    /**
588
     * Set hide condition for current menu item.
589
     *
590
     * @param  Closure
591
     * @return boolean
592
     */
593
    public function hideWhen(Closure $callback)
594
    {
595
        $this->hideWhen = $callback;
596
597
        return $this;
598
    }
599
600
    /**
601
     * Determine whether the menu item is hidden.
602
     *
603
     * @return boolean
604
     */
605
    public function hidden()
606
    {
607
        if (is_null($this->hideWhen)) {
608
            return false;
609
        }
610
611
        return call_user_func($this->hideWhen) == true;
612
    }
613
614
    /**
615
     * Get the instance as an array.
616
     *
617
     * @return array
618
     */
619
    public function toArray()
620
    {
621
        return $this->getProperties();
622
    }
623
624
    /**
625
     * Get property.
626
     *
627
     * @param string $key
628
     *
629
     * @return string|null
630
     */
631 4
    public function __get($key)
632
    {
633 4
        return isset($this->$key) ? $this->$key : null;
634
    }
635
}
636