Completed
Pull Request — master (#32)
by
unknown
07:26
created

MenuItem::url()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16

Duplication

Lines 9
Ratio 56.25 %

Code Coverage

Tests 4
CRAP Score 2.686

Importance

Changes 0
Metric Value
dl 9
loc 16
ccs 4
cts 9
cp 0.4444
rs 9.7333
c 0
b 0
f 0
cc 2
nc 2
nop 4
crap 2.686
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
     * Prefix URL.
64
     *
65
     * @var string|null
66
     */
67
    protected $prefixUrl;
68
69
    /**
70
     * Constructor.
71
     *
72
     * @param array $properties
73
     */
74 24
    public function __construct($properties = array())
75
    {
76 24
        $this->properties = $properties;
77 24
        $this->fill($properties);
78 24
    }
79
80
    /**
81
     * Set the icon property when the icon is defined in the link attributes.
82
     *
83
     * @param array $properties
84
     *
85
     * @return array
86
     */
87 24
    protected static function setIconAttribute(array $properties)
88
    {
89 24
        $icon = array_get($properties, 'attributes.icon');
90 24
        if (!is_null($icon)) {
91 1
            $properties['icon'] = $icon;
92
93 1
            array_forget($properties, 'attributes.icon');
94
95 1
            return $properties;
96
        }
97
98 23
        return $properties;
99
    }
100
101
     /**
102
     * Set Prefix URL.
103
     *
104
     * @param string $prefixUrl
105
     *
106
     * @return $this
107
     */
108
    public function setPrefixUrl($prefixUrl)
109
    {
110
        $this->prefixUrl = $prefixUrl;
111
112
        return $this;
113
    }
114
115
    /**
116
     * Get random name.
117
     *
118
     * @param array $attributes
119
     *
120
     * @return string
121
     */
122
    protected static function getRandomName(array $attributes)
123
    {
124
        return substr(md5(array_get($attributes, 'title', str_random(6))), 0, 5);
125
    }
126
127
    /**
128
     * Create new static instance.
129
     *
130
     * @param array $properties
131
     *
132
     * @return static
133
     */
134 24
    public static function make(array $properties)
135
    {
136 24
        $properties = self::setIconAttribute($properties);
137
138 24
        return new static($properties);
139
    }
140
141
    /**
142
     * Fill the attributes.
143
     *
144
     * @param array $attributes
145
     */
146 24
    public function fill($attributes)
147
    {
148 24
        foreach ($attributes as $key => $value) {
149 23
            if (in_array($key, $this->fillable)) {
150 23
                $this->{$key} = $value;
151
            }
152
        }
153 24
    }
154
155
    /**
156
     * Create new menu child item using array.
157
     *
158
     * @param $attributes
159
     *
160
     * @return $this
161
     */
162 2
    public function child($attributes)
163
    {
164 2
        $this->childs[] = static::make($attributes);
165
166 2
        return $this;
167
    }
168
169
    /**
170
     * Register new child menu with dropdown.
171
     *
172
     * @param $title
173
     * @param callable $callback
174
     *
175
     * @return $this
176
     */
177 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...
178
    {
179 9
        $properties = compact('title', 'order', 'attributes');
180
181 9
        if (func_num_args() === 3) {
182
            $arguments = func_get_args();
183
184
            $title = array_get($arguments, 0);
185
            $attributes = array_get($arguments, 2);
186
187
            $properties = compact('title', 'attributes');
188
        }
189
190 9
        $child = static::make($properties);
191
192 9
        call_user_func($callback, $child);
193
194 9
        $this->childs[] = $child;
195
196 9
        return $child;
197
    }
198
199
    /**
200
     * Create new menu item and set the action to route.
201
     *
202
     * @param $route
203
     * @param $title
204
     * @param array $parameters
205
     * @param array $attributes
206
     *
207
     * @return MenuItem
208
     */
209 3
    public function route($route, $title, $parameters = array(), $order = 0, $attributes = array())
210
    {
211 3 View Code Duplication
        if (func_num_args() === 4) {
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...
212
            $arguments = func_get_args();
213
214
            return $this->add([
215
                'route' => [array_get($arguments, 0), array_get($arguments, 2)],
216
                'title' => array_get($arguments, 1),
217
                'attributes' => array_get($arguments, 3),
218
            ]);
219
        }
220
221 3
        $route = array($route, $parameters);
222
223 3
        return $this->add(compact('route', 'title', 'order', 'attributes'));
224
    }
225
226
    /**
227
     * Format URL.
228
     *
229
     * @param string $url
230
     *
231
     * @return string
232
     */
233 6
    protected function formatUrl($url)
234
    {
235 6
        $uri = !is_null($this->prefixUrl) ? $this->prefixUrl . $url : $url;
236
237 6
        return $uri == '/' ? '/' : ltrim(rtrim($uri, '/'), '/');
238
    }
239
240
    /**
241
     * Create new menu item  and set the action to url.
242
     *
243
     * @param $url
244
     * @param $title
245
     * @param array $attributes
246
     *
247
     * @return MenuItem
248
     */
249 6
    public function url($url, $title, $order = 0, $attributes = array())
250
    {
251 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...
252
            $arguments = func_get_args();
253
254
            return $this->add([
255
                'url' => $this->formatUrl(array_get($arguments, 0)),
256
                'title' => array_get($arguments, 1),
257
                'attributes' => array_get($arguments, 2),
258
            ]);
259
        }
260
261 6
        $url = $this->formatUrl($url);
262
        
263 6
        return $this->add(compact('url', 'title', 'order', 'attributes'));
264
    }
265
266
    /**
267
     * Add new child item.
268
     *
269
     * @param array $properties
270
     *
271
     * @return $this
272
     */
273 9
    public function add(array $properties)
274
    {
275 9
        $item = static::make($properties);
276
277 9
        $this->childs[] = $item;
278
279 9
        return $item;
280
    }
281
282
    /**
283
     * Add new divider.
284
     *
285
     * @param int $order
286
     *
287
     * @return self
288
     */
289 1
    public function addDivider($order = null)
290
    {
291 1
        $item = static::make(array('name' => 'divider', 'order' => $order));
292
293 1
        $this->childs[] = $item;
294
295 1
        return $item;
296
    }
297
298
    /**
299
     * Alias method instead "addDivider".
300
     *
301
     * @param int $order
302
     *
303
     * @return MenuItem
304
     */
305 1
    public function divider($order = null)
306
    {
307 1
        return $this->addDivider($order);
308
    }
309
310
    /**
311
     * Add dropdown header.
312
     *
313
     * @param $title
314
     *
315
     * @return $this
316
     */
317 2
    public function addHeader($title)
318
    {
319 2
        $item = static::make(array(
320 2
            'name' => 'header',
321 2
            'title' => $title,
322
        ));
323
324 2
        $this->childs[] = $item;
325
326 2
        return $item;
327
    }
328
329
    /**
330
     * Same with "addHeader" method.
331
     *
332
     * @param $title
333
     *
334
     * @return $this
335
     */
336 2
    public function header($title)
337
    {
338 2
        return $this->addHeader($title);
339
    }
340
341
    /**
342
     * Get childs.
343
     *
344
     * @return array
345
     */
346 10
    public function getChilds()
347
    {
348 10
        if (config('menus.ordering')) {
349 1
            return collect($this->childs)->sortBy('order')->all();
350
        }
351
352 9
        return $this->childs;
353
    }
354
355
    /**
356
     * Get url.
357
     *
358
     * @return string
359
     */
360 3
    public function getUrl()
361
    {
362 3
        if ($this->route !== null) {
363 1
            return route($this->route[0], $this->route[1]);
364
        }
365
366 2
        return url($this->url);
367
    }
368
369
    /**
370
     * Get request url.
371
     *
372
     * @return string
373
     */
374 1
    public function getRequest()
375
    {
376 1
        return ltrim(str_replace(url('/'), '', $this->getUrl()), '/');
377
    }
378
379
    /**
380
     * Get icon.
381
     *
382
     * @param null|string $default
383
     *
384
     * @return string
385
     */
386 3
    public function getIcon($default = null)
387
    {
388 3
        if ($this->icon !== null && $this->icon !== '') {
389 1
            return '<i class="' . $this->icon . '"></i>';
390
        }
391 2
        if ($default === null) {
392 1
            return $default;
393
        }
394
395 1
        return '<i class="' . $default . '"></i>';
396
    }
397
398
    /**
399
     * Get properties.
400
     *
401
     * @return array
402
     */
403 2
    public function getProperties()
404
    {
405 2
        return $this->properties;
406
    }
407
408
    /**
409
     * Get HTML attribute data.
410
     *
411
     * @return mixed
412
     */
413 1
    public function getAttributes()
414
    {
415 1
        $attributes = $this->attributes ? $this->attributes : [];
416
417 1
        array_forget($attributes, ['active', 'icon']);
418
419 1
        return HTML::attributes($attributes);
420
    }
421
422
    /**
423
     * Check is the current item divider.
424
     *
425
     * @return bool
426
     */
427 1
    public function isDivider()
428
    {
429 1
        return $this->is('divider');
430
    }
431
432
    /**
433
     * Check is the current item divider.
434
     *
435
     * @return bool
436
     */
437 1
    public function isHeader()
438
    {
439 1
        return $this->is('header');
440
    }
441
442
    /**
443
     * Check is the current item divider.
444
     *
445
     * @param $name
446
     *
447
     * @return bool
448
     */
449 2
    public function is($name)
450
    {
451 2
        return $this->name == $name;
452
    }
453
454
    /**
455
     * Check is the current item has sub menu .
456
     *
457
     * @return bool
458
     */
459 1
    public function hasSubMenu()
460
    {
461 1
        return !empty($this->childs);
462
    }
463
464
    /**
465
     * Same with hasSubMenu.
466
     *
467
     * @return bool
468
     */
469 1
    public function hasChilds()
470
    {
471 1
        return $this->hasSubMenu();
472
    }
473
474
    /**
475
     * Check the active state for current menu.
476
     *
477
     * @return mixed
478
     */
479
    public function hasActiveOnChild()
480
    {
481
        if ($this->inactive()) {
482
            return false;
483
        }
484
485
        return $this->hasChilds() ? $this->getActiveStateFromChilds() : false;
486
    }
487
488
    /**
489
     * Get active state from child menu items.
490
     *
491
     * @return bool
492
     */
493
    public function getActiveStateFromChilds()
494
    {
495
        foreach ($this->getChilds() as $child) {
496
            if ($child->inactive()) {
497
                continue;
498
            }
499
            if ($child->hasChilds()) {
500
                if ($child->getActiveStateFromChilds()) {
501
                    return true;
502
                }
503
            } elseif ($child->isActive()) {
504
                return true;
505
            } elseif ($child->hasRoute() && $child->getActiveStateFromRoute()) {
506
                return true;
507
            } elseif ($child->getActiveStateFromUrl()) {
508
                return true;
509
            }
510
        }
511
512
        return false;
513
    }
514
515
    /**
516
     * Get inactive state.
517
     *
518
     * @return bool
519
     */
520
    public function inactive()
521
    {
522
        $inactive = $this->getInactiveAttribute();
523
524
        if (is_bool($inactive)) {
525
            return $inactive;
526
        }
527
528
        if ($inactive instanceof \Closure) {
529
            return call_user_func($inactive);
530
        }
531
532
        return false;
533
    }
534
535
    /**
536
     * Get active attribute.
537
     *
538
     * @return string
539
     */
540
    public function getActiveAttribute()
541
    {
542
        return array_get($this->attributes, 'active');
543
    }
544
545
    /**
546
     * Get inactive attribute.
547
     *
548
     * @return string
549
     */
550
    public function getInactiveAttribute()
551
    {
552
        return array_get($this->attributes, 'inactive');
553
    }
554
555
    /**
556
     * Get active state for current item.
557
     *
558
     * @return mixed
559
     */
560
    public function isActive()
561
    {
562
        if ($this->inactive()) {
563
            return false;
564
        }
565
566
        $active = $this->getActiveAttribute();
567
568
        if (is_bool($active)) {
569
            return $active;
570
        }
571
572
        if ($active instanceof \Closure) {
573
            return call_user_func($active);
574
        }
575
576
        if ($this->hasRoute()) {
577
            return $this->getActiveStateFromRoute();
578
        }
579
580
        return $this->getActiveStateFromUrl();
581
    }
582
583
    /**
584
     * Determine the current item using route.
585
     *
586
     * @return bool
587
     */
588
    protected function hasRoute()
589
    {
590
        return !empty($this->route);
591
    }
592
593
    /**
594
     * Get active status using route.
595
     *
596
     * @return bool
597
     */
598
    protected function getActiveStateFromRoute()
599
    {
600
        return Request::is(str_replace(url('/') . '/', '', $this->getUrl()));
601
    }
602
603
    /**
604
     * Get active status using request url.
605
     *
606
     * @return bool
607
     */
608
    protected function getActiveStateFromUrl()
609
    {
610
        return Request::is($this->url);
611
    }
612
613
    /**
614
     * Set order value.
615
     *
616
     * @param  int $order
617
     * @return self
618
     */
619
    public function order($order)
620
    {
621
        $this->order = $order;
622
623
        return $this;
624
    }
625
626
    /**
627
     * Set hide condition for current menu item.
628
     *
629
     * @param  Closure
630
     * @return boolean
631
     */
632
    public function hideWhen(Closure $callback)
633
    {
634
        $this->hideWhen = $callback;
635
636
        return $this;
637
    }
638
639
    /**
640
     * Determine whether the menu item is hidden.
641
     *
642
     * @return boolean
643
     */
644
    public function hidden()
645
    {
646
        if (is_null($this->hideWhen)) {
647
            return false;
648
        }
649
650
        return call_user_func($this->hideWhen) == true;
651
    }
652
653
    /**
654
     * Get the instance as an array.
655
     *
656
     * @return array
657
     */
658
    public function toArray()
659
    {
660
        return $this->getProperties();
661
    }
662
663
    /**
664
     * Get property.
665
     *
666
     * @param string $key
667
     *
668
     * @return string|null
669
     */
670 4
    public function __get($key)
671
    {
672 4
        return isset($this->$key) ? $this->$key : null;
673
    }
674
}
675