Completed
Push — master ( c436ad...d0a6e2 )
by Stephen
02:15
created

UserAndLevel::removePermission()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
namespace z1haze\Acl\Traits;
4
5
use Illuminate\Support\Collection;
6
use z1haze\Acl\Exceptions\PermissionNotFoundException;
7
use z1haze\Acl\Models\Level;
8
use z1haze\Acl\Models\Permission;
9
10
trait UserAndLevel
11
{
12
    /**
13
     * USER & LEVEL
14
     * Check if a model has a given level
15
     *
16
     * @param $level
17
     * @return bool
18
     */
19 1
    public function isLevel($level)
20
    {
21 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...
22
23 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...
24
    }
25
26
    /**
27
     * USER & LEVEL
28
     * Check if a user has or has inherited
29
     * a given level
30
     *
31
     * @param $level
32
     * @return bool
33
     */
34 1
    public function hasLevel($level)
35
    {
36 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...
37
38 1
        return get_class($this) == config('laravel-acl.level') ?
39
            $this->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...
40 1
            $this->level->rank <= $level->rank;
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
     * @return mixed
103
     */
104 3
    public function clearPermissions()
105
    {
106 3
        if (get_class($this) == config('laravel-acl.user'))
107 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...
108
109 3
        if (get_class($this) == config('laravel-acl.level'))
110 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...
111 3
    }
112
113
114
    /* ------------------------------------------------------------------------------------------------
115
     |  Other Functions
116
     | ------------------------------------------------------------------------------------------------
117
     */
118
    /**
119
     * USER & LEVEL
120
     * First try the cache to return the collection,
121
     * then fetch it from the database.
122
     *
123
     * See @cacheGetAllPermissions()
124
     *
125
     * @return mixed
126
     */
127 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...
128
    {
129 6
        $model = get_class($this) == config('laravel-acl.level') ? 'Level' : 'User';
130
131 6
        return \Cache::remember(
132 6
            'laravel-acl.getAllPermissionsFor' . $model . '_' . $this->id,
133 6
            config('laravel-acl.cacheMinutes'),
134
            function () {
135 6
                return $this->cacheGetAllPermissions();
136 6
            }
137
        );
138
    }
139
140
    /**
141
     * USER & LEVEL
142
     * First try the cache to return the collection,
143
     * then fetch it from the database.
144
     *
145
     * See @cacheGetInheritedPermissions()
146
     *
147
     * @return mixed
148
     */
149 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...
150
    {
151 3
        $model = get_class($this) == config('laravel-acl.level') ? 'Level' : 'User';
152
153 3
        return \Cache::remember(
154 3
            'laravel-acl.getInheritedPermissionsFor' . $model . '_' . $this->id,
155 3
            config('laravel-acl.cacheMinutes'),
156
            function () {
157 3
                return $this->cacheGetInheritedPermissions();
158 3
            }
159
        );
160
    }
161
162
    /**
163
     * USER & LEVEL
164
     * First try the cache to return the collection,
165
     * then fetch it from the database.
166
     *
167
     * See @cacheGetAvailablePermissions()
168
     *
169
     * @return mixed
170
     */
171 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...
172
    {
173 2
        $model = get_class($this) == config('laravel-acl.level') ? 'Level' : 'User';
174
175 2
        return \Cache::remember(
176 2
            'laravel-acl.getAvailablePermissionsFor' . $model . '_' . $this->id,
177 2
            config('laravel-acl.cacheMinutes'),
178
            function () {
179 2
                return $this->cacheGetAvailablePermissions();
180 2
            }
181
        );
182
    }
183
184
    /**
185
     * USER & LEVEL
186
     * First try the cache to return the collection,
187
     * then fetch it from the database.
188
     *
189
     * See @cacheHasPermissionTo()
190
     *
191
     * @param $permission
192
     * @return mixed
193
     */
194 2
    public function hasPermissionTo($permission)
195
    {
196 2
        $model = get_class($this) == config('laravel-acl.level') ? 'Level' : 'User';
197
198 2
        return \Cache::remember(
199 2
            'laravel-acl.hasPermissionTo_' . $model . '_' . $this->id . '_Permission_' . $permission,
200 2
            config('laravel-acl.cacheMinutes'),
201
            function () use ($permission) {
202 2
                return $this->cacheHasPermissionTo($permission);
203 2
            }
204
        );
205
    }
206
207
    /**
208
     * USER & LEVEL
209
     * Returns if a level is lower ranking than another level,
210
     * or if a user is lower ranking than another user.
211
     *
212
     * @param $other
213
     * @return bool
214
     */
215 3
    public function isLowerThan($other)
216
    {
217 3
        return get_class($this) == config('laravel-acl.user') ?
218 3
            $this->level->rank > $other->level->rank :
219 3
            $this->rank > $other->rank;
220
    }
221
222
    /**
223
     * USER & LEVEL
224
     * Returns if a level is higher ranking than another level,
225
     * or if a user is higher ranking than another user.
226
     *
227
     * @param $other
228
     * @return bool
229
     */
230 3
    public function isHigherThan($other)
231
    {
232 3
        return get_class($this) == config('laravel-acl.user') ?
233 3
            $this->level->rank < $other->level->rank :
234 3
            $this->rank < $other->rank;
235
    }
236
237
    /**
238
     * USER & LEVEL
239
     * Returns if a equal is lower ranking than another level,
240
     * or if a user is equal ranking than another user.
241
     *
242
     * @param $other
243
     * @return bool
244
     */
245 1
    public function isEqualTo($other)
246
    {
247 1
        return get_class($this) == config('laravel-acl.user') ?
248 1
            $this->level->rank == $other->level->rank :
249 1
            $this->rank == $other->rank;
250
    }
251
252
253
    /* ------------------------------------------------------------------------------------------------
254
     |  Other Functions
255
     | ------------------------------------------------------------------------------------------------
256
     */
257
    /**
258
     * USER & LEVEL
259
     * Return a collection of all permissions
260
     * associated to a user by direct or
261
     * inheritance
262
     *
263
     * @return mixed
264
     */
265 6
    protected function cacheGetAllPermissions()
266
    {
267 6
        $rank = get_class($this) == config('laravel-acl.level') ?
268 3
            $this->rank :
269 6
            $this->level->rank;
270
271 6
        $levels = config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get();
272
273 6
        $allPerms = new Collection();
274
275
        $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...
276 6
            $allPerms = $allPerms->merge($level->permissions);
277 6
        });
278
279 6
        return $allPerms->merge($this->permissions)->unique('id');
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...
280
    }
281
282
    /**
283
     * USER & LEVEL
284
     * Return a collection of permissions that
285
     * are inherited from a higher level
286
     * @return mixed
287
     */
288 3
    protected function cacheGetInheritedPermissions()
289
    {
290 3
        $rank = get_class($this) == config('laravel-acl.level') ?
291 1
            $this->rank :
292 3
            $this->level->rank;
293
294 3
        $levels = get_class($this) == config('laravel-acl.user') ?
295 2
            config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get() :
296 3
            config('laravel-acl.level', Level::class)::where('rank', '>', $rank)->with('permissions')->get();
297
298 3
        $inheritedPerms = new Collection();
299
300
        $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...
301 3
            $inheritedPerms = $inheritedPerms->merge($level->permissions->load('level'));
302 3
        });
303
304 3
        return $inheritedPerms->unique('id');
305
    }
306
307
    /**
308
     * USER & LEVEL
309
     * Return a collection of permissions still able to be assigned
310
     * ie, not already inherited or explicitly assigned
311
     * @return \Illuminate\Database\Eloquent\Collection
312
     */
313 2
    protected function cacheGetAvailablePermissions()
314
    {
315 2
        $allPerms = config('laravel-acl.permission', Permission::class)::with('level')->get();
316
317 2
        return $allPerms->diff($this->permissions);
318
    }
319
320
    /**
321
     * USER & LEVEL
322
     * Check if a model has permission to do something
323
     *
324
     * @param $permission
325
     * @return bool
326
     */
327 2
    protected function cacheHasPermissionTo($permission)
328
    {
329 2
        $permission = $this->getPermission($permission);
330
331 2
        if (get_class($this) == config('laravel-acl.user')) {
332 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...
333
334 1
            if ($this->getAllPermissions()->contains('id', $permission->id)) {
335
                return !$negatedPermissions->contains('id', $permission->id);
336
            }
337
        }
338
        
339 2
        return $this->getAllPermissions()->contains('id', $permission->id) ||
340 2
        $this->getAllPermissions()->contains('name', '*');
341
    }
342
343
    /**
344
     * USER & LEVEL
345
     * Modify a given set of permissions, given the action to be taken
346
     *
347
     * @param $permissions
348
     * @param $action
349
     * @return mixed
350
     */
351 23
    protected function modifyPermissions($permissions, $action)
352
    {
353 23
        $model = get_class($this) == config('laravel-acl.level') ? 'Level' : 'User';
354
355 23
        \Cache::forget('laravel-acl.getAvailablePermissionsFor' . $model . '_' . $this->id);
356 23
        \Cache::forget('laravel-acl.getAllPermissionsFor' . $model . '_' . $this->id);
357 23
        \Cache::forget('laravel-acl.getNegatedPermissionsForUser_' . $this->id);
358
359 23
        $permissionObjects = $this->buildPermissionsArray($permissions, $action, $model);
360
361 22
        if ($action == 'add' || $action == 'negate') {
362 22
            $this->addOrNegate($model, $permissionObjects, $action);
363
        }
364
365 22
        if ($action == 'remove') {
366 3
            $this->remove($model, $permissionObjects);
367
        }
368
369 22
        if ($action == 'sync') {
370 2
            $this->sync($model, $permissionObjects);
371
        }
372 22
    }
373
374
    /**
375
     * USER & LEVEL
376
     * Helper function to build the array
377
     * for modifyPermissions
378
     *
379
     * @param $permissions
380
     * @param $action
381
     * @param $model
382
     * @return mixed
383
     * @throws PermissionNotFoundException
384
     */
385 23
    protected function buildPermissionsArray($permissions, $action, $model)
386
    {
387 23
        $permissionsObjects = [];
388
389 23
        foreach ($permissions as $permission) {
390 23
            $permission = $this->getPermission($permission);
391 22
            \Cache::forget('laravel-acl.hasPermissionTo_' . $model . '_' . $this->id . '_Permission_' . $permission->id);
392
393 22
            if ($action == 'negate') {
394 2
                $permissionsObjects[$permission->id] = ['negated' => true];
395
            } else {
396 22
                $model == 'User' ?
397 12
                    array_push($permissionsObjects, $permission->id) :
398 22
                    array_push($permissionsObjects, $permission);
399
            }
400
        }
401
402 22
        return $permissionsObjects;
403
    }
404
405
    /**
406
     * USER & LEVEL
407
     * Helper function to handle adding or negating permissions
408
     *
409
     * @param $model
410
     * @param $permissionObjects
411
     */
412 22
    protected function addOrNegate($model, $permissionObjects, $action)
0 ignored issues
show
Unused Code introduced by
The parameter $action 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...
413
    {
414 22
        if ($model == 'User')
415 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...
416
417 22
        if ($model == '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 22
    }
420
421
    /**
422
     * USER & LEVEL
423
     * Helper function to handle removing permissions
424
     *
425
     * @param $model
426
     * @param $permissionObjects
427
     */
428 3 View Code Duplication
    protected function remove($model, $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 ($model == '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 3
        if ($model == 'Level') {
434
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function ($permission) {
435 1
                return $permission->id;
436 1
            }, $permissionObjects))->update(['level_id' => null]);
437
        }
438 3
    }
439
440
    /**
441
     * USER & LEVEL
442
     * Help function to handle syncing permissions
443
     *
444
     * @param $model
445
     * @param $permissionObjects
446
     */
447 2 View Code Duplication
    protected function sync($model, $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 ($model == '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 2
        if ($model == 'Level') {
453 1
            $this->clearPermissions();
454
455 1
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function ($permission) {
456 1
                return $permission->id;
457 1
            }, $permissionObjects))
458 1
                ->update(['level_id' => $this->id]);
459
        }
460 2
    }
461
462
    /**
463
     * USER & LEVEL
464
     * Helper function to get the permission whether it is the permission ID
465
     * or the permission name, or the permission object itself.
466
     *
467
     * @param $permission
468
     * @return mixed
469
     * @throws PermissionNotFoundException
470
     */
471 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...
472
    {
473 23
        if (is_string($permission))
474 5
            $permission = config('laravel-acl.permission', Permission::class)::whereName($permission)->first();
475
476 23
        if (is_int($permission))
477 4
            $permission = config('laravel-acl.permission', Permission::class)::find($permission);
478
479 23
        if (!$permission)
480 1
            throw new PermissionNotFoundException;
481
482 22
        return $permission;
483
    }
484
}