1 | <?php |
||||||
2 | |||||||
3 | namespace jeremykenedy\LaravelRoles\Traits; |
||||||
4 | |||||||
5 | use Illuminate\Database\Eloquent\Builder; |
||||||
6 | use Illuminate\Database\Eloquent\Collection; |
||||||
7 | use Illuminate\Database\Eloquent\Model; |
||||||
8 | use Illuminate\Database\Eloquent\Relations\BelongsToMany; |
||||||
9 | use Illuminate\Support\Str; |
||||||
10 | use InvalidArgumentException; |
||||||
11 | use jeremykenedy\LaravelRoles\Models\Permission; |
||||||
12 | use jeremykenedy\LaravelRoles\Models\Role; |
||||||
13 | |||||||
14 | trait HasRoleAndPermission |
||||||
15 | { |
||||||
16 | /** |
||||||
17 | * Property for caching roles. |
||||||
18 | * |
||||||
19 | * @var Collection|null |
||||||
20 | */ |
||||||
21 | protected $roles; |
||||||
22 | |||||||
23 | /** |
||||||
24 | * Property for caching permissions. |
||||||
25 | * |
||||||
26 | * @var Collection|null |
||||||
27 | */ |
||||||
28 | protected $permissions; |
||||||
29 | |||||||
30 | /** |
||||||
31 | * User belongs to many roles. |
||||||
32 | * |
||||||
33 | * @return BelongsToMany |
||||||
34 | */ |
||||||
35 | public function roles() |
||||||
36 | { |
||||||
37 | return $this->belongsToMany(config('roles.models.role'), config('roles.roleUserTable'))->withTimestamps(); |
||||||
38 | } |
||||||
39 | |||||||
40 | /** |
||||||
41 | * Get all roles as collection. |
||||||
42 | * |
||||||
43 | * @return Collection |
||||||
44 | */ |
||||||
45 | public function getRoles() |
||||||
46 | { |
||||||
47 | if (!$this->roles) { |
||||||
48 | if (method_exists($this, 'loadMissing')) { |
||||||
49 | $this->loadMissing('roles'); |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
50 | } else { |
||||||
51 | if (!array_key_exists('roles', $this->relations)) { |
||||||
52 | $this->load('roles'); |
||||||
0 ignored issues
–
show
The method
load() does not exist on jeremykenedy\LaravelRole...ts\HasRoleAndPermission . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
53 | } |
||||||
54 | } |
||||||
55 | if (method_exists($this, 'getRelation')) { |
||||||
56 | $this->roles = $this->getRelation('roles'); |
||||||
0 ignored issues
–
show
The method
getRelation() does not exist on jeremykenedy\LaravelRole...ts\HasRoleAndPermission . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
57 | } else { |
||||||
58 | $this->roles = $this->relations['roles']; |
||||||
59 | } |
||||||
60 | } |
||||||
61 | |||||||
62 | return $this->roles; |
||||||
63 | } |
||||||
64 | |||||||
65 | /** |
||||||
66 | * Check if the user has a role or roles. |
||||||
67 | * |
||||||
68 | * @param int|string|array $role |
||||||
69 | * @param bool $all |
||||||
70 | * |
||||||
71 | * @return bool |
||||||
72 | */ |
||||||
73 | public function hasRole($role, $all = false) |
||||||
74 | { |
||||||
75 | if ($this->isPretendEnabled()) { |
||||||
76 | return $this->pretend('hasRole'); |
||||||
77 | } |
||||||
78 | |||||||
79 | if (!$all) { |
||||||
80 | return $this->hasOneRole($role); |
||||||
81 | } |
||||||
82 | |||||||
83 | return $this->hasAllRoles($role); |
||||||
84 | } |
||||||
85 | |||||||
86 | /** |
||||||
87 | * Check if the user has at least one of the given roles. |
||||||
88 | * |
||||||
89 | * @param int|string|array $role |
||||||
90 | * |
||||||
91 | * @return bool |
||||||
92 | */ |
||||||
93 | public function hasOneRole($role) |
||||||
94 | { |
||||||
95 | foreach ($this->getArrayFrom($role) as $role) { |
||||||
0 ignored issues
–
show
|
|||||||
96 | if ($this->checkRole($role)) { |
||||||
97 | return true; |
||||||
98 | } |
||||||
99 | } |
||||||
100 | |||||||
101 | return false; |
||||||
102 | } |
||||||
103 | |||||||
104 | /** |
||||||
105 | * Check if the user has all roles. |
||||||
106 | * |
||||||
107 | * @param int|string|array $role |
||||||
108 | * |
||||||
109 | * @return bool |
||||||
110 | */ |
||||||
111 | public function hasAllRoles($role) |
||||||
112 | { |
||||||
113 | foreach ($this->getArrayFrom($role) as $role) { |
||||||
0 ignored issues
–
show
|
|||||||
114 | if (!$this->checkRole($role)) { |
||||||
115 | return false; |
||||||
116 | } |
||||||
117 | } |
||||||
118 | |||||||
119 | return true; |
||||||
120 | } |
||||||
121 | |||||||
122 | /** |
||||||
123 | * Check if the user has role. |
||||||
124 | * |
||||||
125 | * @param int|string $role |
||||||
126 | * |
||||||
127 | * @return bool |
||||||
128 | */ |
||||||
129 | public function checkRole($role) |
||||||
130 | { |
||||||
131 | return $this->getRoles()->contains(function ($value) use ($role) { |
||||||
132 | return $role == $value->id || Str::is($role, $value->slug); |
||||||
133 | }); |
||||||
134 | } |
||||||
135 | |||||||
136 | /** |
||||||
137 | * Attach role to a user. |
||||||
138 | * |
||||||
139 | * @param int|Role $role |
||||||
140 | * |
||||||
141 | * @return null|bool |
||||||
142 | */ |
||||||
143 | public function attachRole($role) |
||||||
144 | { |
||||||
145 | if ($this->getRoles()->contains($role)) { |
||||||
146 | return true; |
||||||
147 | } |
||||||
148 | $this->resetRoles(); |
||||||
149 | |||||||
150 | return $this->roles()->attach($role); |
||||||
151 | } |
||||||
152 | |||||||
153 | /** |
||||||
154 | * Detach role from a user. |
||||||
155 | * |
||||||
156 | * @param int|Role $role |
||||||
157 | * |
||||||
158 | * @return int |
||||||
159 | */ |
||||||
160 | public function detachRole($role) |
||||||
161 | { |
||||||
162 | $this->resetRoles(); |
||||||
163 | |||||||
164 | return $this->roles()->detach($role); |
||||||
165 | } |
||||||
166 | |||||||
167 | /** |
||||||
168 | * Detach all roles from a user. |
||||||
169 | * |
||||||
170 | * @return int |
||||||
171 | */ |
||||||
172 | public function detachAllRoles() |
||||||
173 | { |
||||||
174 | $this->resetRoles(); |
||||||
175 | |||||||
176 | return $this->roles()->detach(); |
||||||
177 | } |
||||||
178 | |||||||
179 | /** |
||||||
180 | * Sync roles for a user. |
||||||
181 | * |
||||||
182 | * @param array|\jeremykenedy\LaravelRoles\Models\Role[]|\Illuminate\Database\Eloquent\Collection $roles |
||||||
183 | * |
||||||
184 | * @return array |
||||||
185 | */ |
||||||
186 | public function syncRoles($roles) |
||||||
187 | { |
||||||
188 | $this->resetRoles(); |
||||||
189 | |||||||
190 | return $this->roles()->sync($roles); |
||||||
191 | } |
||||||
192 | |||||||
193 | /** |
||||||
194 | * Get role level of a user. |
||||||
195 | * |
||||||
196 | * @return int |
||||||
197 | */ |
||||||
198 | public function level() |
||||||
199 | { |
||||||
200 | return ($role = $this->getRoles()->sortByDesc('level')->first()) ? $role->level : 0; |
||||||
201 | } |
||||||
202 | |||||||
203 | /** |
||||||
204 | * Get all permissions from roles. |
||||||
205 | * |
||||||
206 | * @return Builder |
||||||
207 | */ |
||||||
208 | public function rolePermissions() |
||||||
209 | { |
||||||
210 | $permissionModel = app(config('roles.models.permission')); |
||||||
211 | $permissionTable = config('roles.permissionsTable'); |
||||||
212 | $roleTable = config('roles.rolesTable'); |
||||||
213 | |||||||
214 | if (!$permissionModel instanceof Model) { |
||||||
215 | throw new InvalidArgumentException('[roles.models.permission] must be an instance of \Illuminate\Database\Eloquent\Model'); |
||||||
216 | } |
||||||
217 | |||||||
218 | if (config('roles.inheritance')) { |
||||||
219 | return $permissionModel::select([$permissionTable.'.*', 'permission_role.created_at as pivot_created_at', 'permission_role.updated_at as pivot_updated_at']) |
||||||
0 ignored issues
–
show
|
|||||||
220 | ->join('permission_role', 'permission_role.permission_id', '=', $permissionTable.'.id') |
||||||
221 | ->join($roleTable, $roleTable.'.id', '=', 'permission_role.role_id') |
||||||
222 | ->whereIn($roleTable.'.id', $this->getRoles()->pluck('id')->toArray()) |
||||||
223 | ->orWhere($roleTable.'.level', '<', $this->level()) |
||||||
224 | ->groupBy([$permissionTable.'.id', $permissionTable.'.name', $permissionTable.'.slug', $permissionTable.'.description', $permissionTable.'.model', $permissionTable.'.created_at', 'permissions.updated_at', $permissionTable.'.deleted_at', 'pivot_created_at', 'pivot_updated_at']); |
||||||
225 | } else { |
||||||
226 | return $permissionModel::select([$permissionTable.'.*', 'permission_role.created_at as pivot_created_at', 'permission_role.updated_at as pivot_updated_at']) |
||||||
0 ignored issues
–
show
|
|||||||
227 | ->join('permission_role', 'permission_role.permission_id', '=', $permissionTable.'.id') |
||||||
228 | ->join($roleTable, $roleTable.'.id', '=', 'permission_role.role_id') |
||||||
229 | ->whereIn($roleTable.'.id', $this->getRoles()->pluck('id')->toArray()) |
||||||
230 | ->groupBy([$permissionTable.'.id', $permissionTable.'.name', $permissionTable.'.slug', $permissionTable.'.description', $permissionTable.'.model', $permissionTable.'.created_at', $permissionTable.'.updated_at', $permissionTable.'.deleted_at', 'pivot_created_at', 'pivot_updated_at']); |
||||||
231 | } |
||||||
232 | } |
||||||
233 | |||||||
234 | /** |
||||||
235 | * User belongs to many permissions. |
||||||
236 | * |
||||||
237 | * @return BelongsToMany |
||||||
238 | */ |
||||||
239 | public function userPermissions() |
||||||
240 | { |
||||||
241 | return $this->belongsToMany(config('roles.models.permission'), config('permissionsUserTable'))->withTimestamps(); |
||||||
242 | } |
||||||
243 | |||||||
244 | /** |
||||||
245 | * Get all permissions as collection. |
||||||
246 | * |
||||||
247 | * @return Collection |
||||||
248 | */ |
||||||
249 | public function getPermissions() |
||||||
250 | { |
||||||
251 | return (!$this->permissions) ? $this->permissions = $this->rolePermissions()->get()->merge($this->userPermissions()->get()) : $this->permissions; |
||||||
252 | } |
||||||
253 | |||||||
254 | /** |
||||||
255 | * Check if the user has a permission or permissions. |
||||||
256 | * |
||||||
257 | * @param int|string|array $permission |
||||||
258 | * @param bool $all |
||||||
259 | * |
||||||
260 | * @return bool |
||||||
261 | */ |
||||||
262 | public function hasPermission($permission, $all = false) |
||||||
263 | { |
||||||
264 | if ($this->isPretendEnabled()) { |
||||||
265 | return $this->pretend('hasPermission'); |
||||||
266 | } |
||||||
267 | |||||||
268 | if (!$all) { |
||||||
269 | return $this->hasOnePermission($permission); |
||||||
270 | } |
||||||
271 | |||||||
272 | return $this->hasAllPermissions($permission); |
||||||
273 | } |
||||||
274 | |||||||
275 | /** |
||||||
276 | * Check if the user has at least one of the given permissions. |
||||||
277 | * |
||||||
278 | * @param int|string|array $permission |
||||||
279 | * |
||||||
280 | * @return bool |
||||||
281 | */ |
||||||
282 | public function hasOnePermission($permission) |
||||||
283 | { |
||||||
284 | foreach ($this->getArrayFrom($permission) as $permission) { |
||||||
0 ignored issues
–
show
|
|||||||
285 | if ($this->checkPermission($permission)) { |
||||||
286 | return true; |
||||||
287 | } |
||||||
288 | } |
||||||
289 | |||||||
290 | return false; |
||||||
291 | } |
||||||
292 | |||||||
293 | /** |
||||||
294 | * Check if the user has all permissions. |
||||||
295 | * |
||||||
296 | * @param int|string|array $permission |
||||||
297 | * |
||||||
298 | * @return bool |
||||||
299 | */ |
||||||
300 | public function hasAllPermissions($permission) |
||||||
301 | { |
||||||
302 | foreach ($this->getArrayFrom($permission) as $permission) { |
||||||
0 ignored issues
–
show
|
|||||||
303 | if (!$this->checkPermission($permission)) { |
||||||
304 | return false; |
||||||
305 | } |
||||||
306 | } |
||||||
307 | |||||||
308 | return true; |
||||||
309 | } |
||||||
310 | |||||||
311 | /** |
||||||
312 | * Check if the user has a permission. |
||||||
313 | * |
||||||
314 | * @param int|string $permission |
||||||
315 | * |
||||||
316 | * @return bool |
||||||
317 | */ |
||||||
318 | public function checkPermission($permission) |
||||||
319 | { |
||||||
320 | return $this->getPermissions()->contains(function ($value) use ($permission) { |
||||||
321 | return $permission == $value->id || Str::is($permission, $value->slug); |
||||||
322 | }); |
||||||
323 | } |
||||||
324 | |||||||
325 | /** |
||||||
326 | * Check if the user is allowed to manipulate with entity. |
||||||
327 | * |
||||||
328 | * @param string $providedPermission |
||||||
329 | * @param Model $entity |
||||||
330 | * @param bool $owner |
||||||
331 | * @param string $ownerColumn |
||||||
332 | * |
||||||
333 | * @return bool |
||||||
334 | */ |
||||||
335 | public function allowed($providedPermission, Model $entity, $owner = true, $ownerColumn = 'user_id') |
||||||
336 | { |
||||||
337 | if ($this->isPretendEnabled()) { |
||||||
338 | return $this->pretend('allowed'); |
||||||
339 | } |
||||||
340 | |||||||
341 | if ($owner === true && $entity->{$ownerColumn} == $this->id) { |
||||||
342 | return true; |
||||||
343 | } |
||||||
344 | |||||||
345 | return $this->isAllowed($providedPermission, $entity); |
||||||
346 | } |
||||||
347 | |||||||
348 | /** |
||||||
349 | * Check if the user is allowed to manipulate with provided entity. |
||||||
350 | * |
||||||
351 | * @param string $providedPermission |
||||||
352 | * @param Model $entity |
||||||
353 | * |
||||||
354 | * @return bool |
||||||
355 | */ |
||||||
356 | protected function isAllowed($providedPermission, Model $entity) |
||||||
357 | { |
||||||
358 | foreach ($this->getPermissions() as $permission) { |
||||||
359 | if ($permission->model != '' && get_class($entity) == $permission->model |
||||||
360 | && ($permission->id == $providedPermission || $permission->slug === $providedPermission) |
||||||
361 | ) { |
||||||
362 | return true; |
||||||
363 | } |
||||||
364 | } |
||||||
365 | |||||||
366 | return false; |
||||||
367 | } |
||||||
368 | |||||||
369 | /** |
||||||
370 | * Attach permission to a user. |
||||||
371 | * |
||||||
372 | * @param int|Permission $permission |
||||||
373 | * |
||||||
374 | * @return null|bool |
||||||
375 | */ |
||||||
376 | public function attachPermission($permission) |
||||||
377 | { |
||||||
378 | if ($this->getPermissions()->contains($permission)) { |
||||||
379 | return true; |
||||||
380 | } |
||||||
381 | $this->permissions = null; |
||||||
382 | |||||||
383 | return $this->userPermissions()->attach($permission); |
||||||
384 | } |
||||||
385 | |||||||
386 | /** |
||||||
387 | * Detach permission from a user. |
||||||
388 | * |
||||||
389 | * @param int|Permission $permission |
||||||
390 | * |
||||||
391 | * @return int |
||||||
392 | */ |
||||||
393 | public function detachPermission($permission) |
||||||
394 | { |
||||||
395 | $this->permissions = null; |
||||||
396 | |||||||
397 | return $this->userPermissions()->detach($permission); |
||||||
398 | } |
||||||
399 | |||||||
400 | /** |
||||||
401 | * Detach all permissions from a user. |
||||||
402 | * |
||||||
403 | * @return int |
||||||
404 | */ |
||||||
405 | public function detachAllPermissions() |
||||||
406 | { |
||||||
407 | $this->permissions = null; |
||||||
408 | |||||||
409 | return $this->userPermissions()->detach(); |
||||||
410 | } |
||||||
411 | |||||||
412 | /** |
||||||
413 | * Sync permissions for a user. |
||||||
414 | * |
||||||
415 | * @param array|\jeremykenedy\LaravelRoles\Models\Permission[]|\Illuminate\Database\Eloquent\Collection $permissions |
||||||
416 | * |
||||||
417 | * @return array |
||||||
418 | */ |
||||||
419 | public function syncPermissions($permissions) |
||||||
420 | { |
||||||
421 | $this->permissions = null; |
||||||
422 | |||||||
423 | return $this->userPermissions()->sync($permissions); |
||||||
424 | } |
||||||
425 | |||||||
426 | /** |
||||||
427 | * Check if pretend option is enabled. |
||||||
428 | * |
||||||
429 | * @return bool |
||||||
430 | */ |
||||||
431 | private function isPretendEnabled() |
||||||
432 | { |
||||||
433 | return (bool) config('roles.pretend.enabled'); |
||||||
434 | } |
||||||
435 | |||||||
436 | /** |
||||||
437 | * Allows to pretend or simulate package behavior. |
||||||
438 | * |
||||||
439 | * @param string $option |
||||||
440 | * |
||||||
441 | * @return bool |
||||||
442 | */ |
||||||
443 | private function pretend($option) |
||||||
444 | { |
||||||
445 | return (bool) config('roles.pretend.options.'.$option); |
||||||
446 | } |
||||||
447 | |||||||
448 | /** |
||||||
449 | * Get an array from argument. |
||||||
450 | * |
||||||
451 | * @param int|string|array $argument |
||||||
452 | * |
||||||
453 | * @return array |
||||||
454 | */ |
||||||
455 | private function getArrayFrom($argument) |
||||||
456 | { |
||||||
457 | return (!is_array($argument)) ? preg_split('/ ?[,|] ?/', $argument) : $argument; |
||||||
458 | } |
||||||
459 | |||||||
460 | protected function resetRoles() |
||||||
461 | { |
||||||
462 | $this->roles = null; |
||||||
463 | if (method_exists($this, 'unsetRelation')) { |
||||||
464 | $this->unsetRelation('roles'); |
||||||
0 ignored issues
–
show
The method
unsetRelation() does not exist on jeremykenedy\LaravelRole...ts\HasRoleAndPermission . Since you implemented __call , consider adding a @method annotation.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
![]() |
|||||||
465 | } else { |
||||||
466 | unset($this->relations['roles']); |
||||||
467 | } |
||||||
468 | } |
||||||
469 | |||||||
470 | public function callMagic($method, $parameters) |
||||||
471 | { |
||||||
472 | if (starts_with($method, 'is')) { |
||||||
473 | return $this->hasRole(snake_case(substr($method, 2), config('roles.separator'))); |
||||||
474 | } elseif (starts_with($method, 'can')) { |
||||||
475 | return $this->hasPermission(snake_case(substr($method, 3), config('roles.separator'))); |
||||||
476 | } elseif (starts_with($method, 'allowed')) { |
||||||
477 | return $this->allowed(snake_case(substr($method, 7), config('roles.separator')), $parameters[0], (isset($parameters[1])) ? $parameters[1] : true, (isset($parameters[2])) ? $parameters[2] : 'user_id'); |
||||||
478 | } |
||||||
479 | |||||||
480 | return parent::__call($method, $parameters); |
||||||
481 | } |
||||||
482 | |||||||
483 | public function __call($method, $parameters) |
||||||
484 | { |
||||||
485 | return $this->callMagic($method, $parameters); |
||||||
486 | } |
||||||
487 | } |
||||||
488 |