Completed
Push — master ( bd74a4...d9ea8c )
by Stephen
05:53
created

UserAndLevel::cacheGetInheritedPermissions()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 15
ccs 8
cts 8
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 8
nc 4
nop 0
crap 3
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
        return Cache::remember(
182 3
            'laravel-acl.hasPermissionTo_' . (new ReflectionClass($this))->getShortName() . '_' . $this->id . '_Permission_' . $permission,
183 3
            config('laravel-acl.cacheMinutes'),
184
            function() use ($permission) {
185 3
                return $this->cacheHasPermissionTo($permission);
186 3
            }
187
        );
188
    }
189
190
    /**
191
     * USER & LEVEL
192
     * Returns if a level is lower ranking than another level,
193
     * or if a user is lower ranking than another user.
194
     *
195
     * @param $other
196
     * @return bool
197
     */
198 3
    public function isLowerThan($other)
199
    {
200 3
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank > $other->level->rank : $this->rank > $other->rank;
201
    }
202
203
    /**
204
     * USER & LEVEL
205
     * Returns if a level is higher ranking than another level,
206
     * or if a user is higher ranking than another user.
207
     *
208
     * @param $other
209
     * @return bool
210
     */
211 3
    public function isHigherThan($other)
212
    {
213 3
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank < $other->level->rank : $this->rank < $other->rank;
214
    }
215
216
    /**
217
     * USER & LEVEL
218
     * Returns if a equal is lower ranking than another level,
219
     * or if a user is equal ranking than another user.
220
     *
221
     * @param $other
222
     * @return bool
223
     */
224 1
    public function isEqualTo($other)
225
    {
226 1
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank == $other->level->rank : $this->rank == $other->rank;
227
    }
228
229
230
    /* ------------------------------------------------------------------------------------------------
231
     |  Other Functions
232
     | ------------------------------------------------------------------------------------------------
233
     */
234
    /**
235
     * USER & LEVEL
236
     * Pull the specific type requested from the cache
237
     *
238
     * @param $type
239
     * @return \Illuminate\Support\Collection
240
     */
241 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...
242
    {
243 12
        return Cache::remember(
244 12
            'laravel-acl.' . lcfirst(substr($type, 5)) . 'For' . (new ReflectionClass($this))->getShortName() . '_' . $this->id,
245 12
            config('laravel-acl.cacheMinutes'),
246
            function() use ($type) {
247 12
                return $this->{$type}();
248 12
            }
249
        );
250
    }
251
    /**
252
     * USER & LEVEL
253
     * Return a collection of permissions
254
     * assigned to a user
255
     *
256
     * @return \Illuminate\Support\Collection
257
     */
258 2
    protected function cacheGetPermissions()
259
    {
260 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...
261
    }
262
263
    /**
264
     * USER & LEVEL
265
     * Return a collection of all permissions
266
     * associated to a user by direct or
267
     * inheritance
268
     *
269
     * @return \Illuminate\Support\Collection
270
     */
271 7
    protected function cacheGetAllPermissions()
272
    {
273 7
        $rank = is_a($this, config('laravel-acl.level'), true) ? $this->rank : $this->level->rank;
274
275 7
        $levels = config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get();
276
277 7
        $allPerms = new Collection();
278
279
        $levels->each(function($level) use (&$allPerms) {
280 7
            $allPerms = $allPerms->merge($level->permissions);
281 7
        });
282
283 7
        return $allPerms->merge($this->permissions)->unique('id');
284
    }
285
286
    /**
287
     * USER & LEVEL
288
     * Return a collection of permissions that
289
     * are inherited from a higher level
290
     *
291
     * @return \Illuminate\Support\Collection
292
     */
293 3
    protected function cacheGetInheritedPermissions()
294
    {
295 3
        $rank = is_a($this, config('laravel-acl.level'), true) ? $this->rank : $this->level->rank;
296
297 3
        $levels = is_a($this, config('laravel-acl.user'), true) ?
298 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();
299
300 3
        $inheritedPerms = new Collection();
301
302
        $levels->each(function($level) use (&$inheritedPerms) {
303 3
            $inheritedPerms = $inheritedPerms->merge($level->permissions->load('level'));
304 3
        });
305
306 3
        return $inheritedPerms->unique('id');
307
    }
308
309
    /**
310
     * USER & LEVEL
311
     * Return a collection of permissions still able to be assigned
312
     * ie, not already inherited or explicitly assigned
313
     *
314
     * @return \Illuminate\Support\Collection
315
     */
316 2
    protected function cacheGetAvailablePermissions()
317
    {
318 2
        $allPerms = config('laravel-acl.permission', Permission::class)::with('level')->get();
319
320 2
        return $allPerms->diff($this->permissions);
321
    }
322
323
    /**
324
     * USER & LEVEL
325
     * Check if a model has permission to do something
326
     *
327
     * @param $permission
328
     * @return bool
329
     */
330 3
    protected function cacheHasPermissionTo($permission)
331
    {
332 3
        $permission = $this->getPermission($permission);
333
334 3
        if (is_a($this, config('laravel-acl.user'), true)) {
335 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...
336
337 2
            if ($this->getAllPermissions()->contains('id', $permission->id)) {
338 1
                return !$negatedPermissions->contains('id', $permission->id);
339
            }
340
        }
341
342 2
        return $this->getAllPermissions()->contains('id', $permission->id) || $this->getAllPermissions()->contains('name', '*');
343
    }
344
345
    /**
346
     * USER & LEVEL
347
     * Modify a given set of permissions, given the action to be taken
348
     *
349
     * @param $permissions
350
     * @param string $action
351
     */
352 24
    protected function modifyPermissions($permissions, $action)
353
    {
354 24
        Cache::forget('laravel-acl.getAvailablePermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id);
355 24
        Cache::forget('laravel-acl.getAllPermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id);
356 24
        Cache::forget('laravel-acl.getNegatedPermissionsForUser_' . $this->id);
357
358 24
        $permissionObjects = $this->buildPermissionsArray($permissions, $action);
359
360
        switch ($action) {
361 23
            case 'add':
362
                // Add and negate call the same method
363 7
            case 'negate':
364 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...
365 23
                break;
366 5
            case 'remove':
367 3
                $this->remove($permissionObjects);
368 3
                break;
369 2
            case 'sync':
370 2
                $this->sync($permissionObjects);
371
            default:
372
                // Hopefully this never happens
373
        }
374 23
    }
375
376
    /**
377
     * USER & LEVEL
378
     * Helper function to build the array
379
     * for modifyPermissions
380
     *
381
     * @param $permissions
382
     * @param $action
383
     * @return array
384
     * @throws PermissionNotFoundException
385
     */
386 24
    protected function buildPermissionsArray($permissions, $action)
387
    {
388 24
        $permissionsObjects = [];
389
390 24
        foreach ($permissions as $permission) {
391 24
            $permission = $this->getPermission($permission);
392 23
            Cache::forget('laravel-acl.hasPermissionTo_' . (new ReflectionClass($this))->getShortName() . '_' . $this->id . '_Permission_' . $permission->id);
393
394 23
            if ($action == 'negate') {
395 2
                $permissionsObjects[$permission->id] = ['negated' => true];
396
            } else {
397 23
                is_a($this, config('laravel-acl.user')) ?
398 23
                    array_push($permissionsObjects, $permission->id) : array_push($permissionsObjects, $permission);
399
            }
400
        }
401
402 23
        return $permissionsObjects;
403
    }
404
405
    /**
406
     * USER & LEVEL
407
     * Helper function to handle adding or negating permissions
408
     *
409
     * @param $permissionObjects
410
     */
411 23
    protected function addOrNegate($permissionObjects)
412
    {
413 23
        if (is_a($this, config('laravel-acl.user'))) {
414 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...
415
        }
416
417 23
        if (is_a($this, config('laravel-acl.level'))) {
418 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...
419
        }
420 23
    }
421
422
    /**
423
     * USER & LEVEL
424
     * Helper function to handle removing permissions
425
     *
426
     * @param $permissionObjects
427
     */
428 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...
429
    {
430 3
        if (is_a($this, config('laravel-acl.user'))) {
431 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...
432
        }
433
434 3
        if (is_a($this, config('laravel-acl.level'))) {
435
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function($permission) {
436 1
                return $permission->id;
437 1
            }, $permissionObjects))->update(['level_id' => null]);
438
        }
439 3
    }
440
441
    /**
442
     * USER & LEVEL
443
     * Help function to handle syncing permissions
444
     *
445
     * @param $permissionObjects
446
     */
447 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...
448
    {
449 2
        if (is_a($this, config('laravel-acl.user'))) {
450 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...
451
        }
452
453 2
        if (is_a($this, config('laravel-acl.level'))) {
454 1
            $this->clearPermissions();
455
456 1
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function($permission) {
457 1
                return $permission->id;
458 1
            }, $permissionObjects))
459 1
                ->update(['level_id' => $this->id]);
460
        }
461 2
    }
462
463
    /**
464
     * USER & LEVEL
465
     * Helper function to get the permission whether it is the permission ID
466
     * or the permission name, or the permission object itself.
467
     *
468
     * @param $permission
469
     * @return \z1haze\Acl\Models\Permission
470
     * @throws PermissionNotFoundException
471
     */
472 24
    protected function getPermission($permission)
473
    {
474 24
        if (is_string($permission)) {
475 5
            $permission = config('laravel-acl.permission', Permission::class)::whereName($permission)->first();
476
        }
477
478 24
        if (is_int($permission)) {
479 4
            $permission = config('laravel-acl.permission', Permission::class)::find($permission);
480
        }
481
482 24
        if (!$permission) {
483 1
            throw new PermissionNotFoundException;
484
        }
485
486 23
        return $permission;
487
    }
488
}