Completed
Pull Request — master (#23)
by ARCANEDEV
02:45
created

Role::detachPermission()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 12
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
ccs 4
cts 4
cp 1
cc 2
eloc 7
nc 2
nop 2
crap 2
1
<?php namespace Arcanedev\LaravelAuth\Models;
2
3
use Arcanedev\LaravelAuth\Events\Roles\AttachedPermissionToRole;
4
use Arcanedev\LaravelAuth\Events\Roles\AttachedUserToRole;
5
use Arcanedev\LaravelAuth\Events\Roles\AttachingPermissionToRole;
6
use Arcanedev\LaravelAuth\Events\Roles\AttachingUserToRole;
7
use Arcanedev\LaravelAuth\Events\Roles\DetachedAllPermissionsFromRole;
8
use Arcanedev\LaravelAuth\Events\Roles\DetachedAllUsersFromRole;
9
use Arcanedev\LaravelAuth\Events\Roles\DetachedPermissionFromRole;
10
use Arcanedev\LaravelAuth\Events\Roles\DetachedUserFromRole;
11
use Arcanedev\LaravelAuth\Events\Roles\DetachingAllPermissionsFromRole;
12
use Arcanedev\LaravelAuth\Events\Roles\DetachingAllUsersFromRole;
13
use Arcanedev\LaravelAuth\Events\Roles\DetachingPermissionFromRole;
14
use Arcanedev\LaravelAuth\Events\Roles\DetachingUserFromRole;
15
use Arcanedev\LaravelAuth\Models\Traits\Activatable;
16
use Arcanesoft\Contracts\Auth\Models\Permission as PermissionContract;
17
use Arcanesoft\Contracts\Auth\Models\Role as RoleContract;
18
use Arcanesoft\Contracts\Auth\Models\User;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Arcanedev\LaravelAuth\Models\User.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
19
use Illuminate\Database\Eloquent\Model as Eloquent;
20
use Illuminate\Support\Str;
21
22
/**
23
 * Class     Role
24
 *
25
 * @package  Arcanedev\LaravelAuth\Models
26
 * @author   ARCANEDEV <[email protected]>
27
 *
28
 * @property  int                                       id
29
 * @property  string                                    name
30
 * @property  string                                    slug
31
 * @property  string                                    description
32
 * @property  bool                                      is_active
33
 * @property  bool                                      is_locked
34
 * @property  \Carbon\Carbon                            created_at
35
 * @property  \Carbon\Carbon                            updated_at
36
 *
37
 * @property  \Illuminate\Database\Eloquent\Collection       users
38
 * @property  \Illuminate\Database\Eloquent\Collection       permissions
39
 *
40
 * @property  \Arcanedev\LaravelAuth\Models\Pivots\RoleUser|\Arcanedev\LaravelAuth\Models\Pivots\PermissionRole  pivot
41
 */
42
class Role extends AbstractModel implements RoleContract
0 ignored issues
show
Bug introduced by
There is one abstract method forceFill in this class; you could implement it, or declare this class as abstract.
Loading history...
43
{
44
    /* ------------------------------------------------------------------------------------------------
45
     |  Traits
46
     | ------------------------------------------------------------------------------------------------
47
     */
48
    use Activatable;
49
50
    /* ------------------------------------------------------------------------------------------------
51
     |  Properties
52
     | ------------------------------------------------------------------------------------------------
53
     */
54
    /**
55
     * The attributes that are mass assignable.
56
     *
57
     * @var array
58
     */
59
    protected $fillable = ['name', 'slug', 'description'];
60
61
    /**
62
     * The attributes that should be casted to native types.
63
     *
64
     * @var array
65
     */
66 225
    protected $casts = [
67
        'is_active' => 'boolean',
68 225
        'is_locked' => 'boolean',
69
    ];
70 225
71 225
    /* ------------------------------------------------------------------------------------------------
72
     |  Constructor
73
     | ------------------------------------------------------------------------------------------------
74
     */
75
    /**
76
     * Create a new Eloquent model instance.
77
     *
78
     * @param  array  $attributes
79
     */
80
    public function __construct(array $attributes = [])
81
    {
82 90
        $this->setTable(config('laravel-auth.roles.table', 'roles'));
83
84 90
        parent::__construct($attributes);
85 90
    }
86 90
87
    /* ------------------------------------------------------------------------------------------------
88
     |  Relationships
89
     | ------------------------------------------------------------------------------------------------
90
     */
91
    /**
92
     * Role belongs to many users.
93 90
     *
94
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
95 90
     */
96 90
    public function users()
97
    {
98
        return $this
99
            ->belongsToMany(
100
                config('laravel-auth.users.model', User::class),
101
                $this->getPrefix().config('laravel-auth.role-user.table', 'permission_role')
102
            )
103
            ->using(Pivots\RoleUser::class)
104
            ->withTimestamps();
105
    }
106
107
    /**
108 9
     * Role belongs to many permissions.
109
     *
110 9
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
111 9
     */
112 9
    public function permissions()
113
    {
114 9
        return $this
115
            ->belongsToMany(
116
                config('laravel-auth.permissions.model', Permission::class),
117
                $this->getPrefix().config('laravel-auth.permission-role.table', 'permission_role')
118
            )
119
            ->using(Pivots\PermissionRole::class)
120
            ->withTimestamps();
121
    }
122
123
    /* ------------------------------------------------------------------------------------------------
124 3
     |  Getters & Setters
125
     | ------------------------------------------------------------------------------------------------
126 3
     */
127 3
    /**
128
     * Set the name attribute.
129 3
     *
130 3
     * @param  string  $name
131
     */
132 3
    public function setNameAttribute($name)
133
    {
134
        $this->attributes['name'] = $name;
135
        $this->setSlugAttribute($name);
136
    }
137
138
    /**
139
     * Set the slug attribute.
140
     *
141
     * @param  string  $slug
142 3
     */
143
    public function setSlugAttribute($slug)
144 3
    {
145 3
        $this->attributes['slug'] = $this->slugify($slug);
146
    }
147 3
148
    /* ------------------------------------------------------------------------------------------------
149
     |  CRUD Functions
150
     | ------------------------------------------------------------------------------------------------
151
     */
152
    /**
153
     * Attach a permission to a role.
154
     *
155
     * @param  \Arcanesoft\Contracts\Auth\Models\User|int  $user
156
     * @param  bool                                        $reload
157 9
     */
158
    public function attachUser($user, $reload = true)
159 9
    {
160 9
        if ( ! $this->hasUser($user)) {
161
            event(new AttachingUserToRole($this, $user));
0 ignored issues
show
Bug introduced by
It seems like $user defined by parameter $user on line 158 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...erToRole::__construct() does only seem to accept object<Arcanesoft\Contracts\Auth\Models\User>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
162 9
            $this->users()->attach($user);
163
            event(new AttachedUserToRole($this, $user));
0 ignored issues
show
Bug introduced by
It seems like $user defined by parameter $user on line 158 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...erToRole::__construct() does only seem to accept object<Arcanesoft\Contracts\Auth\Models\User>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
164
165
            $this->loadUsers($reload);
166
        }
167
    }
168
169
    // TODO: Adding attach multiple users to a role ?
170
171 27
    /**
172
     * Detach a user from a role.
173 27
     *
174 27
     * @param  \Arcanesoft\Contracts\Auth\Models\User|int  $user
175 27
     * @param  bool                                        $reload
176
     *
177 27
     * @return int
178
     */
179
    public function detachUser($user, $reload = true)
180
    {
181
        event(new DetachingUserFromRole($this, $user));
0 ignored issues
show
Bug introduced by
It seems like $user defined by parameter $user on line 179 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...FromRole::__construct() does only seem to accept object<Arcanesoft\Contracts\Auth\Models\User>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
182
        $results = $this->users()->detach($user);
183
        event(new DetachedUserFromRole($this, $user, $results));
0 ignored issues
show
Bug introduced by
It seems like $user defined by parameter $user on line 179 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...FromRole::__construct() does only seem to accept object<Arcanesoft\Contracts\Auth\Models\User>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
184
185
        $this->loadUsers($reload);
186
187 3
        return $results;
188
    }
189 3
190 3
    // TODO: Adding detach multiple users to a role ?
191
192 3
    /**
193 3
     * Detach all users from a role.
194
     *
195 3
     * @param  bool  $reload
196
     *
197
     * @return int
198
     */
199
    public function detachAllUsers($reload = true)
200
    {
201
        event(new DetachingAllUsersFromRole($this));
202
        $results = $this->users()->detach();
203
        event(new DetachedAllUsersFromRole($this, $results));
204
205 3
        $this->loadUsers($reload);
206
207 3
        return $results;
208 3
    }
209
210 3
    /**
211
     * Attach a permission to a role.
212
     *
213
     * @param  \Arcanesoft\Contracts\Auth\Models\Permission|int  $permission
214
     * @param  bool                                              $reload
215
     */
216
    public function attachPermission($permission, $reload = true)
217
    {
218
        if ($this->hasPermission($permission)) return;
219
220 27
        event(new AttachingPermissionToRole($this, $permission));
0 ignored issues
show
Bug introduced by
It seems like $permission defined by parameter $permission on line 216 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...onToRole::__construct() does only seem to accept object<Arcanesoft\Contra...Auth\Models\Permission>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
221
        $this->permissions()->attach($permission);
222 27
        event(new AttachedPermissionToRole($this, $permission));
0 ignored issues
show
Bug introduced by
It seems like $permission defined by parameter $permission on line 216 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...onToRole::__construct() does only seem to accept object<Arcanesoft\Contra...Auth\Models\Permission>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
223 27
224
        $this->loadPermissions($reload);
225 27
    }
226
227
    // TODO: Adding attach multiple permissions to a role ?
228
229
    /**
230
     * Detach a permission from a role.
231
     *
232
     * @param  \Arcanesoft\Contracts\Auth\Models\Permission|int  $permission
233
     * @param  bool                                              $reload
234
     *
235
     * @return int
236
     */
237
    public function detachPermission($permission, $reload = true)
238
    {
239
        if ( ! $this->hasPermission($permission)) return 0;
240
241 9
        event(new DetachingPermissionFromRole($this, $permission));
0 ignored issues
show
Bug introduced by
It seems like $permission defined by parameter $permission on line 237 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...FromRole::__construct() does only seem to accept object<Arcanesoft\Contra...Auth\Models\Permission>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
242 9
        $results = $this->permissions()->detach($permission);
243 9
        event(new DetachedPermissionFromRole($this, $permission, $results));
0 ignored issues
show
Bug introduced by
It seems like $permission defined by parameter $permission on line 237 can also be of type integer; however, Arcanedev\LaravelAuth\Ev...FromRole::__construct() does only seem to accept object<Arcanesoft\Contra...Auth\Models\Permission>, maybe add an additional type check?

This check looks at variables that have been passed in as parameters and are passed out again to other methods.

If the outgoing method call has stricter type requirements than the method itself, an issue is raised.

An additional type check may prevent trouble.

Loading history...
244
245 9
        $this->loadPermissions($reload);
246
247
        return $results;
248
    }
249
250
    // TODO: Adding detach multiple permissions to a role ?
251
252
    /**
253
     * Detach all permissions from a role.
254
     *
255
     * @param  bool  $reload
256 6
     *
257
     * @return int
258 6
     */
259 6
    public function detachAllPermissions($reload = true)
260 6
    {
261
        if ($this->permissions->isEmpty()) return 0;
262
263 6
        event(new DetachingAllPermissionsFromRole($this));
264
        $results = $this->permissions()->detach();
265
        event(new DetachedAllPermissionsFromRole($this, $results));
266
267
        $this->loadPermissions($reload);
268
269
        return $results;
270
    }
271
272
    /* -----------------------------------------------------------------
273
     |  Check Methods
274 3
     | -----------------------------------------------------------------
275
     */
276 3
    /**
277
     * Check if role has the given user (User Model or Id).
278 3
     *
279
     * @param  \Arcanesoft\Contracts\Auth\Models\User|int  $id
280
     *
281
     * @return bool
282
     */
283
    public function hasUser($id)
284
    {
285
        if ($id instanceof Eloquent) $id = $id->getKey();
0 ignored issues
show
Bug introduced by
The class Illuminate\Database\Eloquent\Model does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
286 6
287
        return $this->users->contains('id', $id);
288 6
    }
289
290
    /**
291
     * Check if role has the given permission (Permission Model or Id).
292
     *
293
     * @param  \Arcanesoft\Contracts\Auth\Models\User|int  $id
294
     *
295
     * @return bool
296
     */
297
    public function hasPermission($id)
298 18
    {
299
        if ($id instanceof Eloquent) $id = $id->getKey();
0 ignored issues
show
Bug introduced by
The class Illuminate\Database\Eloquent\Model does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
300 18
301
        return $this->permissions->contains('id', $id);
302
    }
303
304
    /**
305
     * Check if role is associated with a permission by slug.
306
     *
307
     * @param  string  $slug
308
     *
309
     * @return bool
310
     */
311
    public function can($slug)
312
    {
313
        return $this->permissions
314 9
                ->filter(function(PermissionContract $permission) use ($slug) {
315
                    return $permission->checkSlug($slug);
316 9
                })
317
                ->first() !== null;
318
    }
319
320
    /**
321
     * Check if a role is associated with any of given permissions.
322
     *
323
     * @param  array  $permissions
324
     * @param  array  &$failedPermissions
325
     *
326 27
     * @return bool
327
     */
328 27
    public function canAny(array $permissions, array &$failedPermissions = [])
329
    {
330
        foreach ($permissions as $permission) {
331
            if ( ! $this->can($permission))
332
                $failedPermissions[] = $permission;
333
        }
334
335
        return count($permissions) !== count($failedPermissions);
336
    }
337
338 90
    /**
339
     * Check if role is associated with all given permissions.
340 90
     *
341
     * @param  array  $permissions
342
     * @param  array  &$failedPermissions
343
     *
344
     * @return bool
345
     */
346
    public function canAll(array $permissions, array &$failedPermissions = [])
347
    {
348
        $this->canAny($permissions, $failedPermissions);
349
350
        return count($failedPermissions) === 0;
351
    }
352
353
    /**
354
     * Check if the role is locked.
355
     *
356
     * @return bool
357
     */
358
    public function isLocked()
359
    {
360
        return $this->is_locked;
361
    }
362
363
    /**
364
     * Check if slug is the same as the given value.
365
     *
366
     * @param  string  $value
367
     *
368
     * @return bool
369
     */
370
    public function checkSlug($value)
371
    {
372
        return $this->slug === $this->slugify($value);
373
    }
374
375
    /* ------------------------------------------------------------------------------------------------
376
     |  Other Functions
377
     | ------------------------------------------------------------------------------------------------
378
     */
379
    /**
380
     * Load the users.
381
     *
382
     * @param  bool  $load
383
     *
384
     * @return self
385
     */
386
    protected function loadUsers($load = true)
387
    {
388
        return $load ? $this->load('users') : $this;
389
    }
390
391
    /**
392
     * Load the permissions.
393
     *
394
     * @param  bool  $load
395
     *
396
     * @return self
397
     */
398
    protected function loadPermissions($load = true)
399
    {
400
        return $load ? $this->load('permissions') : $this;
401
    }
402
403
    /**
404
     * Slugify the value.
405
     *
406
     * @param  string  $value
407
     *
408
     * @return string
409
     */
410
    protected function slugify($value)
411
    {
412
        return Str::slug($value, config('laravel-auth.roles.slug-separator', '-'));
413
    }
414
}
415