Completed
Push — master ( 5acf75...dcb410 )
by Stephen
01:54
created

UserAndLevel::addOrNegate()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 3

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 6
cts 6
cp 1
rs 9.4285
c 0
b 0
f 0
cc 3
eloc 5
nc 4
nop 3
crap 3
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 View Code Duplication
    public function isLevel($level)
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...
20
    {
21 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...
22
23 1
        return is_a($this, config('laravel-acl.level'), true) ?
24
            $this->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...
25 1
            $this->level->name == $level->name;
0 ignored issues
show
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 View Code Duplication
    public function hasLevel($level)
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...
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) ?
41
            $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...
42 1
            $this->level->rank <= $level->rank;
43
    }
44
45
    /**
46
     * USER & LEVEL
47
     * Add a single permission to a model
48
     *
49
     * @param $permission
50
     */
51 15
    public function addPermission($permission)
52
    {
53 15
        $this->modifyPermissions([$permission], 'add');
54 14
    }
55
56
    /**
57
     * USER & LEVEL
58
     * Add an array of permissions to a model
59
     *
60
     * @param $permissions
61
     */
62 7
    public function addPermissions(array $permissions)
63
    {
64 7
        $this->modifyPermissions($permissions, 'add');
65 7
    }
66
67
    /**
68
     * USER & LEVEL
69
     * Remove a permission from a model
70
     *
71
     * @param $permission
72
     */
73 2
    public function removePermission($permission)
74
    {
75 2
        $this->modifyPermissions([$permission], 'remove');
76 2
    }
77
78
    /**
79
     * USER & LEVEL
80
     * Remove an array of permissions objects or permission names (can be mixed)
81
     *
82
     * @param $permissions
83
     */
84 1
    public function removePermissions(array $permissions)
85
    {
86 1
        $this->modifyPermissions($permissions, 'remove');
87 1
    }
88
89
    /**
90
     * USER & LEVEL
91
     * Sync permissions on a model
92
     *
93
     * @param $permissions
94
     */
95 2
    public function syncPermissions(array $permissions)
96
    {
97 2
        $this->modifyPermissions($permissions, 'sync');
98 2
    }
99
100
    /**
101
     * USER & LEVEL
102
     * Clear permissions from a model
103
     *
104
     * @return mixed
105
     */
106 3
    public function clearPermissions()
107
    {
108 3
        if (is_a($this, config('laravel-acl.user'), true))
109 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...
110
111 3
        if (is_a($this, config('laravel-acl.level'), true))
112 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...
113 3
    }
114
115
116
    /* ------------------------------------------------------------------------------------------------
117
     |  Other Functions
118
     | ------------------------------------------------------------------------------------------------
119
     */
120
    /**
121
     * USER & LEVEL
122
     * First try the cache to return the collection,
123
     * then fetch it from the database.
124
     *
125
     * See @cacheGetAllPermissions()
126
     *
127
     * @return mixed
128
     */
129 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...
130
    {
131 6
        $model = is_a($this, config('laravel-acl.level'), true) ? 'Level' : 'User';
132
133 6
        return \Cache::remember(
134 6
            'laravel-acl.getAllPermissionsFor' . $model . '_' . $this->id,
135 6
            config('laravel-acl.cacheMinutes'),
136
            function () {
137 6
                return $this->cacheGetAllPermissions();
138 6
            }
139
        );
140
    }
141
142
    /**
143
     * USER & LEVEL
144
     * First try the cache to return the collection,
145
     * then fetch it from the database.
146
     *
147
     * See @cacheGetInheritedPermissions()
148
     *
149
     * @return mixed
150
     */
151 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...
152
    {
153 3
        $model = is_a($this, config('laravel-acl.level'), true) ? 'Level' : 'User';
154
155 3
        return \Cache::remember(
156 3
            'laravel-acl.getInheritedPermissionsFor' . $model . '_' . $this->id,
157 3
            config('laravel-acl.cacheMinutes'),
158
            function () {
159 3
                return $this->cacheGetInheritedPermissions();
160 3
            }
161
        );
162
    }
163
164
    /**
165
     * USER & LEVEL
166
     * First try the cache to return the collection,
167
     * then fetch it from the database.
168
     *
169
     * See @cacheGetAvailablePermissions()
170
     *
171
     * @return mixed
172
     */
173 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...
174
    {
175 2
        $model = is_a($this, config('laravel-acl.level'), true) ? 'Level' : 'User';
176
177 2
        return \Cache::remember(
178 2
            'laravel-acl.getAvailablePermissionsFor' . $model . '_' . $this->id,
179 2
            config('laravel-acl.cacheMinutes'),
180
            function () {
181 2
                return $this->cacheGetAvailablePermissions();
182 2
            }
183
        );
184
    }
185
186
    /**
187
     * USER & LEVEL
188
     * First try the cache to return the collection,
189
     * then fetch it from the database.
190
     *
191
     * See @cacheHasPermissionTo()
192
     *
193
     * @param $permission
194
     * @return mixed
195
     */
196 2
    public function hasPermissionTo($permission)
197
    {
198 2
        $model = is_a($this, config('laravel-acl.level'), true) ? 'Level' : 'User';
199
200 2
        return \Cache::remember(
201 2
            'laravel-acl.hasPermissionTo_' . $model . '_' . $this->id . '_Permission_' . $permission,
202 2
            config('laravel-acl.cacheMinutes'),
203
            function () use ($permission) {
204 2
                return $this->cacheHasPermissionTo($permission);
205 2
            }
206
        );
207
    }
208
209
    /**
210
     * USER & LEVEL
211
     * Returns if a level is lower ranking than another level,
212
     * or if a user is lower ranking than another user.
213
     *
214
     * @param $other
215
     * @return bool
216
     */
217 3
    public function isLowerThan($other)
218
    {
219 3
        return is_a($this, config('laravel-acl.user'), true) ?
220 3
            $this->level->rank > $other->level->rank :
221 3
            $this->rank > $other->rank;
222
    }
223
224
    /**
225
     * USER & LEVEL
226
     * Returns if a level is higher ranking than another level,
227
     * or if a user is higher ranking than another user.
228
     *
229
     * @param $other
230
     * @return bool
231
     */
232 3
    public function isHigherThan($other)
233
    {
234 3
        return is_a($this, config('laravel-acl.user'), true) ?
235 3
            $this->level->rank < $other->level->rank :
236 3
            $this->rank < $other->rank;
237
    }
238
239
    /**
240
     * USER & LEVEL
241
     * Returns if a equal is lower ranking than another level,
242
     * or if a user is equal ranking than another user.
243
     *
244
     * @param $other
245
     * @return bool
246
     */
247 1
    public function isEqualTo($other)
248
    {
249 1
        return is_a($this, config('laravel-acl.user'), true) ?
250 1
            $this->level->rank == $other->level->rank :
251 1
            $this->rank == $other->rank;
252
    }
253
254
255
    /* ------------------------------------------------------------------------------------------------
256
     |  Other Functions
257
     | ------------------------------------------------------------------------------------------------
258
     */
259
    /**
260
     * USER & LEVEL
261
     * Return a collection of all permissions
262
     * associated to a user by direct or
263
     * inheritance
264
     *
265
     * @return mixed
266
     */
267 6
    protected function cacheGetAllPermissions()
268
    {
269 6
        $rank = is_a($this, config('laravel-acl.level'), true) ?
270 3
            $this->rank :
271 6
            $this->level->rank;
272
273 6
        $levels = config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get();
274
275 6
        $allPerms = new Collection();
276
277
        $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...
278 6
            $allPerms = $allPerms->merge($level->permissions);
279 6
        });
280
281 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...
282
    }
283
284
    /**
285
     * USER & LEVEL
286
     * Return a collection of permissions that
287
     * are inherited from a higher level
288
     * @return mixed
289
     */
290 3
    protected function cacheGetInheritedPermissions()
291
    {
292 3
        $rank = is_a($this, config('laravel-acl.level'), true) ?
293 1
            $this->rank :
294 3
            $this->level->rank;
295
296 3
        $levels = is_a($this, config('laravel-acl.user'), true) ?
297 2
            config('laravel-acl.level', Level::class)::where('rank', '>=', $rank)->with('permissions')->get() :
298 3
            config('laravel-acl.level', Level::class)::where('rank', '>', $rank)->with('permissions')->get();
299
300 3
        $inheritedPerms = new Collection();
301
302
        $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...
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
     * @return \Illuminate\Database\Eloquent\Collection
314
     */
315 2
    protected function cacheGetAvailablePermissions()
316
    {
317 2
        $allPerms = config('laravel-acl.permission', Permission::class)::with('level')->get();
318
319 2
        return $allPerms->diff($this->permissions);
320
    }
321
322
    /**
323
     * USER & LEVEL
324
     * Check if a model has permission to do something
325
     *
326
     * @param $permission
327
     * @return bool
328
     */
329 2
    protected function cacheHasPermissionTo($permission)
330
    {
331 2
        $permission = $this->getPermission($permission);
332
333 2
        if (is_a($this, config('laravel-acl.user'), true)) {
334 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...
335
336 1
            if ($this->getAllPermissions()->contains('id', $permission->id)) {
337
                return !$negatedPermissions->contains('id', $permission->id);
338
            }
339
        }
340
        
341 2
        return $this->getAllPermissions()->contains('id', $permission->id) ||
342 2
        $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 $action
351
     * @return mixed
352
     */
353 21
    protected function modifyPermissions($permissions, $action)
354
    {
355 21
        $model = is_a($this, config('laravel-acl.level'), true) ? 'Level' : 'User';
356
357 21
        \Cache::forget('laravel-acl.getAvailablePermissionsFor' . $model . '_' . $this->id);
358 21
        \Cache::forget('laravel-acl.getAllPermissionsFor' . $model . '_' . $this->id);
359 21
        \Cache::forget('laravel-acl.getNegatedPermissionsForUser_' . $this->id);
360
361 21
        $permissionObjects = $this->buildPermissionsArray($permissions, $action, $model);
362
363 20
        if ($action == 'add' || $action == 'negate') {
364 20
            $this->addOrNegate($model, $permissionObjects, $action);
365
        }
366
367 20
        if ($action == 'remove') {
368 3
            $this->remove($model, $permissionObjects);
369
        }
370
371 20
        if ($action == 'sync') {
372 2
            $this->sync($model, $permissionObjects);
373
        }
374 20
    }
375
376
    /**
377
     * USER & LEVEL
378
     * Helper function to build the array
379
     * for modifyPermissions
380
     *
381
     * @param $permissions
382
     * @param $action
383
     * @param $model
384
     * @return mixed
385
     * @throws PermissionNotFoundException
386
     */
387 21
    protected function buildPermissionsArray($permissions, $action, $model)
388
    {
389 21
        $permissionsObjects = [];
390
391 21
        foreach ($permissions as $permission) {
392 21
            $permission = $this->getPermission($permission);
393 20
            \Cache::forget('laravel-acl.hasPermissionTo_' . $model . '_' . $this->id . '_Permission_' . $permission->id);
394
395 20
            if ($action == 'negate') {
396 2
                $permissionsObjects[$permission->id] = ['negated' => true];
397
            } else {
398 20
                $model == 'User' ?
399 11
                    array_push($permissionsObjects, $permission->id) :
400 20
                    array_push($permissionsObjects, $permission);
401
            }
402
        }
403
404 20
        return $permissionsObjects;
405
    }
406
407
    /**
408
     * USER & LEVEL
409
     * Helper function to handle adding or negating permissions
410
     *
411
     * @param $model
412
     * @param $permissionObjects
413
     */
414 20
    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...
415
    {
416 20
        if ($model == 'User')
417 11
            $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...
418
419 20
        if ($model == 'Level')
420 11
            $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...
421 20
    }
422
423
    /**
424
     * USER & LEVEL
425
     * Helper function to handle removing permissions
426
     *
427
     * @param $model
428
     * @param $permissionObjects
429
     */
430 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...
431
    {
432 3
        if ($model == 'User')
433 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...
434
435 3
        if ($model == 'Level') {
436
            config('laravel-acl.permission', Permission::class)::whereIn('id', array_map(function ($permission) {
437 1
                return $permission->id;
438 1
            }, $permissionObjects))->update(['level_id' => null]);
439
        }
440 3
    }
441
442
    /**
443
     * USER & LEVEL
444
     * Help function to handle syncing permissions
445
     *
446
     * @param $model
447
     * @param $permissionObjects
448
     */
449 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...
450
    {
451 2
        if ($model == '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 ($model == '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 mixed
471
     * @throws PermissionNotFoundException
472
     */
473 21 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 21
        if (is_string($permission))
476 5
            $permission = config('laravel-acl.permission', Permission::class)::whereName($permission)->first();
477
478 21
        if (is_int($permission))
479 4
            $permission = config('laravel-acl.permission', Permission::class)::find($permission);
480
481 21
        if (!$permission)
482 1
            throw new PermissionNotFoundException;
483
484 20
        return $permission;
485
    }
486
}