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()) |
|
|
|
|
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) { |
|
|
|
|
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]); |
|
|
|
|
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
|
|
|
|
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.