Completed
Pull Request — master (#57)
by
unknown
01:32
created

MenuItem::dropdown()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21

Duplication

Lines 21
Ratio 100 %

Code Coverage

Tests 4
CRAP Score 2.5

Importance

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