Completed
Branch master (585519)
by Jeremy
40:45 queued 37:23
created

src/Traits/HasRoleAndPermission.php (1 issue)

1
<?php
2
3
namespace jeremykenedy\LaravelRoles\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 jeremykenedy\LaravelRoles\Models\Permission;
12
use jeremykenedy\LaravelRoles\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();
38
    }
39
40
    /**
41
     * Get all roles as collection.
42
     *
43
     * @return Collection
44
     */
45
    public function getRoles()
46
    {
47
        return (!$this->roles) ? $this->roles = $this->roles()->get() : $this->roles;
48
    }
49
50
    /**
51
     * Check if the user has a role or roles.
52
     *
53
     * @param int|string|array $role
54
     * @param bool             $all
55
     *
56
     * @return bool
57
     */
58
    public function hasRole($role, $all = false)
59
    {
60
        if ($this->isPretendEnabled()) {
61
            return $this->pretend('hasRole');
62
        }
63
64
        if (!$all) {
65
            return $this->hasOneRole($role);
66
        }
67
68
        return $this->hasAllRoles($role);
69
    }
70
71
    /**
72
     * Check if the user has at least one of the given roles.
73
     *
74
     * @param int|string|array $role
75
     *
76
     * @return bool
77
     */
78
    public function hasOneRole($role)
79
    {
80
        foreach ($this->getArrayFrom($role) as $role) {
81
            if ($this->checkRole($role)) {
82
                return true;
83
            }
84
        }
85
86
        return false;
87
    }
88
89
    /**
90
     * Check if the user has all roles.
91
     *
92
     * @param int|string|array $role
93
     *
94
     * @return bool
95
     */
96
    public function hasAllRoles($role)
97
    {
98
        foreach ($this->getArrayFrom($role) as $role) {
99
            if (!$this->checkRole($role)) {
100
                return false;
101
            }
102
        }
103
104
        return true;
105
    }
106
107
    /**
108
     * Check if the user has role.
109
     *
110
     * @param int|string $role
111
     *
112
     * @return bool
113
     */
114
    public function checkRole($role)
115
    {
116
        return $this->getRoles()->contains(function ($value) use ($role) {
117
            return $role == $value->id || Str::is($role, $value->slug);
118
        });
119
    }
120
121
    /**
122
     * Attach role to a user.
123
     *
124
     * @param int|Role $role
125
     *
126
     * @return null|bool
127
     */
128
    public function attachRole($role)
129
    {
130
        if ($this->getRoles()->contains($role)) {
131
            return true;
132
        }
133
        $this->roles = null;
134
135
        return $this->roles()->attach($role);
136
    }
137
138
    /**
139
     * Detach role from a user.
140
     *
141
     * @param int|Role $role
142
     *
143
     * @return int
144
     */
145
    public function detachRole($role)
146
    {
147
        $this->roles = null;
148
149
        return $this->roles()->detach($role);
150
    }
151
152
    /**
153
     * Detach all roles from a user.
154
     *
155
     * @return int
156
     */
157
    public function detachAllRoles()
158
    {
159
        $this->roles = null;
160
161
        return $this->roles()->detach();
162
    }
163
164
    /**
165
     * Sync roles for a user.
166
     *
167
     * @param array|\jeremykenedy\LaravelRoles\Models\Role[]|\Illuminate\Database\Eloquent\Collection $roles
168
     *
169
     * @return array
170
     */
171
    public function syncRoles($roles)
172
    {
173
        $this->roles = null;
174
175
        return $this->roles()->sync($roles);
176
    }
177
178
    /**
179
     * Get role level of a user.
180
     *
181
     * @return int
182
     */
183
    public function level()
184
    {
185
        return ($role = $this->getRoles()->sortByDesc('level')->first()) ? $role->level : 0;
186
    }
187
188
    /**
189
     * Get all permissions from roles.
190
     *
191
     * @return Builder
192
     */
193
    public function rolePermissions()
194
    {
195
        $permissionModel = app(config('roles.models.permission'));
196
197
        if (!$permissionModel instanceof Model) {
198
            throw new InvalidArgumentException('[roles.models.permission] must be an instance of \Illuminate\Database\Eloquent\Model');
199
        }
200
201
        return $permissionModel
0 ignored issues
show
Bug Best Practice introduced by
The expression return $permissionModel:...', 'pivot_updated_at')) also could return the type Illuminate\Database\Query\Builder which is incompatible with the documented return type Illuminate\Database\Eloquent\Builder.
Loading history...
202
            ::select(['permissions.*', 'permission_role.created_at as pivot_created_at', 'permission_role.updated_at as pivot_updated_at'])
203
            ->join('permission_role', 'permission_role.permission_id', '=', 'permissions.id')
204
            ->join('roles', 'roles.id', '=', 'permission_role.role_id')
205
            ->whereIn('roles.id', $this->getRoles()->pluck('id')->toArray())
206
            ->orWhere('roles.level', '<', $this->level())
207
            ->groupBy(['permissions.id', 'permissions.name', 'permissions.slug', 'permissions.description', 'permissions.model', 'permissions.created_at', 'permissions.updated_at', 'pivot_created_at', 'pivot_updated_at']);
208
    }
209
210
    /**
211
     * User belongs to many permissions.
212
     *
213
     * @return BelongsToMany
214
     */
215
    public function userPermissions()
216
    {
217
        return $this->belongsToMany(config('roles.models.permission'))->withTimestamps();
218
    }
219
220
    /**
221
     * Get all permissions as collection.
222
     *
223
     * @return Collection
224
     */
225
    public function getPermissions()
226
    {
227
        return (!$this->permissions) ? $this->permissions = $this->rolePermissions()->get()->merge($this->userPermissions()->get()) : $this->permissions;
228
    }
229
230
    /**
231
     * Check if the user has a permission or permissions.
232
     *
233
     * @param int|string|array $permission
234
     * @param bool             $all
235
     *
236
     * @return bool
237
     */
238
    public function hasPermission($permission, $all = false)
239
    {
240
        if ($this->isPretendEnabled()) {
241
            return $this->pretend('hasPermission');
242
        }
243
244
        if (!$all) {
245
            return $this->hasOnePermission($permission);
246
        }
247
248
        return $this->hasAllPermissions($permission);
249
    }
250
251
    /**
252
     * Check if the user has at least one of the given permissions.
253
     *
254
     * @param int|string|array $permission
255
     *
256
     * @return bool
257
     */
258
    public function hasOnePermission($permission)
259
    {
260
        foreach ($this->getArrayFrom($permission) as $permission) {
261
            if ($this->checkPermission($permission)) {
262
                return true;
263
            }
264
        }
265
266
        return false;
267
    }
268
269
    /**
270
     * Check if the user has all permissions.
271
     *
272
     * @param int|string|array $permission
273
     *
274
     * @return bool
275
     */
276
    public function hasAllPermissions($permission)
277
    {
278
        foreach ($this->getArrayFrom($permission) as $permission) {
279
            if (!$this->checkPermission($permission)) {
280
                return false;
281
            }
282
        }
283
284
        return true;
285
    }
286
287
    /**
288
     * Check if the user has a permission.
289
     *
290
     * @param int|string $permission
291
     *
292
     * @return bool
293
     */
294
    public function checkPermission($permission)
295
    {
296
        return $this->getPermissions()->contains(function ($value) use ($permission) {
297
            return $permission == $value->id || Str::is($permission, $value->slug);
298
        });
299
    }
300
301
    /**
302
     * Check if the user is allowed to manipulate with entity.
303
     *
304
     * @param string $providedPermission
305
     * @param Model  $entity
306
     * @param bool   $owner
307
     * @param string $ownerColumn
308
     *
309
     * @return bool
310
     */
311
    public function allowed($providedPermission, Model $entity, $owner = true, $ownerColumn = 'user_id')
312
    {
313
        if ($this->isPretendEnabled()) {
314
            return $this->pretend('allowed');
315
        }
316
317
        if ($owner === true && $entity->{$ownerColumn} == $this->id) {
318
            return true;
319
        }
320
321
        return $this->isAllowed($providedPermission, $entity);
322
    }
323
324
    /**
325
     * Check if the user is allowed to manipulate with provided entity.
326
     *
327
     * @param string $providedPermission
328
     * @param Model  $entity
329
     *
330
     * @return bool
331
     */
332
    protected function isAllowed($providedPermission, Model $entity)
333
    {
334
        foreach ($this->getPermissions() as $permission) {
335
            if ($permission->model != '' && get_class($entity) == $permission->model
336
                && ($permission->id == $providedPermission || $permission->slug === $providedPermission)
337
            ) {
338
                return true;
339
            }
340
        }
341
342
        return false;
343
    }
344
345
    /**
346
     * Attach permission to a user.
347
     *
348
     * @param int|Permission $permission
349
     *
350
     * @return null|bool
351
     */
352
    public function attachPermission($permission)
353
    {
354
        if ($this->getPermissions()->contains($permission)) {
355
            return true;
356
        }
357
        $this->permissions = null;
358
359
        return $this->userPermissions()->attach($permission);
360
    }
361
362
    /**
363
     * Detach permission from a user.
364
     *
365
     * @param int|Permission $permission
366
     *
367
     * @return int
368
     */
369
    public function detachPermission($permission)
370
    {
371
        $this->permissions = null;
372
373
        return $this->userPermissions()->detach($permission);
374
    }
375
376
    /**
377
     * Detach all permissions from a user.
378
     *
379
     * @return int
380
     */
381
    public function detachAllPermissions()
382
    {
383
        $this->permissions = null;
384
385
        return $this->userPermissions()->detach();
386
    }
387
388
    /**
389
     * Sync permissions for a user.
390
     *
391
     * @param array|\jeremykenedy\LaravelRoles\Models\Permission[]|\Illuminate\Database\Eloquent\Collection $permissions
392
     *
393
     * @return array
394
     */
395
    public function syncPermissions($permissions)
396
    {
397
        $this->permissions = null;
398
399
        return $this->userPermissions()->sync($permissions);
400
    }
401
402
    /**
403
     * Check if pretend option is enabled.
404
     *
405
     * @return bool
406
     */
407
    private function isPretendEnabled()
408
    {
409
        return (bool) config('roles.pretend.enabled');
410
    }
411
412
    /**
413
     * Allows to pretend or simulate package behavior.
414
     *
415
     * @param string $option
416
     *
417
     * @return bool
418
     */
419
    private function pretend($option)
420
    {
421
        return (bool) config('roles.pretend.options.'.$option);
422
    }
423
424
    /**
425
     * Get an array from argument.
426
     *
427
     * @param int|string|array $argument
428
     *
429
     * @return array
430
     */
431
    private function getArrayFrom($argument)
432
    {
433
        return (!is_array($argument)) ? preg_split('/ ?[,|] ?/', $argument) : $argument;
434
    }
435
436
    public function callMagic($method, $parameters)
437
    {
438
        if (starts_with($method, 'is')) {
439
            return $this->hasRole(snake_case(substr($method, 2), config('roles.separator')));
440
        } elseif (starts_with($method, 'can')) {
441
            return $this->hasPermission(snake_case(substr($method, 3), config('roles.separator')));
442
        } elseif (starts_with($method, 'allowed')) {
443
            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');
444
        }
445
446
        return parent::__call($method, $parameters);
447
    }
448
449
    public function __call($method, $parameters)
450
    {
451
        return $this->callMagic($method, $parameters);
452
    }
453
}
454