This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Spatie\Permission\Traits; |
||
4 | |||
5 | use Spatie\Permission\Guard; |
||
6 | use Illuminate\Support\Collection; |
||
7 | use Illuminate\Database\Eloquent\Builder; |
||
8 | use Spatie\Permission\WildcardPermission; |
||
9 | use Spatie\Permission\PermissionRegistrar; |
||
10 | use Spatie\Permission\Contracts\Permission; |
||
11 | use Spatie\Permission\Exceptions\GuardDoesNotMatch; |
||
12 | use Spatie\Permission\Exceptions\PermissionDoesNotExist; |
||
13 | use Illuminate\Database\Eloquent\Relations\BelongsToMany; |
||
14 | use Spatie\Permission\Exceptions\WildcardPermissionInvalidArgument; |
||
15 | |||
16 | trait HasPermissions |
||
17 | { |
||
18 | private $permissionClass; |
||
19 | |||
20 | View Code Duplication | public static function bootHasPermissions() |
|
0 ignored issues
–
show
|
|||
21 | { |
||
22 | static::deleting(function ($model) { |
||
23 | if (method_exists($model, 'isForceDeleting') && ! $model->isForceDeleting()) { |
||
24 | return; |
||
25 | } |
||
26 | |||
27 | $model->permissions()->detach(); |
||
28 | }); |
||
29 | } |
||
30 | |||
31 | public function getPermissionClass() |
||
32 | { |
||
33 | if (! isset($this->permissionClass)) { |
||
34 | $this->permissionClass = app(PermissionRegistrar::class)->getPermissionClass(); |
||
35 | } |
||
36 | |||
37 | return $this->permissionClass; |
||
38 | } |
||
39 | |||
40 | /** |
||
41 | * A model may have multiple direct permissions. |
||
42 | */ |
||
43 | public function permissions(): BelongsToMany |
||
44 | { |
||
45 | return $this->morphToMany( |
||
0 ignored issues
–
show
It seems like
morphToMany() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
46 | config('permission.models.permission'), |
||
47 | 'model', |
||
48 | config('permission.table_names.model_has_permissions'), |
||
49 | config('permission.column_names.model_morph_key'), |
||
50 | 'permission_id' |
||
51 | ); |
||
52 | } |
||
53 | |||
54 | /** |
||
55 | * Scope the model query to certain permissions only. |
||
56 | * |
||
57 | * @param \Illuminate\Database\Eloquent\Builder $query |
||
58 | * @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
||
59 | * |
||
60 | * @return \Illuminate\Database\Eloquent\Builder |
||
61 | */ |
||
62 | public function scopePermission(Builder $query, $permissions): Builder |
||
63 | { |
||
64 | $permissions = $this->convertToPermissionModels($permissions); |
||
65 | |||
66 | $rolesWithPermissions = array_unique(array_reduce($permissions, function ($result, $permission) { |
||
67 | return array_merge($result, $permission->roles->all()); |
||
68 | }, [])); |
||
69 | |||
70 | return $query->where(function (Builder $query) use ($permissions, $rolesWithPermissions) { |
||
71 | $query->whereHas('permissions', function (Builder $subQuery) use ($permissions) { |
||
72 | $subQuery->whereIn(config('permission.table_names.permissions').'.id', \array_column($permissions, 'id')); |
||
73 | }); |
||
74 | if (count($rolesWithPermissions) > 0) { |
||
75 | $query->orWhereHas('roles', function (Builder $subQuery) use ($rolesWithPermissions) { |
||
76 | $subQuery->whereIn(config('permission.table_names.roles').'.id', \array_column($rolesWithPermissions, 'id')); |
||
77 | }); |
||
78 | } |
||
79 | }); |
||
80 | } |
||
81 | |||
82 | /** |
||
83 | * @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
||
84 | * |
||
85 | * @return array |
||
86 | */ |
||
87 | protected function convertToPermissionModels($permissions): array |
||
88 | { |
||
89 | if ($permissions instanceof Collection) { |
||
90 | $permissions = $permissions->all(); |
||
91 | } |
||
92 | |||
93 | $permissions = is_array($permissions) ? $permissions : [$permissions]; |
||
94 | |||
95 | return array_map(function ($permission) { |
||
96 | if ($permission instanceof Permission) { |
||
97 | return $permission; |
||
98 | } |
||
99 | |||
100 | return $this->getPermissionClass()->findByName($permission, $this->getDefaultGuardName()); |
||
101 | }, $permissions); |
||
102 | } |
||
103 | |||
104 | /** |
||
105 | * Determine if the model may perform the given permission. |
||
106 | * |
||
107 | * @param string|int|\Spatie\Permission\Contracts\Permission $permission |
||
108 | * @param string|null $guardName |
||
109 | * |
||
110 | * @return bool |
||
111 | * @throws PermissionDoesNotExist |
||
112 | */ |
||
113 | public function hasPermissionTo($permission, $guardName = null): bool |
||
114 | { |
||
115 | if (config('permission.enable_wildcard_permission', false)) { |
||
116 | return $this->hasWildcardPermission($permission, $guardName); |
||
117 | } |
||
118 | |||
119 | $permissionClass = $this->getPermissionClass(); |
||
120 | |||
121 | if (is_string($permission)) { |
||
122 | $permission = $permissionClass->findByName( |
||
123 | $permission, |
||
124 | $guardName ?? $this->getDefaultGuardName() |
||
125 | ); |
||
126 | } |
||
127 | |||
128 | if (is_int($permission)) { |
||
129 | $permission = $permissionClass->findById( |
||
130 | $permission, |
||
131 | $guardName ?? $this->getDefaultGuardName() |
||
132 | ); |
||
133 | } |
||
134 | |||
135 | if (! $permission instanceof Permission) { |
||
136 | throw new PermissionDoesNotExist; |
||
137 | } |
||
138 | |||
139 | return $this->hasDirectPermission($permission) || $this->hasPermissionViaRole($permission); |
||
140 | } |
||
141 | |||
142 | /** |
||
143 | * Validates a wildcard permission against all permissions of a user. |
||
144 | * |
||
145 | * @param string|int|\Spatie\Permission\Contracts\Permission $permission |
||
146 | * @param string|null $guardName |
||
147 | * |
||
148 | * @return bool |
||
149 | */ |
||
150 | protected function hasWildcardPermission($permission, $guardName = null): bool |
||
151 | { |
||
152 | $guardName = $guardName ?? $this->getDefaultGuardName(); |
||
153 | |||
154 | if (is_int($permission)) { |
||
155 | $permission = $this->getPermissionClass()->findById($permission, $guardName); |
||
156 | } |
||
157 | |||
158 | if ($permission instanceof Permission) { |
||
159 | $permission = $permission->name; |
||
0 ignored issues
–
show
Accessing
name on the interface Spatie\Permission\Contracts\Permission suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
160 | } |
||
161 | |||
162 | if (! is_string($permission)) { |
||
163 | throw WildcardPermissionInvalidArgument::create(); |
||
164 | } |
||
165 | |||
166 | foreach ($this->getAllPermissions() as $userPermission) { |
||
167 | if ($guardName !== $userPermission->guard_name) { |
||
168 | continue; |
||
169 | } |
||
170 | |||
171 | $userPermission = new WildcardPermission($userPermission->name); |
||
172 | |||
173 | if ($userPermission->implies($permission)) { |
||
174 | return true; |
||
175 | } |
||
176 | } |
||
177 | |||
178 | return false; |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * @deprecated since 2.35.0 |
||
183 | * @alias of hasPermissionTo() |
||
184 | */ |
||
185 | public function hasUncachedPermissionTo($permission, $guardName = null): bool |
||
186 | { |
||
187 | return $this->hasPermissionTo($permission, $guardName); |
||
188 | } |
||
189 | |||
190 | /** |
||
191 | * An alias to hasPermissionTo(), but avoids throwing an exception. |
||
192 | * |
||
193 | * @param string|int|\Spatie\Permission\Contracts\Permission $permission |
||
194 | * @param string|null $guardName |
||
195 | * |
||
196 | * @return bool |
||
197 | */ |
||
198 | public function checkPermissionTo($permission, $guardName = null): bool |
||
199 | { |
||
200 | try { |
||
201 | return $this->hasPermissionTo($permission, $guardName); |
||
202 | } catch (PermissionDoesNotExist $e) { |
||
203 | return false; |
||
204 | } |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Determine if the model has any of the given permissions. |
||
209 | * |
||
210 | * @param array ...$permissions |
||
211 | * |
||
212 | * @return bool |
||
213 | * @throws \Exception |
||
214 | */ |
||
215 | View Code Duplication | public function hasAnyPermission(...$permissions): bool |
|
0 ignored issues
–
show
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. ![]() |
|||
216 | { |
||
217 | $permissions = collect($permissions)->flatten(); |
||
218 | |||
219 | foreach ($permissions as $permission) { |
||
220 | if ($this->checkPermissionTo($permission)) { |
||
221 | return true; |
||
222 | } |
||
223 | } |
||
224 | |||
225 | return false; |
||
226 | } |
||
227 | |||
228 | /** |
||
229 | * Determine if the model has all of the given permissions. |
||
230 | * |
||
231 | * @param array ...$permissions |
||
232 | * |
||
233 | * @return bool |
||
234 | * @throws \Exception |
||
235 | */ |
||
236 | View Code Duplication | public function hasAllPermissions(...$permissions): bool |
|
0 ignored issues
–
show
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. ![]() |
|||
237 | { |
||
238 | $permissions = collect($permissions)->flatten(); |
||
239 | |||
240 | foreach ($permissions as $permission) { |
||
241 | if (! $this->hasPermissionTo($permission)) { |
||
242 | return false; |
||
243 | } |
||
244 | } |
||
245 | |||
246 | return true; |
||
247 | } |
||
248 | |||
249 | /** |
||
250 | * Determine if the model has, via roles, the given permission. |
||
251 | * |
||
252 | * @param \Spatie\Permission\Contracts\Permission $permission |
||
253 | * |
||
254 | * @return bool |
||
255 | */ |
||
256 | protected function hasPermissionViaRole(Permission $permission): bool |
||
257 | { |
||
258 | return $this->hasRole($permission->roles); |
||
0 ignored issues
–
show
Accessing
roles on the interface Spatie\Permission\Contracts\Permission suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() It seems like
hasRole() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Determine if the model has the given permission. |
||
263 | * |
||
264 | * @param string|int|\Spatie\Permission\Contracts\Permission $permission |
||
265 | * |
||
266 | * @return bool |
||
267 | * @throws PermissionDoesNotExist |
||
268 | */ |
||
269 | public function hasDirectPermission($permission): bool |
||
270 | { |
||
271 | $permissionClass = $this->getPermissionClass(); |
||
272 | |||
273 | if (is_string($permission)) { |
||
274 | $permission = $permissionClass->findByName($permission, $this->getDefaultGuardName()); |
||
275 | } |
||
276 | |||
277 | if (is_int($permission)) { |
||
278 | $permission = $permissionClass->findById($permission, $this->getDefaultGuardName()); |
||
279 | } |
||
280 | |||
281 | if (! $permission instanceof Permission) { |
||
282 | throw new PermissionDoesNotExist; |
||
283 | } |
||
284 | |||
285 | return $this->permissions->contains('id', $permission->id); |
||
0 ignored issues
–
show
The property
permissions does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() Accessing
id on the interface Spatie\Permission\Contracts\Permission suggest that you code against a concrete implementation. How about adding an instanceof check?
If you access a property on an interface, you most likely code against a concrete implementation of the interface. Available Fixes
![]() |
|||
286 | } |
||
287 | |||
288 | /** |
||
289 | * Return all the permissions the model has via roles. |
||
290 | */ |
||
291 | public function getPermissionsViaRoles(): Collection |
||
292 | { |
||
293 | return $this->loadMissing('roles', 'roles.permissions') |
||
0 ignored issues
–
show
It seems like
loadMissing() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
294 | ->roles->flatMap(function ($role) { |
||
295 | return $role->permissions; |
||
296 | })->sort()->values(); |
||
297 | } |
||
298 | |||
299 | /** |
||
300 | * Return all the permissions the model has, both directly and via roles. |
||
301 | */ |
||
302 | public function getAllPermissions(): Collection |
||
303 | { |
||
304 | /** @var Collection $permissions */ |
||
305 | $permissions = $this->permissions; |
||
306 | |||
307 | if ($this->roles) { |
||
0 ignored issues
–
show
The property
roles does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
308 | $permissions = $permissions->merge($this->getPermissionsViaRoles()); |
||
309 | } |
||
310 | |||
311 | return $permissions->sort()->values(); |
||
312 | } |
||
313 | |||
314 | /** |
||
315 | * Grant the given permission(s) to a role. |
||
316 | * |
||
317 | * @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
||
318 | * |
||
319 | * @return $this |
||
320 | */ |
||
321 | View Code Duplication | public function givePermissionTo(...$permissions) |
|
0 ignored issues
–
show
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. ![]() |
|||
322 | { |
||
323 | $permissions = collect($permissions) |
||
324 | ->flatten() |
||
325 | ->map(function ($permission) { |
||
326 | if (empty($permission)) { |
||
327 | return false; |
||
328 | } |
||
329 | |||
330 | return $this->getStoredPermission($permission); |
||
331 | }) |
||
332 | ->filter(function ($permission) { |
||
333 | return $permission instanceof Permission; |
||
334 | }) |
||
335 | ->each(function ($permission) { |
||
336 | $this->ensureModelSharesGuard($permission); |
||
337 | }) |
||
338 | ->map->id |
||
339 | ->all(); |
||
340 | |||
341 | $model = $this->getModel(); |
||
0 ignored issues
–
show
It seems like
getModel() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
342 | |||
343 | if ($model->exists) { |
||
344 | $this->permissions()->sync($permissions, false); |
||
345 | $model->load('permissions'); |
||
346 | } else { |
||
347 | $class = \get_class($model); |
||
348 | |||
349 | $class::saved( |
||
350 | function ($object) use ($permissions, $model) { |
||
351 | static $modelLastFiredOn; |
||
352 | if ($modelLastFiredOn !== null && $modelLastFiredOn === $model) { |
||
353 | return; |
||
354 | } |
||
355 | $object->permissions()->sync($permissions, false); |
||
356 | $object->load('permissions'); |
||
357 | $modelLastFiredOn = $object; |
||
358 | } |
||
359 | ); |
||
360 | } |
||
361 | |||
362 | $this->forgetCachedPermissions(); |
||
363 | |||
364 | return $this; |
||
365 | } |
||
366 | |||
367 | /** |
||
368 | * Remove all current permissions and set the given ones. |
||
369 | * |
||
370 | * @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
||
371 | * |
||
372 | * @return $this |
||
373 | */ |
||
374 | public function syncPermissions(...$permissions) |
||
375 | { |
||
376 | $this->permissions()->detach(); |
||
377 | |||
378 | return $this->givePermissionTo($permissions); |
||
379 | } |
||
380 | |||
381 | /** |
||
382 | * Revoke the given permission. |
||
383 | * |
||
384 | * @param \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Permission[]|string|string[] $permission |
||
385 | * |
||
386 | * @return $this |
||
387 | */ |
||
388 | public function revokePermissionTo($permission) |
||
389 | { |
||
390 | $this->permissions()->detach($this->getStoredPermission($permission)); |
||
391 | |||
392 | $this->forgetCachedPermissions(); |
||
393 | |||
394 | $this->load('permissions'); |
||
0 ignored issues
–
show
It seems like
load() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
395 | |||
396 | return $this; |
||
397 | } |
||
398 | |||
399 | public function getPermissionNames(): Collection |
||
400 | { |
||
401 | return $this->permissions->pluck('name'); |
||
402 | } |
||
403 | |||
404 | /** |
||
405 | * @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
||
406 | * |
||
407 | * @return \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Permission[]|\Illuminate\Support\Collection |
||
408 | */ |
||
409 | protected function getStoredPermission($permissions) |
||
410 | { |
||
411 | $permissionClass = $this->getPermissionClass(); |
||
412 | |||
413 | if (is_numeric($permissions)) { |
||
414 | return $permissionClass->findById($permissions, $this->getDefaultGuardName()); |
||
415 | } |
||
416 | |||
417 | if (is_string($permissions)) { |
||
418 | return $permissionClass->findByName($permissions, $this->getDefaultGuardName()); |
||
419 | } |
||
420 | |||
421 | if (is_array($permissions)) { |
||
422 | return $permissionClass |
||
423 | ->whereIn('name', $permissions) |
||
424 | ->whereIn('guard_name', $this->getGuardNames()) |
||
425 | ->get(); |
||
426 | } |
||
427 | |||
428 | return $permissions; |
||
429 | } |
||
430 | |||
431 | /** |
||
432 | * @param \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Role $roleOrPermission |
||
433 | * |
||
434 | * @throws \Spatie\Permission\Exceptions\GuardDoesNotMatch |
||
435 | */ |
||
436 | protected function ensureModelSharesGuard($roleOrPermission) |
||
437 | { |
||
438 | if (! $this->getGuardNames()->contains($roleOrPermission->guard_name)) { |
||
439 | throw GuardDoesNotMatch::create($roleOrPermission->guard_name, $this->getGuardNames()); |
||
440 | } |
||
441 | } |
||
442 | |||
443 | protected function getGuardNames(): Collection |
||
444 | { |
||
445 | return Guard::getNames($this); |
||
446 | } |
||
447 | |||
448 | protected function getDefaultGuardName(): string |
||
449 | { |
||
450 | return Guard::getDefaultName($this); |
||
451 | } |
||
452 | |||
453 | /** |
||
454 | * Forget the cached permissions. |
||
455 | */ |
||
456 | public function forgetCachedPermissions() |
||
457 | { |
||
458 | app(PermissionRegistrar::class)->forgetCachedPermissions(); |
||
459 | } |
||
460 | |||
461 | /** |
||
462 | * Check if the model has All of the requested Direct permissions. |
||
463 | * @param array ...$permissions |
||
464 | * @return bool |
||
465 | */ |
||
466 | View Code Duplication | public function hasAllDirectPermissions(...$permissions): bool |
|
0 ignored issues
–
show
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. ![]() |
|||
467 | { |
||
468 | $permissions = collect($permissions)->flatten(); |
||
469 | |||
470 | foreach ($permissions as $permission) { |
||
471 | if (! $this->hasDirectPermission($permission)) { |
||
472 | return false; |
||
473 | } |
||
474 | } |
||
475 | |||
476 | return true; |
||
477 | } |
||
478 | |||
479 | /** |
||
480 | * Check if the model has Any of the requested Direct permissions. |
||
481 | * @param array ...$permissions |
||
482 | * @return bool |
||
483 | */ |
||
484 | View Code Duplication | public function hasAnyDirectPermission(...$permissions): bool |
|
0 ignored issues
–
show
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. ![]() |
|||
485 | { |
||
486 | $permissions = collect($permissions)->flatten(); |
||
487 | |||
488 | foreach ($permissions as $permission) { |
||
489 | if ($this->hasDirectPermission($permission)) { |
||
490 | return true; |
||
491 | } |
||
492 | } |
||
493 | |||
494 | return false; |
||
495 | } |
||
496 | } |
||
497 |
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.