Completed
Pull Request — master (#17)
by Nauris
10:18
created

MenuItem::setAuthAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 13
Code Lines 7

Duplication

Lines 13
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 2

Importance

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