Completed
Push — master ( c1e6c3...800341 )
by Stephen
04:07 queued 02:05
created

UserAndLevel::remove()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 11
Code Lines 7

Duplication

Lines 11
Ratio 100 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
dl 11
loc 11
ccs 7
cts 7
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 7
nc 4
nop 1
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 = $this->getALevel($level);
0 ignored issues
show
Bug introduced by
It seems like getALevel() 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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
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 1
    public function hasLevel($level)
37
    {
38 1
        $level = $this->getLevel($level);
0 ignored issues
show
Bug introduced by
It seems like getLevel() 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 Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
39
40 1
        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 15
    public function addPermission($permission)
50
    {
51 15
        $this->modifyPermissions([$permission], 'add');
52 14
    }
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 3
        if (is_a($this, config('laravel-acl.level'), true))
108 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...
109 3
    }
110
111
    /**
112
     * USER & LEVEL
113
     * First try the cache to return the collection,
114
     * then fetch it from the database.
115
     *
116
     * See @cacheGetPermissions()
117
     *
118
     * @return \Illuminate\Support\Collection
119
     */
120 2 View Code Duplication
    public function getPermissions()
1 ignored issue
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...
121
    {
122 2
        return Cache::remember(
123 2
            'laravel-acl.getPermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id,
124 2
            config('laravel-acl.cacheMinutes'),
125
            function () {
126 2
                return $this->cachegetPermissions();
127 2
            }
128
        );
129
    }
130
131
    /**
132
     * USER & LEVEL
133
     * First try the cache to return the collection,
134
     * then fetch it from the database.
135
     *
136
     * See @cacheGetAllPermissions()
137
     *
138
     * @return \Illuminate\Support\Collection
139
     */
140 6 View Code Duplication
    public function getAllPermissions()
1 ignored issue
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...
141
    {
142 6
        return Cache::remember(
143 6
            'laravel-acl.getAllPermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id,
144 6
            config('laravel-acl.cacheMinutes'),
145
            function () {
146 6
                return $this->cacheGetAllPermissions();
147 6
            }
148
        );
149
    }
150
151
    /**
152
     * USER & LEVEL
153
     * First try the cache to return the collection,
154
     * then fetch it from the database.
155
     *
156
     * See @cacheGetInheritedPermissions()
157
     *
158
     * @return \Illuminate\Support\Collection
159
     */
160 3 View Code Duplication
    public function getInheritedPermissions()
1 ignored issue
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...
161
    {
162 3
        return Cache::remember(
163 3
            'laravel-acl.getInheritedPermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id,
164 3
            config('laravel-acl.cacheMinutes'),
165
            function () {
166 3
                return $this->cacheGetInheritedPermissions();
167 3
            }
168
        );
169
    }
170
171
    /**
172
     * USER & LEVEL
173
     * First try the cache to return the collection,
174
     * then fetch it from the database.
175
     *
176
     * See @cacheGetAvailablePermissions()
177
     *
178
     * @return \Illuminate\Support\Collection
179
     */
180 2 View Code Duplication
    public function getAvailablePermissions()
1 ignored issue
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...
181
    {
182 2
        return Cache::remember(
183 2
            'laravel-acl.getAvailablePermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id,
184 2
            config('laravel-acl.cacheMinutes'),
185
            function () {
186 2
                return $this->cacheGetAvailablePermissions();
187 2
            }
188
        );
189
    }
190
191
    /**
192
     * USER & LEVEL
193
     * First try the cache to return the collection,
194
     * then fetch it from the database.
195
     *
196
     * See @cacheHasPermissionTo()
197
     *
198
     * @param $permission
199
     * @return bool
200
     */
201 2
    public function hasPermissionTo($permission)
202
    {
203 2
        return Cache::remember(
204 2
            'laravel-acl.hasPermissionTo_' . (new ReflectionClass($this))->getShortName() . '_' . $this->id . '_Permission_' . $permission,
205 2
            config('laravel-acl.cacheMinutes'),
206
            function () use ($permission) {
207 2
                return $this->cacheHasPermissionTo($permission);
208 2
            }
209
        );
210
    }
211
212
    /**
213
     * USER & LEVEL
214
     * Returns if a level is lower ranking than another level,
215
     * or if a user is lower ranking than another user.
216
     *
217
     * @param $other
218
     * @return bool
219
     */
220 3
    public function isLowerThan($other)
221
    {
222 3
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank > $other->level->rank : $this->rank > $other->rank;
223
    }
224
225
    /**
226
     * USER & LEVEL
227
     * Returns if a level is higher ranking than another level,
228
     * or if a user is higher ranking than another user.
229
     *
230
     * @param $other
231
     * @return bool
232
     */
233 3
    public function isHigherThan($other)
234
    {
235 3
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank < $other->level->rank : $this->rank < $other->rank;
236
    }
237
238
    /**
239
     * USER & LEVEL
240
     * Returns if a equal is lower ranking than another level,
241
     * or if a user is equal ranking than another user.
242
     *
243
     * @param $other
244
     * @return bool
245
     */
246 1
    public function isEqualTo($other)
247
    {
248 1
        return is_a($this, config('laravel-acl.user'), true) ? $this->level->rank == $other->level->rank : $this->rank == $other->rank;
249
    }
250
251
252
    /* ------------------------------------------------------------------------------------------------
253
     |  Other Functions
254
     | ------------------------------------------------------------------------------------------------
255
     */
256
    /**
257
     * USER & LEVEL
258
     * Return a collection of permissions
259
     * assigned to a user
260
     *
261
     * @return \Illuminate\Support\Collection
262
     */
263 2
    protected function cacheGetPermissions()
264
    {
265 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...
266
    }
267
268
    /**
269
     * USER & LEVEL
270
     * Return a collection of all permissions
271
     * associated to a user by direct or
272
     * inheritance
273
     *
274
     * @return \Illuminate\Support\Collection
275
     */
276 6
    protected function cacheGetAllPermissions()
277
    {
278 6
        $rank = is_a($this, config('laravel-acl.level'), true) ? $this->rank : $this->level->rank;
279
280 6
        $levels = config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get();
281
282 6
        $allPerms = new Collection();
283
284
        $levels->each(function ($level, $key) use (&$allPerms) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
285 6
            $allPerms = $allPerms->merge($level->permissions);
286 6
        });
287
288 6
        return $allPerms->merge($this->permissions)->unique('id');
289
    }
290
291
    /**
292
     * USER & LEVEL
293
     * Return a collection of permissions that
294
     * are inherited from a higher level
295
     *
296
     * @return \Illuminate\Support\Collection
297
     */
298 3
    protected function cacheGetInheritedPermissions()
299
    {
300 3
        $rank = is_a($this, config('laravel-acl.level'), true) ? $this->rank : $this->level->rank;
301
302 3
        $levels = is_a($this, config('laravel-acl.user'), true) ?
303 2
            config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get() :
304 3
            config('laravel-acl.level', Level::class)::where('rank', '>', $rank)->with('permissions')->get();
305
306 3
        $inheritedPerms = new Collection();
307
308
        $levels->each(function ($level, $key) use (&$inheritedPerms) {
0 ignored issues
show
Unused Code introduced by
The parameter $key is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
309 3
            $inheritedPerms = $inheritedPerms->merge($level->permissions->load('level'));
310 3
        });
311
312 3
        return $inheritedPerms->unique('id');
313
    }
314
315
    /**
316
     * USER & LEVEL
317
     * Return a collection of permissions still able to be assigned
318
     * ie, not already inherited or explicitly assigned
319
     *
320
     * @return \Illuminate\Support\Collection
321
     */
322 2
    protected function cacheGetAvailablePermissions()
323
    {
324 2
        $allPerms = config('laravel-acl.permission', Permission::class)::with('level')->get();
325
326 2
        return $allPerms->diff($this->permissions);
327
    }
328
329
    /**
330
     * USER & LEVEL
331
     * Check if a model has permission to do something
332
     *
333
     * @param $permission
334
     * @return bool
335
     */
336 2
    protected function cacheHasPermissionTo($permission)
337
    {
338 2
        $permission = $this->getPermission($permission);
339
340 2
        if (is_a($this, config('laravel-acl.user'), true)) {
341 1
            $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...
342
343 1
            if ($this->getAllPermissions()->contains('id', $permission->id)) {
344
                return !$negatedPermissions->contains('id', $permission->id);
345
            }
346
        }
347
348 2
        return $this->getAllPermissions()->contains('id', $permission->id) ||
349 2
            $this->getAllPermissions()->contains('name', '*');
350
    }
351
352
    /**
353
     * USER & LEVEL
354
     * Modify a given set of permissions, given the action to be taken
355
     *
356
     * @param $permissions
357
     * @param $action
358
     */
359 23
    protected function modifyPermissions($permissions, $action)
360
    {
361 23
        Cache::forget('laravel-acl.getAvailablePermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id);
362 23
        Cache::forget('laravel-acl.getAllPermissionsFor' . (new ReflectionClass($this))->getShortName() . '_' . $this->id);
363 23
        Cache::forget('laravel-acl.getNegatedPermissionsForUser_' . $this->id);
364
365 23
        $permissionObjects = $this->buildPermissionsArray($permissions, $action);
366
367 22
        if ($action == 'add' || $action == 'negate') {
368 22
            $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...
369
        }
370
371 22
        if ($action == 'remove') {
372 3
            $this->remove($permissionObjects);
373
        }
374
375 22
        if ($action == 'sync') {
376 2
            $this->sync($permissionObjects);
377
        }
378 22
    }
379
380
    /**
381
     * USER & LEVEL
382
     * Helper function to build the array
383
     * for modifyPermissions
384
     *
385
     * @param $permissions
386
     * @param $action
387
     * @return array
388
     * @throws PermissionNotFoundException
389
     */
390 23
    protected function buildPermissionsArray($permissions, $action)
391
    {
392 23
        $permissionsObjects = [];
393
394 23
        foreach ($permissions as $permission) {
395 23
            $permission = $this->getPermission($permission);
396 22
            Cache::forget('laravel-acl.hasPermissionTo_' . (new ReflectionClass($this))->getShortName() . '_' . $this->id . '_Permission_' . $permission->id);
397
398 22
            if ($action == 'negate') {
399 2
                $permissionsObjects[$permission->id] = ['negated' => true];
400
            } else {
401 22
                is_a($this, config('laravel-acl.user')) ?
402 12
                    array_push($permissionsObjects, $permission->id) :
403 22
                    array_push($permissionsObjects, $permission);
404
            }
405
        }
406
407 22
        return $permissionsObjects;
408
    }
409
410
    /**
411
     * USER & LEVEL
412
     * Helper function to handle adding or negating permissions
413
     *
414
     * @param $permissionObjects
415
     */
416 22
    protected function addOrNegate($permissionObjects)
417
    {
418 22
        if (is_a($this, config('laravel-acl.user')))
419 12
            $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...
420
421 22
        if (is_a($this, config('laravel-acl.level')))
422 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...
423 22
    }
424
425
    /**
426
     * USER & LEVEL
427
     * Helper function to handle removing permissions
428
     *
429
     * @param $permissionObjects
430
     */
431 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...
432
    {
433 3
        if (is_a($this, config('laravel-acl.user')))
434 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...
435
436 3
        if (is_a($this, config('laravel-acl.level'))) {
437
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function ($permission) {
438 1
                return $permission->id;
439 1
            }, $permissionObjects))->update(['level_id' => null]);
440
        }
441 3
    }
442
443
    /**
444
     * USER & LEVEL
445
     * Help function to handle syncing permissions
446
     *
447
     * @param $permissionObjects
448
     */
449 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...
450
    {
451 2
        if (is_a($this, config('laravel-acl.user')))
452 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...
453
454 2
        if (is_a($this, config('laravel-acl.level'))) {
455 1
            $this->clearPermissions();
456
457 1
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function ($permission) {
458 1
                return $permission->id;
459 1
            }, $permissionObjects))
460 1
                ->update(['level_id' => $this->id]);
461
        }
462 2
    }
463
464
    /**
465
     * USER & LEVEL
466
     * Helper function to get the permission whether it is the permission ID
467
     * or the permission name, or the permission object itself.
468
     *
469
     * @param $permission
470
     * @return \z1haze\Acl\Models\Permission
471
     * @throws PermissionNotFoundException
472
     */
473 23 View Code Duplication
    protected function getPermission($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...
474
    {
475 23
        if (is_string($permission))
476 5
            $permission = config('laravel-acl.permission', Permission::class)::whereName($permission)->first();
477
478 23
        if (is_int($permission))
479 4
            $permission = config('laravel-acl.permission', Permission::class)::find($permission);
480
481 23
        if (!$permission)
482 1
            throw new PermissionNotFoundException;
483
484 22
        return $permission;
485
    }
486
}