Completed
Pull Request — master (#34)
by
unknown
03:42
created

MenuItem::add()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

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