HasRoles::scopeRole()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

Changes 3
Bugs 1 Features 1
Metric Value
cc 1
eloc 2
c 3
b 1
f 1
nc 1
nop 2
dl 0
loc 5
ccs 1
cts 1
cp 1
crap 1
rs 10
1
<?php
2
3
namespace Maklad\Permission\Traits;
4
5
use Illuminate\Support\Collection;
6
use Jenssegers\Mongodb\Eloquent\Builder;
7
use Jenssegers\Mongodb\Eloquent\Model;
8
use Maklad\Permission\Contracts\RoleInterface as Role;
9
use Maklad\Permission\Helpers;
10
use Maklad\Permission\PermissionRegistrar;
11
use ReflectionException;
12
13
/**
14
 * Trait HasRoles
15
 * @package Maklad\Permission\Traits
16
 */
17
trait HasRoles
18
{
19
    use HasPermissions;
20
21
    private $roleClass;
22 123
23 5
    public static function bootHasRoles()
24 2
    {
25
        static::deleting(function (Model $model) {
26
            if (isset($model->forceDeleting) && !$model->forceDeleting) {
0 ignored issues
show
Bug introduced by
The property forceDeleting does not seem to exist on Jenssegers\Mongodb\Eloquent\Model. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
27 3
                return;
28 123
            }
29 123
30
            $model->roles()->sync([]);
31
        });
32
    }
33
34 69
    public function getRoleClass()
35
    {
36 69
        if ($this->roleClass === null) {
37
            $this->roleClass = app(PermissionRegistrar::class)->getRoleClass();
38
        }
39
        return $this->roleClass;
40
    }
41
42
    /**
43
     * A model may have multiple roles.
44
     */
45
    public function roles()
46
    {
47 4
        return $this->belongsToMany(config('permission.models.role'));
0 ignored issues
show
Bug introduced by
It seems like belongsToMany() must be provided by classes using this trait. How about adding it as abstract method to this trait? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

47
        return $this->/** @scrutinizer ignore-call */ belongsToMany(config('permission.models.role'));
Loading history...
48
    }
49 4
50
    /**
51 4
     * Scope the model query to certain roles only.
52
     *
53
     * @param Builder $query
54
     * @param string|array|Role|Collection $roles
55
     *
56
     * @return Builder
57
     */
58
    public function scopeRole(Builder $query, $roles): Builder
59
    {
60
        $roles = $this->convertToRoleModels($roles);
61 55
62
        return $query->whereIn('role_ids', $roles->pluck('_id'));
63 55
    }
64 55
65 55
    /**
66 55
     * Assign the given role to the model.
67 55
     *
68 53
     * @param array|string|Role ...$roles
69 53
     *
70 53
     * @return array|Role|string
71 51
     */
72
    public function assignRole(...$roles)
73 51
    {
74
        $roles = \collect($roles)
75 51
            ->flatten()
76
            ->map(function ($role) {
77 51
                return $this->getStoredRole($role);
78
            })
79
            ->each(function ($role) {
80
                $this->ensureModelSharesGuard($role);
81
            })
82
            ->all();
83
84
        $this->roles()->saveMany($roles);
85
86
        $this->forgetCachedPermissions();
87 3
88
        return $roles;
89 3
    }
90 3
91 3
    /**
92 3
     * Revoke the given role from the model.
93 3
     *
94
     * @param array|string|Role ...$roles
95 3
     *
96 3
     * @return array|Role|string
97
     */
98 3
    public function removeRole(...$roles)
99
    {
100 3
        \collect($roles)
101
            ->flatten()
102
            ->map(function ($role) {
103
                $role = $this->getStoredRole($role);
104
                $this->roles()->detach($role);
105
106
                return $role;
107
            });
108
109
        $this->forgetCachedPermissions();
110 6
111
        return $roles;
112 6
    }
113
114 6
    /**
115
     * Remove all current roles and set the given ones.
116
     *
117
     * @param array ...$roles
118
     *
119
     * @return array|Role|string
120
     */
121
    public function syncRoles(...$roles)
122
    {
123
        $this->roles()->sync([]);
124 48
125
        return $this->assignRole($roles);
126 48
    }
127 3
128
    /**
129
     * Determine if the model has (one of) the given role(s).
130 48
     *
131 22
     * @param string|array|Role|\Illuminate\Support\Collection $roles
132
     *
133
     * @return bool
134 29
     */
135 16
    public function hasRole($roles): bool
136 29
    {
137
        if (\is_string($roles) && false !== \strpos($roles, '|')) {
138 29
            $roles = \explode('|', $roles);
139
        }
140
141
        if (\is_string($roles) || $roles instanceof Role) {
142
            return $this->roles->contains('name', $roles->name ?? $roles);
0 ignored issues
show
Bug introduced by
The property roles does not exist on Maklad\Permission\Traits\HasRoles. Did you mean roleClass?
Loading history...
Bug introduced by
The property name does not exist on string.
Loading history...
Bug introduced by
Accessing name on the interface Maklad\Permission\Contracts\RoleInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
143
        }
144
145
        $roles = \collect()->make($roles)->map(function ($role) {
146
            return $role instanceof Role ? $role->name : $role;
0 ignored issues
show
Bug introduced by
Accessing name on the interface Maklad\Permission\Contracts\RoleInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
147
        });
148 13
149
        return !$roles->intersect($this->roles->pluck('name'))->isEmpty();
150 13
    }
151
152
    /**
153
     * Determine if the model has any of the given role(s).
154
     *
155
     * @param string|array|Role|\Illuminate\Support\Collection $roles
156
     *
157
     * @return bool
158
     */
159
    public function hasAnyRole($roles): bool
160 7
    {
161
        return $this->hasRole($roles);
162 7
    }
163 4
164
    /**
165
     * Determine if the model has all of the given role(s).
166 7
     *
167 2
     * @param $roles
168
     *
169
     * @return bool
170 6
     */
171 6
    public function hasAllRoles(...$roles): bool
172 6
    {
173
        $helpers = new Helpers();
174 6
        $roles = $helpers->flattenArray($roles);
175
176
        foreach ($roles as $role) {
177
            if (!$this->hasRole($role)) {
178
                return false;
179
            }
180
        }
181
        return true;
182
    }
183
184
    /**
185 55
     * Return Role object
186
     *
187 55
     * @param String|Role $role role name
188 47
     *
189
     * @return Role
190
     * @throws ReflectionException
191 13
     */
192
    protected function getStoredRole($role): Role
193
    {
194
        if (\is_string($role)) {
195
            return $this->getRoleClass()->findByName($role, $this->getDefaultGuardName());
196
        }
197
198
        return $role;
199 1
    }
200
201 1
    /**
202
     * Return a collection of role names associated with this user.
203
     *
204
     * @return Collection
205
     */
206
    public function getRoleNames(): Collection
207
    {
208
        return $this->roles()->pluck('name');
209
    }
210
211 4
    /**
212
     * Convert to Role Models
213 4
     *
214 3
     * @param $roles
215
     *
216
     * @return Collection
217 4
     */
218 2
    private function convertToRoleModels($roles): Collection
219
    {
220
        if (is_array($roles)) {
221 4
            $roles = collect($roles);
222 4
        }
223 4
224
        if (!$roles instanceof Collection) {
225 4
            $roles = collect([$roles]);
226
        }
227
228
        $roles = $roles->map(function ($role) {
229
            return $this->getStoredRole($role);
230
        });
231
232
        return $roles;
233
    }
234
}
235