1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace PhpCollective\MenuMaker; |
4
|
|
|
|
5
|
|
|
use Cache; |
6
|
|
|
use Route; |
7
|
|
|
use Kalnoy\Nestedset\Collection; |
8
|
|
|
use PhpCollective\MenuMaker\Storage\Role; |
9
|
|
|
use PhpCollective\MenuMaker\Storage\Menu; |
10
|
|
|
|
11
|
|
|
trait MenuMaker |
12
|
|
|
{ |
13
|
|
|
protected $section; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* The group that associates with the group. |
17
|
|
|
*/ |
18
|
|
|
public function roles() |
19
|
|
|
{ |
20
|
|
|
return $this->belongsToMany(Role::class, 'pcmm_role_user', 'user_id', 'role_id'); |
|
|
|
|
21
|
|
|
} |
22
|
|
|
|
23
|
|
|
public function menus($alias) |
24
|
|
|
{ |
25
|
|
|
$this->section = Menu::whereAlias($alias)->first(); |
26
|
|
|
|
27
|
|
|
if (! $this->section) { |
28
|
|
|
return collect([]); |
29
|
|
|
} |
30
|
|
|
return $this->getMenuItemsWithActive(); |
31
|
|
|
|
32
|
|
|
} |
33
|
|
|
|
34
|
|
|
protected function getMenuItemsWithActive() |
35
|
|
|
{ |
36
|
|
|
$currentRoute = Route::currentRouteName(); |
37
|
|
|
$currentPath = request()->path(); |
38
|
|
|
$menus = $this->getMenuItems(); |
39
|
|
|
|
40
|
|
|
$traverse = function ($menus) use (&$traverse, $currentRoute, $currentPath) { |
41
|
|
|
$checked = collect([]); |
42
|
|
|
foreach ($menus as $key => $menu) { |
43
|
|
|
$menu['children'] = $traverse($menu['children'], $currentRoute, $currentPath); |
44
|
|
|
if((is_array($menu['routes']) && in_array($currentRoute, $menu['routes'])) |
45
|
|
|
|| $currentPath === $menu['link'] |
46
|
|
|
|| $menu['children']->where('active', true)->count()) |
47
|
|
|
{ |
48
|
|
|
$menu['active'] = true; |
49
|
|
|
} |
50
|
|
|
$checked->put($key, new MenuItem($menu)); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
return $checked; |
54
|
|
|
}; |
55
|
|
|
|
56
|
|
|
return $traverse($menus); |
57
|
|
|
} |
58
|
|
|
|
59
|
|
|
protected function getMenuItems() |
60
|
|
|
{ |
61
|
|
|
return Cache::rememberForever('menus.section.' . optional($this->section)->id . '.user.' . $this->id, function () { |
62
|
|
|
return $this->admin() |
63
|
|
|
? $this->getAdminMenuItems() |
64
|
|
|
: $this->getUserMenuItems(); |
65
|
|
|
}); |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
private function getAdminMenuItems() |
69
|
|
|
{ |
70
|
|
|
$this->section->load([ |
71
|
|
|
'descendants' => function ($query) { |
72
|
|
|
$query->visible(); |
73
|
|
|
} |
74
|
|
|
]); |
75
|
|
|
|
76
|
|
|
return self::buildTree($this->section->descendants, $this->section->id); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
private function getUserMenuItems() |
80
|
|
|
{ |
81
|
|
|
$this->section->load([ |
82
|
|
|
'descendants' => function ($query) { |
83
|
|
|
$query->with([ |
84
|
|
|
'ancestors' => function ($query) { |
85
|
|
|
$query->descendantsOf($this->section); |
86
|
|
|
} |
87
|
|
|
])->select('pcmm_menus.*') |
88
|
|
|
->leftJoin('pcmm_menu_role', 'pcmm_menus.id', '=', 'pcmm_menu_role.menu_id') |
89
|
|
|
->leftJoin('pcmm_roles', 'pcmm_menu_role.role_id', '=', 'pcmm_roles.id') |
90
|
|
|
->leftJoin('pcmm_role_user', 'pcmm_roles.id', '=', 'pcmm_role_user.role_id') |
91
|
|
|
->leftJoin($this->getTable(), 'pcmm_role_user.user_id', '=', $this->getTable() . '.id') |
|
|
|
|
92
|
|
|
->visible() |
93
|
|
|
->where(function ($query) { |
94
|
|
|
$query->public() |
95
|
|
|
->orWhere(function ($query) { |
96
|
|
|
$query->where('pcmm_menus.privilege', 'PROTECTED') |
97
|
|
|
->where('pcmm_roles.is_active', true) |
98
|
|
|
->where($this->getTable() . '.id', $this->id); |
99
|
|
|
}); |
100
|
|
|
}); |
101
|
|
|
} |
102
|
|
|
]); |
103
|
|
|
|
104
|
|
|
$items = $this->section->descendants->reject(function ($item) { |
105
|
|
|
return $item->ancestors->contains('privilege', 'PRIVATE') |
106
|
|
|
|| $item->ancestors->contains('visible', false); |
107
|
|
|
}); |
108
|
|
|
|
109
|
|
|
$menus = collect([]); |
110
|
|
|
foreach ($items as $last) { |
111
|
|
|
$item = self::buildPartialTree($last->ancestors, $last); |
112
|
|
|
if ($menus->has($item['id'])) { |
113
|
|
|
$menus = self::mergeTree($menus, $item); |
114
|
|
|
} else { |
115
|
|
|
$menus->put($item['id'], $item); |
116
|
|
|
} |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
return $menus; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
protected static function mergeTree($menus, $item) |
123
|
|
|
{ |
124
|
|
|
if (isset($menus[$item['id']])) { |
125
|
|
|
$childItem = $item['children']->first(); |
126
|
|
|
if ($menus[$item['id']]['children']->has($childItem['id'])) { |
127
|
|
|
$children = $menus[$item['id']]['children']; |
128
|
|
|
$menus[$item['id']]['children'] = self::mergeTree($children, $childItem); |
129
|
|
|
} else { |
130
|
|
|
$menus[$item['id']]['children']->put($childItem['id'], $childItem); |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
return $menus; |
134
|
|
|
} |
135
|
|
|
|
136
|
|
|
protected static function buildPartialTree(Collection $nodes, $lastChild) |
137
|
|
|
{ |
138
|
|
|
if ($nodes->count()) { |
139
|
|
|
$node = $nodes->shift(); |
140
|
|
|
$element = self::prepareMenuItem($node); |
141
|
|
|
$child = $nodes->count() |
142
|
|
|
? self::buildPartialTree($nodes, $lastChild) |
143
|
|
|
: self::prepareMenuItem($lastChild); |
144
|
|
|
|
145
|
|
|
$element['children']->put( |
146
|
|
|
$child['id'], $child |
147
|
|
|
); |
148
|
|
|
} else { |
149
|
|
|
$element = self::prepareMenuItem($lastChild); |
150
|
|
|
} |
151
|
|
|
return $element; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
protected static function buildTree(Collection $nodes, $parent_id = 0) |
155
|
|
|
{ |
156
|
|
|
$branch = collect([]); |
157
|
|
|
|
158
|
|
|
foreach ($nodes as $node) { |
159
|
|
|
if ($node->parent_id == $parent_id) { |
160
|
|
|
|
161
|
|
|
$element = self::prepareMenuItem($node); |
162
|
|
|
|
163
|
|
|
$children = self::buildTree($node->children()->visible()->get(), $node->id); |
164
|
|
|
if ($children) { |
165
|
|
|
$element['children'] = $children; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
$branch->put($element['id'], $element); |
169
|
|
|
} |
170
|
|
|
} |
171
|
|
|
|
172
|
|
|
return $branch; |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
protected static function prepareMenuItem(Menu $node) |
176
|
|
|
{ |
177
|
|
|
return [ |
178
|
|
|
'id' => $node->id, |
179
|
|
|
'name' => $node->name, |
180
|
|
|
'alias' => $node->alias, |
181
|
|
|
'routes' => $node->routes, |
182
|
|
|
'link' => $node->link, |
183
|
|
|
'icon' => $node->icon, |
184
|
|
|
'class' => $node->class, |
185
|
|
|
'attr' => $node->attr, |
186
|
|
|
'active' => false, |
187
|
|
|
'children' => collect([]) |
188
|
|
|
]; |
189
|
|
|
} |
190
|
|
|
|
191
|
|
|
public function admin() |
192
|
|
|
{ |
193
|
|
|
return $this->roles()->admin()->exists(); |
194
|
|
|
} |
195
|
|
|
|
196
|
|
|
public function approve($alias) |
197
|
|
|
{ |
198
|
|
|
return $this->admin() || $this->whereHas('roles.menus', function ($query) use ($alias) { |
|
|
|
|
199
|
|
|
$query->whereAlias($alias); |
200
|
|
|
})->exists(); |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
public function authorize($request) |
204
|
|
|
{ |
205
|
|
|
$route = explode_route($request->route()); |
206
|
|
|
return $this->whereHas('roles.menus.permissions', function ($query) use ($route) { |
207
|
|
|
return $query->ofRoute($route); |
208
|
|
|
})->exists(); |
209
|
|
|
} |
210
|
|
|
} |
211
|
|
|
|