Completed
Pull Request — 5.4 (#4)
by
unknown
03:23
created

HasRoleAndPermission::hasAllRoles()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
c 0
b 0
f 0
rs 9.4285
cc 3
eloc 5
nc 3
nop 1
1
<?php
2
3
namespace SlFomin\Roles\Traits;
4
5
use Illuminate\Database\Eloquent\Builder;
6
use Illuminate\Database\Eloquent\Collection;
7
use Illuminate\Database\Eloquent\Model;
8
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
9
use Illuminate\Support\Str;
10
use InvalidArgumentException;
11
use Ultraware\Roles\Models\Permission;
12
use Ultraware\Roles\Models\Role;
13
14
trait HasRoleAndPermission
15
{
16
    /**
17
     * Property for caching roles.
18
     *
19
     * @var Collection|null
20
     */
21
    protected $roles;
22
23
    /**
24
     * Property for caching permissions.
25
     *
26
     * @var Collection|null
27
     */
28
    protected $permissions;
29
30
    /**
31
     * User belongs to many roles.
32
     *
33
     * @return BelongsToMany
34
     */
35
    public function roles()
36
    {
37
        return $this->belongsToMany(config('roles.models.role'))->withTimestamps();
0 ignored issues
show
Documentation Bug introduced by
The method belongsToMany does not exist on object<SlFomin\Roles\Traits\HasRoleAndPermission>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
38
    }
39
40
    /**
41
     * Get all roles as collection.
42
     *
43
     * @return Collection
44
     */
45
    public function getRoles()
46
    {
47
        if(!$this->roles){
48
            $this->roles = $this->roles()->get();
49
50
            foreach($this->roles as $role)
51
                    $this->roles = $this->roles->merge($role->descendants());
52
        }
53
        return  $this->roles;
54
    }
55
56
    /**
57
     * Check if the user has a role or roles.
58
     *
59
     * @param int|string|array $role
60
     * @param bool $all
61
     * @return bool
62
     */
63
    public function hasRole($role, $all = false)
64
    {
65
        if ($this->isPretendEnabled()) {
66
            return $this->pretend('hasRole');
67
        }
68
69
        if (!$all) {
70
            return $this->hasOneRole($role);
71
        }
72
73
        return $this->hasAllRoles($role);
74
    }
75
76
    /**
77
     * Check if the user has at least one of the given roles.
78
     *
79
     * @param int|string|array $role
80
     * @return bool
81
     */
82
    public function hasOneRole($role)
83
    {
84
        foreach ($this->getArrayFrom($role) as $role) {
85
            if ($this->checkRole($role)) {
86
                return true;
87
            }
88
        }
89
90
        return false;
91
    }
92
93
    /**
94
     * Check if the user has all roles.
95
     *
96
     * @param int|string|array $role
97
     * @return bool
98
     */
99
    public function hasAllRoles($role)
100
    {
101
        foreach ($this->getArrayFrom($role) as $role) {
102
            if (!$this->checkRole($role)) {
103
                return false;
104
            }
105
        }
106
107
        return true;
108
    }
109
110
    /**
111
     * Check if the user has role.
112
     *
113
     * @param int|string $role
114
     * @return bool
115
     */
116
    public function checkRole($role)
117
    {
118
        return $this->getRoles()->contains(function ($value) use ($role) {
119
            return $role == $value->id || Str::is($role, $value->slug);
120
        });
121
    }
122
123
    /**
124
     * Attach role to a user.
125
     *
126
     * @param int|Role $role
127
     * @return null|bool
128
     */
129
    public function attachRole($role)
130
    {
131
        return (!$this->getRoles()->contains($role)) ? $this->roles()->attach($role) : true;
132
    }
133
134
    /**
135
     * Detach role from a user.
136
     *
137
     * @param int|Role $role
138
     * @return int
139
     */
140
    public function detachRole($role)
141
    {
142
        $this->roles = null;
143
144
        return $this->roles()->detach($role);
145
    }
146
147
    /**
148
     * Detach all roles from a user.
149
     *
150
     * @return int
151
     */
152
    public function detachAllRoles()
153
    {
154
        $this->roles = null;
155
156
        return $this->roles()->detach();
157
    }
158
159
    /**
160
     * Sync roles for a user.
161
     *
162
     * @param array|\Ultraware\Roles\Models\Role[]|\Illuminate\Database\Eloquent\Collection $roles
163
     * @return array
164
     */
165
    public function syncRoles($roles)
166
    {
167
        $this->roles = null;
168
169
        return $this->roles()->sync($roles);
170
    }
171
172
    /**
173
     * Get all permissions from roles.
174
     *
175
     * @return Builder
176
     */
177
    public function rolePermissions()
178
    {
179
        $permissionModel = app(config('roles.models.permission'));
180
181
        if (!$permissionModel instanceof Model) {
182
            throw new InvalidArgumentException('[roles.models.permission] must be an instance of \Illuminate\Database\Eloquent\Model');
183
        }
184
185
        return $permissionModel
186
            ::select(['permissions.*', 'permission_role.created_at as pivot_created_at', 'permission_role.updated_at as pivot_updated_at'])
187
            ->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id')
188
            ->join('roles', 'roles.id', '=', 'permission_role.role_id')
189
            ->whereIn('roles.id', $this->getRoles()->pluck('id')->toArray())
190
            ->groupBy(['permissions.id', 'permissions.name', 'permissions.slug', 'permissions.description', 'permissions.model', 'permissions.created_at', 'permissions.updated_at', 'pivot_created_at', 'pivot_updated_at']);
191
    }
192
193
    /**
194
     * User belongs to many permissions.
195
     *
196
     * @return BelongsToMany
197
     */
198
    public function userPermissions()
199
    {
200
        return $this->belongsToMany(config('roles.models.permission'))->withTimestamps();
0 ignored issues
show
Documentation Bug introduced by
The method belongsToMany does not exist on object<SlFomin\Roles\Traits\HasRoleAndPermission>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
201
    }
202
203
    /**
204
     * Get all permissions as collection.
205
     *
206
     * @return Collection
207
     */
208
    public function getPermissions()
209
    {
210
        return (!$this->permissions) ? $this->permissions = $this->rolePermissions()->get()->merge($this->userPermissions()->get()) : $this->permissions;
211
    }
212
213
    /**
214
     * Check if the user has a permission or permissions.
215
     *
216
     * @param int|string|array $permission
217
     * @param bool $all
218
     * @return bool
219
     */
220
    public function hasPermission($permission, $all = false)
221
    {
222
        if ($this->isPretendEnabled()) {
223
            return $this->pretend('hasPermission');
224
        }
225
226
        if (!$all) {
227
            return $this->hasOnePermission($permission);
228
        }
229
230
        return $this->hasAllPermissions($permission);
231
    }
232
233
    /**
234
     * Check if the user has at least one of the given permissions.
235
     *
236
     * @param int|string|array $permission
237
     * @return bool
238
     */
239
    public function hasOnePermission($permission)
240
    {
241
        foreach ($this->getArrayFrom($permission) as $permission) {
242
            if ($this->checkPermission($permission)) {
243
                return true;
244
            }
245
        }
246
247
        return false;
248
    }
249
250
    /**
251
     * Check if the user has all permissions.
252
     *
253
     * @param int|string|array $permission
254
     * @return bool
255
     */
256
    public function hasAllPermissions($permission)
257
    {
258
        foreach ($this->getArrayFrom($permission) as $permission) {
259
            if (!$this->checkPermission($permission)) {
260
                return false;
261
            }
262
        }
263
264
        return true;
265
    }
266
267
    /**
268
     * Check if the user has a permission.
269
     *
270
     * @param int|string $permission
271
     * @return bool
272
     */
273
    public function checkPermission($permission)
274
    {
275
        return $this->getPermissions()->contains(function ($value) use ($permission) {
276
            return $permission == $value->id || Str::is($permission, $value->slug);
277
        });
278
    }
279
280
    /**
281
     * Check if the user is allowed to manipulate with entity.
282
     *
283
     * @param string $providedPermission
284
     * @param Model $entity
285
     * @param bool $owner
286
     * @param string $ownerColumn
287
     * @return bool
288
     */
289
    public function allowed($providedPermission, Model $entity, $owner = true, $ownerColumn = 'user_id')
290
    {
291
        if ($this->isPretendEnabled()) {
292
            return $this->pretend('allowed');
293
        }
294
295
        if ($owner === true && $entity->{$ownerColumn} == $this->id) {
296
            return true;
297
        }
298
299
        return $this->isAllowed($providedPermission, $entity);
300
    }
301
302
    /**
303
     * Check if the user is allowed to manipulate with provided entity.
304
     *
305
     * @param string $providedPermission
306
     * @param Model $entity
307
     * @return bool
308
     */
309
    protected function isAllowed($providedPermission, Model $entity)
310
    {
311
        foreach ($this->getPermissions() as $permission) {
312
            if ($permission->model != '' && get_class($entity) == $permission->model
313
                && ($permission->id == $providedPermission || $permission->slug === $providedPermission)
314
            ) {
315
                return true;
316
            }
317
        }
318
319
        return false;
320
    }
321
322
    /**
323
     * Attach permission to a user.
324
     *
325
     * @param int|Permission $permission
326
     * @return null|bool
327
     */
328
    public function attachPermission($permission)
329
    {
330
        return (!$this->getPermissions()->contains($permission)) ? $this->userPermissions()->attach($permission) : true;
331
    }
332
333
    /**
334
     * Detach permission from a user.
335
     *
336
     * @param int|Permission $permission
337
     * @return int
338
     */
339
    public function detachPermission($permission)
340
    {
341
        $this->permissions = null;
342
343
        return $this->userPermissions()->detach($permission);
344
    }
345
346
    /**
347
     * Detach all permissions from a user.
348
     *
349
     * @return int
350
     */
351
    public function detachAllPermissions()
352
    {
353
        $this->permissions = null;
354
355
        return $this->userPermissions()->detach();
356
    }
357
358
    /**
359
     * Sync permissions for a user.
360
     *
361
     * @param array|\Ultraware\Roles\Models\Permission[]|\Illuminate\Database\Eloquent\Collection $permissions
362
     * @return array
363
     */
364
    public function syncPermissions($permissions)
365
    {
366
        $this->permissions = null;
367
368
        return $this->userPermissions()->sync($permissions);
369
    }
370
371
    /**
372
     * Check if pretend option is enabled.
373
     *
374
     * @return bool
375
     */
376
    private function isPretendEnabled()
377
    {
378
        return (bool) config('roles.pretend.enabled');
379
    }
380
381
    /**
382
     * Allows to pretend or simulate package behavior.
383
     *
384
     * @param string $option
385
     * @return bool
386
     */
387
    private function pretend($option)
388
    {
389
        return (bool) config('roles.pretend.options.' . $option);
390
    }
391
392
    /**
393
     * Get an array from argument.
394
     *
395
     * @param int|string|array $argument
396
     * @return array
397
     */
398
    private function getArrayFrom($argument)
399
    {
400
        return (!is_array($argument)) ? preg_split('/ ?[,|] ?/', $argument) : $argument;
401
    }
402
403
    public function callMagic($method, $parameters)
404
    {
405
        if (starts_with($method, 'is')) {
406
            return $this->hasRole(snake_case(substr($method, 2), config('roles.separator')));
407
        } elseif (starts_with($method, 'can')) {
408
            return $this->hasPermission(snake_case(substr($method, 3), config('roles.separator')));
409
        } elseif (starts_with($method, 'allowed')) {
410
            return $this->allowed(snake_case(substr($method, 7), config('roles.separator')), $parameters[0], (isset($parameters[1])) ? $parameters[1] : true, (isset($parameters[2])) ? $parameters[2] : 'user_id');
411
        }
412
413
        return parent::__call($method, $parameters);
414
    }
415
416
    public function __call($method, $parameters)
417
    {
418
        return $this->callMagic($method, $parameters);
419
    }
420
}
421