UserAndLevel::cacheGetAllPermissions()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 7
nc 2
nop 0
crap 2
1
<?php
2
3
namespace z1haze\Acl\Traits;
4
5
use Illuminate\Support\Collection;
6
use ReflectionClass;
7
use z1haze\Acl\Exceptions\PermissionNotFoundException;
8
use Illuminate\Support\Facades\Cache;
9
use z1haze\Acl\Models\Level;
10
use z1haze\Acl\Models\Permission;
11
12
trait UserAndLevel
13
{
14
    /**
15
     * USER & LEVEL
16
     * Check if a model has a given level
17
     *
18
     * @param mixed level
19
     * @return bool
20
     */
21 1
    public function isLevel($level)
22
    {
23 1
        $level = aclGetALevel($level);
24
25 1
        return is_a($this, config('laravel-acl.level'), true) ? $this->name == $level->name : $this->level->name == $level->name;
0 ignored issues
show
Bug introduced by
The property name 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;
Loading history...
Bug introduced by
The property level 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;
Loading history...
26
    }
27
28
    /**
29
     * USER & LEVEL
30
     * Check if a user has or has inherited
31
     * a given level
32
     *
33
     * @param $level
34
     * @return bool
35
     */
36 2
    public function hasLevel($level)
37
    {
38 2
        $level = aclGetALevel($level);
39
40 2
        return is_a($this, config('laravel-acl.level'), true) ? $this->rank <= $level->rank : $this->level->rank <= $level->rank;
0 ignored issues
show
Bug introduced by
The property rank 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;
Loading history...
41
    }
42
43
    /**
44
     * USER & LEVEL
45
     * Add a single permission to a model
46
     *
47
     * @param $permission
48
     */
49 16
    public function addPermission($permission)
50
    {
51 16
        $this->modifyPermissions([$permission], 'add');
52 15
    }
53
54
    /**
55
     * USER & LEVEL
56
     * Add an array of permissions to a model
57
     *
58
     * @param $permissions
59
     */
60 9
    public function addPermissions(array $permissions)
61
    {
62 9
        $this->modifyPermissions($permissions, 'add');
63 9
    }
64
65
    /**
66
     * USER & LEVEL
67
     * Remove a permission from a model
68
     *
69
     * @param $permission
70
     */
71 2
    public function removePermission($permission)
72
    {
73 2
        $this->modifyPermissions([$permission], 'remove');
74 2
    }
75
76
    /**
77
     * USER & LEVEL
78
     * Remove an array of permissions objects or permission names (can be mixed)
79
     *
80
     * @param $permissions
81
     */
82 1
    public function removePermissions(array $permissions)
83
    {
84 1
        $this->modifyPermissions($permissions, 'remove');
85 1
    }
86
87
    /**
88
     * USER & LEVEL
89
     * Sync permissions on a model
90
     *
91
     * @param $permissions
92
     */
93 2
    public function syncPermissions(array $permissions)
94
    {
95 2
        $this->modifyPermissions($permissions, 'sync');
96 2
    }
97
98
    /**
99
     * USER & LEVEL
100
     * Clear permissions from a model
101
     */
102 3
    public function clearPermissions()
103
    {
104 3
        if (is_a($this, config('laravel-acl.user'), true)) {
105 1
            $this->permissions()->detach();
0 ignored issues
show
Bug introduced by
The method permissions() does not exist on z1haze\Acl\Traits\UserAndLevel. Did you maybe mean addPermissions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
106
        }
107
108 3
        if (is_a($this, config('laravel-acl.level'), true)) {
109 2
            config('laravel-acl.permission', Permission::class)::whereLevelId($this->id)->update(['level_id' => null]);
0 ignored issues
show
Bug introduced by
The property id 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;
Loading history...
110
        }
111 3
    }
112
113
    /**
114
     * USER & LEVEL
115
     * First try the cache to return the collection,
116
     * then fetch it from the database.
117
     *
118
     * See @cacheGetPermissions()
119
     *
120
     * @return \Illuminate\Support\Collection
121
     */
122 2
    public function getPermissions()
123
    {
124 2
        return $this->cachePull('cacheGetPermissions');
125
    }
126
127
    /**
128
     * USER & LEVEL
129
     * First try the cache to return the collection,
130
     * then fetch it from the database.
131
     *
132
     * See @cacheGetAllPermissions()
133
     *
134
     * @return \Illuminate\Support\Collection
135
     */
136 7
    public function getAllPermissions()
137
    {
138 7
        return $this->cachePull('cacheGetAllPermissions');
139
    }
140
141
    /**
142
     * USER & LEVEL
143
     * First try the cache to return the collection,
144
     * then fetch it from the database.
145
     *
146
     * See @cacheGetInheritedPermissions()
147
     *
148
     * @return \Illuminate\Support\Collection
149
     */
150 3
    public function getInheritedPermissions()
151
    {
152 3
        return $this->cachePull('cacheGetInheritedPermissions');
153
    }
154
155
    /**
156
     * USER & LEVEL
157
     * First try the cache to return the collection,
158
     * then fetch it from the database.
159
     *
160
     * See @cacheGetAvailablePermissions()
161
     *
162
     * @return \Illuminate\Support\Collection
163
     */
164 2
    public function getAvailablePermissions()
165
    {
166 2
        return $this->cachePull('cacheGetAvailablePermissions');
167
    }
168
169
    /**
170
     * USER & LEVEL
171
     * First try the cache to return the collection,
172
     * then fetch it from the database.
173
     *
174
     * See @cacheHasPermissionTo()
175
     *
176
     * @param $permission
177
     * @return bool
178
     */
179 3 View Code Duplication
    public function hasPermissionTo($permission)
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...
180
    {
181 3
        $shortName = (new ReflectionClass($this))->getShortName();
182
183 3
        return Cache::remember(
184 3
            'laravel-acl.hasPermissionTo_' . $shortName . '_' . $this->id . '_Permission_' . $permission,
185 3
            config('laravel-acl.cacheMinutes'),
186
            function() use ($permission) {
187 3
                return $this->cacheHasPermissionTo($permission);
188 3
            }
189
        );
190
    }
191
192
    /**
193
     * USER & LEVEL
194
     * Returns if a level is lower ranking than another level,
195
     * or if a user is lower ranking than another user.
196
     *
197
     * @param $other
198
     * @return bool
199
     */
200 3
    public function isLowerThan($other)
201
    {
202 3
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank > $other->level->rank : $this->rank > $other->rank;
203
    }
204
205
    /**
206
     * USER & LEVEL
207
     * Returns if a level is higher ranking than another level,
208
     * or if a user is higher ranking than another user.
209
     *
210
     * @param $other
211
     * @return bool
212
     */
213 3
    public function isHigherThan($other)
214
    {
215 3
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank < $other->level->rank : $this->rank < $other->rank;
216
    }
217
218
    /**
219
     * USER & LEVEL
220
     * Returns if a equal is lower ranking than another level,
221
     * or if a user is equal ranking than another user.
222
     *
223
     * @param $other
224
     * @return bool
225
     */
226 1
    public function isEqualTo($other)
227
    {
228 1
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank == $other->level->rank : $this->rank == $other->rank;
229
    }
230
231
232
    /* ------------------------------------------------------------------------------------------------
233
     |  Other Functions
234
     | ------------------------------------------------------------------------------------------------
235
     */
236
    /**
237
     * USER & LEVEL
238
     * Pull the specific type requested from the cache
239
     *
240
     * @param $type
241
     * @return \Illuminate\Support\Collection
242
     */
243 12 View Code Duplication
    protected function cachePull($type)
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...
244
    {
245 12
        $shortName = (new ReflectionClass($this))->getShortName();
246
247 12
        return Cache::remember(
248 12
            'laravel-acl.' . lcfirst(substr($type, 5)) . 'For' . $shortName . '_' . $this->id,
249 12
            config('laravel-acl.cacheMinutes'),
250
            function() use ($type) {
251 12
                return $this->{$type}();
252 12
            }
253
        );
254
    }
255
    /**
256
     * USER & LEVEL
257
     * Return a collection of permissions
258
     * assigned to a user
259
     *
260
     * @return \Illuminate\Support\Collection
261
     */
262 2
    protected function cacheGetPermissions()
263
    {
264 2
        return $this->permissions;
0 ignored issues
show
Bug introduced by
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;
Loading history...
265
    }
266
267
    /**
268
     * USER & LEVEL
269
     * Return a collection of all permissions
270
     * associated to a user by direct or
271
     * inheritance
272
     *
273
     * @return \Illuminate\Support\Collection
274
     */
275 7
    protected function cacheGetAllPermissions()
276
    {
277 7
        $rank = is_a($this, config('laravel-acl.level'), true) ? $this->rank : $this->level->rank;
278
279 7
        $levels = config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get();
280
281 7
        $allPerms = new Collection();
282
283
        $levels->each(function($level) use (&$allPerms) {
284 7
            $allPerms = $allPerms->merge($level->permissions);
285 7
        });
286
287 7
        return $allPerms->merge($this->permissions)->unique('id');
288
    }
289
290
    /**
291
     * USER & LEVEL
292
     * Return a collection of permissions that
293
     * are inherited from a higher level
294
     *
295
     * @return \Illuminate\Support\Collection
296
     */
297 3
    protected function cacheGetInheritedPermissions()
298
    {
299 3
        $rank = is_a($this, config('laravel-acl.level'), true) ? $this->rank : $this->level->rank;
300
301 3
        $levels = is_a($this, config('laravel-acl.user'), true) ?
302 3
            config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get() : config('laravel-acl.level', Level::class)::where('rank', '>', $rank)->with('permissions')->get();
303
304 3
        $inheritedPerms = new Collection();
305
306
        $levels->each(function($level) use (&$inheritedPerms) {
307 3
            $inheritedPerms = $inheritedPerms->merge($level->permissions->load('level'));
308 3
        });
309
310 3
        return $inheritedPerms->unique('id');
311
    }
312
313
    /**
314
     * USER & LEVEL
315
     * Return a collection of permissions still able to be assigned
316
     * ie, not already inherited or explicitly assigned
317
     *
318
     * @return \Illuminate\Support\Collection
319
     */
320 2
    protected function cacheGetAvailablePermissions()
321
    {
322 2
        $allPerms = config('laravel-acl.permission', Permission::class)::with('level')->get();
323
324 2
        return $allPerms->diff($this->permissions);
325
    }
326
327
    /**
328
     * USER & LEVEL
329
     * Check if a model has permission to do something
330
     *
331
     * @param $permission
332
     * @return bool
333
     */
334 3
    protected function cacheHasPermissionTo($permission)
335
    {
336 3
        $permission = $this->getPermission($permission);
337
338 3
        if (is_a($this, config('laravel-acl.user'), true)) {
339 2
            $negatedPermissions = $this->permissions()->wherePivot('negated', true)->get();
0 ignored issues
show
Bug introduced by
The method permissions() does not exist on z1haze\Acl\Traits\UserAndLevel. Did you maybe mean addPermissions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
340
341 2
            if ($this->getAllPermissions()->contains('id', $permission->id)) {
342 1
                return !$negatedPermissions->contains('id', $permission->id);
343
            }
344
        }
345
346 2
        return $this->getAllPermissions()->contains('id', $permission->id) || $this->getAllPermissions()->contains('name', '*');
347
    }
348
349
    /**
350
     * USER & LEVEL
351
     * Modify a given set of permissions, given the action to be taken
352
     *
353
     * @param $permissions
354
     * @param string $action
355
     */
356 24
    protected function modifyPermissions($permissions, $action)
357
    {
358 24
        $shortName = (new ReflectionClass($this))->getShortName();
359
360 24
        Cache::forget('laravel-acl.getAvailablePermissionsFor' . $shortName . '_' . $this->id);
361 24
        Cache::forget('laravel-acl.getAllPermissionsFor' . $shortName . '_' . $this->id);
362 24
        Cache::forget('laravel-acl.getNegatedPermissionsForUser_' . $this->id);
363
364 24
        $permissionObjects = $this->buildPermissionsArray($permissions, $action);
365
366
        switch ($action) {
367 23
            case 'add':
368
                // Add and negate call the same method
369 7
            case 'negate':
370 23
                $this->addOrNegate($permissionObjects, $action);
0 ignored issues
show
Unused Code introduced by
The call to UserAndLevel::addOrNegate() has too many arguments starting with $action.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
371 23
                break;
372 5
            case 'remove':
373 3
                $this->remove($permissionObjects);
374 3
                break;
375 2
            case 'sync':
376 2
                $this->sync($permissionObjects);
377
            default:
378
                // Hopefully this never happens
379
        }
380 23
    }
381
382
    /**
383
     * USER & LEVEL
384
     * Helper function to build the array
385
     * for modifyPermissions
386
     *
387
     * @param $permissions
388
     * @param $action
389
     * @return array
390
     * @throws PermissionNotFoundException
391
     */
392 24
    protected function buildPermissionsArray($permissions, $action)
393
    {
394 24
        $permissionsObjects = [];
395 24
        $shortName = (new ReflectionClass($this))->getShortName();
396
397 24
        foreach ($permissions as $permission) {
398 24
            $permission = $this->getPermission($permission);
399 23
            Cache::forget('laravel-acl.hasPermissionTo_' . $shortName . '_' . $this->id . '_Permission_' . $permission->id);
400
401 23
            if ($action == 'negate') {
402 2
                $permissionsObjects[$permission->id] = ['negated' => true];
403
            } else {
404 23
                is_a($this, config('laravel-acl.user')) ?
405 23
                    array_push($permissionsObjects, $permission->id) : array_push($permissionsObjects, $permission);
406
            }
407
        }
408
409 23
        return $permissionsObjects;
410
    }
411
412
    /**
413
     * USER & LEVEL
414
     * Helper function to handle adding or negating permissions
415
     *
416
     * @param $permissionObjects
417
     */
418 23
    protected function addOrNegate($permissionObjects)
419
    {
420 23
        if (is_a($this, config('laravel-acl.user'))) {
421 13
            $this->permissions()->attach($permissionObjects);
0 ignored issues
show
Bug introduced by
The method permissions() does not exist on z1haze\Acl\Traits\UserAndLevel. Did you maybe mean addPermissions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
422
        }
423
424 23
        if (is_a($this, config('laravel-acl.level'))) {
425 12
            $this->permissions()->saveMany($permissionObjects);
0 ignored issues
show
Bug introduced by
The method permissions() does not exist on z1haze\Acl\Traits\UserAndLevel. Did you maybe mean addPermissions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
426
        }
427 23
    }
428
429
    /**
430
     * USER & LEVEL
431
     * Helper function to handle removing permissions
432
     *
433
     * @param $permissionObjects
434
     */
435 3 View Code Duplication
    protected function remove($permissionObjects)
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...
436
    {
437 3
        if (is_a($this, config('laravel-acl.user'))) {
438 2
            $this->permissions()->detach($permissionObjects);
0 ignored issues
show
Bug introduced by
The method permissions() does not exist on z1haze\Acl\Traits\UserAndLevel. Did you maybe mean addPermissions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
439
        }
440
441 3
        if (is_a($this, config('laravel-acl.level'))) {
442
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function($permission) {
443 1
                return $permission->id;
444 1
            }, $permissionObjects))->update(['level_id' => null]);
445
        }
446 3
    }
447
448
    /**
449
     * USER & LEVEL
450
     * Help function to handle syncing permissions
451
     *
452
     * @param $permissionObjects
453
     */
454 2 View Code Duplication
    protected function sync($permissionObjects)
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...
455
    {
456 2
        if (is_a($this, config('laravel-acl.user'))) {
457 1
            $this->permissions()->sync($permissionObjects);
0 ignored issues
show
Bug introduced by
The method permissions() does not exist on z1haze\Acl\Traits\UserAndLevel. Did you maybe mean addPermissions()?

This check marks calls to methods that do not seem to exist on an object.

This is most likely the result of a method being renamed without all references to it being renamed likewise.

Loading history...
458
        }
459
460 2
        if (is_a($this, config('laravel-acl.level'))) {
461 1
            $this->clearPermissions();
462
463 1
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function($permission) {
464 1
                return $permission->id;
465 1
            }, $permissionObjects))
466 1
                ->update(['level_id' => $this->id]);
467
        }
468 2
    }
469
470
    /**
471
     * USER & LEVEL
472
     * Helper function to get the permission whether it is the permission ID
473
     * or the permission name, or the permission object itself.
474
     *
475
     * @param $permission
476
     * @return \z1haze\Acl\Models\Permission
477
     * @throws PermissionNotFoundException
478
     */
479 24
    protected function getPermission($permission)
480
    {
481 24
        if (is_string($permission)) {
482 5
            $permission = config('laravel-acl.permission', Permission::class)::whereName($permission)->first();
483
        }
484
485 24
        if (is_int($permission)) {
486 4
            $permission = config('laravel-acl.permission', Permission::class)::find($permission);
487
        }
488
489 24
        if (!$permission) {
490 1
            throw new PermissionNotFoundException;
491
        }
492
493 23
        return $permission;
494
    }
495
}