1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Spatie\Permission\Traits; |
4
|
|
|
|
5
|
|
|
use Spatie\Permission\Guard; |
6
|
|
|
use Illuminate\Support\Collection; |
7
|
|
|
use Illuminate\Database\Eloquent\Builder; |
8
|
|
|
use Spatie\Permission\PermissionRegistrar; |
9
|
|
|
use Spatie\Permission\Contracts\Permission; |
10
|
|
|
use Spatie\Permission\Exceptions\GuardDoesNotMatch; |
11
|
|
|
use Illuminate\Database\Eloquent\Relations\MorphToMany; |
12
|
|
|
|
13
|
|
|
trait HasPermissions |
14
|
|
|
{ |
15
|
|
View Code Duplication |
public static function bootHasPermissions() |
|
|
|
|
16
|
|
|
{ |
17
|
|
|
static::deleting(function ($model) { |
18
|
|
|
if (method_exists($model, 'isForceDeleting') && ! $model->isForceDeleting()) { |
19
|
|
|
return; |
20
|
|
|
} |
21
|
|
|
|
22
|
|
|
$model->permissions()->detach(); |
23
|
|
|
}); |
24
|
|
|
} |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* A model may have multiple direct permissions. |
28
|
|
|
*/ |
29
|
|
|
public function permissions(): MorphToMany |
30
|
|
|
{ |
31
|
|
|
return $this->morphToMany( |
|
|
|
|
32
|
|
|
config('permission.models.permission'), |
33
|
|
|
'model', |
34
|
|
|
config('permission.table_names.model_has_permissions'), |
35
|
|
|
'model_id', |
36
|
|
|
'permission_id' |
37
|
|
|
); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* Scope the model query to certain permissions only. |
42
|
|
|
* |
43
|
|
|
* @param \Illuminate\Database\Eloquent\Builder $query |
44
|
|
|
* @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
45
|
|
|
* |
46
|
|
|
* @return \Illuminate\Database\Eloquent\Builder |
47
|
|
|
*/ |
48
|
|
|
public function scopePermission(Builder $query, $permissions): Builder |
49
|
|
|
{ |
50
|
|
|
$permissions = $this->convertToPermissionModels($permissions); |
51
|
|
|
|
52
|
|
|
$rolesWithPermissions = array_unique(array_reduce($permissions, function ($result, $permission) { |
53
|
|
|
return array_merge($result, $permission->roles->all()); |
54
|
|
|
}, [])); |
55
|
|
|
|
56
|
|
|
return $query->where(function ($query) use ($permissions, $rolesWithPermissions) { |
57
|
|
|
$query->whereHas('permissions', function ($query) use ($permissions) { |
58
|
|
|
$query->where(function ($query) use ($permissions) { |
59
|
|
|
foreach ($permissions as $permission) { |
60
|
|
|
$query->orWhere(config('permission.table_names.permissions').'.id', $permission->id); |
61
|
|
|
} |
62
|
|
|
}); |
63
|
|
|
}); |
64
|
|
|
if (count($rolesWithPermissions) > 0) { |
65
|
|
|
$query->orWhereHas('roles', function ($query) use ($rolesWithPermissions) { |
66
|
|
|
$query->where(function ($query) use ($rolesWithPermissions) { |
67
|
|
|
foreach ($rolesWithPermissions as $role) { |
68
|
|
|
$query->orWhere(config('permission.table_names.roles').'.id', $role->id); |
69
|
|
|
} |
70
|
|
|
}); |
71
|
|
|
}); |
72
|
|
|
} |
73
|
|
|
}); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
78
|
|
|
* |
79
|
|
|
* @return array |
80
|
|
|
*/ |
81
|
|
|
protected function convertToPermissionModels($permissions): array |
82
|
|
|
{ |
83
|
|
|
if ($permissions instanceof Collection) { |
84
|
|
|
$permissions = $permissions->all(); |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
$permissions = array_wrap($permissions); |
88
|
|
|
|
89
|
|
|
return array_map(function ($permission) { |
90
|
|
|
if ($permission instanceof Permission) { |
91
|
|
|
return $permission; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
return app(Permission::class)->findByName($permission, $this->getDefaultGuardName()); |
95
|
|
|
}, $permissions); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Determine if the model may perform the given permission. |
100
|
|
|
* |
101
|
|
|
* @param string|\Spatie\Permission\Contracts\Permission $permission |
102
|
|
|
* @param string|null $guardName |
103
|
|
|
* |
104
|
|
|
* @return bool |
105
|
|
|
*/ |
106
|
|
|
public function hasPermissionTo($permission, $guardName = null): bool |
107
|
|
|
{ |
108
|
|
View Code Duplication |
if (! is_object($permission)) { |
|
|
|
|
109
|
|
|
$permission = app(Permission::class)->findByNameOrId($permission, $guardName ?? $this->getDefaultGuardName()); |
110
|
|
|
} |
111
|
|
|
|
112
|
|
|
if (! $permission) { |
113
|
|
|
return false; |
114
|
|
|
} |
115
|
|
|
|
116
|
|
|
return $this->hasDirectPermission($permission) || $this->hasPermissionViaRole($permission); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Determine if the model has any of the given permissions. |
121
|
|
|
* |
122
|
|
|
* @param array ...$permissions |
123
|
|
|
* |
124
|
|
|
* @return bool |
125
|
|
|
*/ |
126
|
|
View Code Duplication |
public function hasAnyPermission(...$permissions): bool |
|
|
|
|
127
|
|
|
{ |
128
|
|
|
if (is_array($permissions[0])) { |
129
|
|
|
$permissions = $permissions[0]; |
130
|
|
|
} |
131
|
|
|
|
132
|
|
|
foreach ($permissions as $permission) { |
133
|
|
|
if ($this->hasPermissionTo($permission)) { |
134
|
|
|
return true; |
135
|
|
|
} |
136
|
|
|
} |
137
|
|
|
|
138
|
|
|
return false; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Determine if the model has all of the given permissions. |
143
|
|
|
* |
144
|
|
|
* @param array ...$permissions |
145
|
|
|
* |
146
|
|
|
* @return bool |
147
|
|
|
*/ |
148
|
|
View Code Duplication |
public function hasAllPermissions(...$permissions): bool |
|
|
|
|
149
|
|
|
{ |
150
|
|
|
if (is_array($permissions[0])) { |
151
|
|
|
$permissions = $permissions[0]; |
152
|
|
|
} |
153
|
|
|
|
154
|
|
|
foreach ($permissions as $permission) { |
155
|
|
|
if (! $this->hasPermissionTo($permission)) { |
156
|
|
|
return false; |
157
|
|
|
} |
158
|
|
|
} |
159
|
|
|
|
160
|
|
|
return true; |
161
|
|
|
} |
162
|
|
|
|
163
|
|
|
/** |
164
|
|
|
* Determine if the model has, via roles, the given permission. |
165
|
|
|
* |
166
|
|
|
* @param \Spatie\Permission\Contracts\Permission $permission |
167
|
|
|
* |
168
|
|
|
* @return bool |
169
|
|
|
*/ |
170
|
|
|
protected function hasPermissionViaRole(Permission $permission): bool |
171
|
|
|
{ |
172
|
|
|
return $this->hasRole($permission->roles); |
|
|
|
|
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
/** |
176
|
|
|
* Determine if the model has the given permission. |
177
|
|
|
* |
178
|
|
|
* @param string|\Spatie\Permission\Contracts\Permission $permission |
179
|
|
|
* |
180
|
|
|
* @return bool |
181
|
|
|
*/ |
182
|
|
|
public function hasDirectPermission($permission): bool |
183
|
|
|
{ |
184
|
|
View Code Duplication |
if (! is_object($permission)) { |
|
|
|
|
185
|
|
|
$permission = app(Permission::class)->findByNameOrId($permission, $guardName ?? $this->getDefaultGuardName()); |
186
|
|
|
} |
187
|
|
|
|
188
|
|
|
if (! $permission) { |
189
|
|
|
return false; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
return $this->permissions->contains('id', $permission->id); |
|
|
|
|
193
|
|
|
} |
194
|
|
|
|
195
|
|
|
/** |
196
|
|
|
* Return all the permissions the model has via roles. |
197
|
|
|
*/ |
198
|
|
|
public function getPermissionsViaRoles(): Collection |
199
|
|
|
{ |
200
|
|
|
return $this->load('roles', 'roles.permissions') |
|
|
|
|
201
|
|
|
->roles->flatMap(function ($role) { |
202
|
|
|
return $role->permissions; |
203
|
|
|
})->sort()->values(); |
204
|
|
|
} |
205
|
|
|
|
206
|
|
|
/** |
207
|
|
|
* Return all the permissions the model has, both directly and via roles. |
208
|
|
|
*/ |
209
|
|
|
public function getAllPermissions(): Collection |
210
|
|
|
{ |
211
|
|
|
return $this->permissions |
212
|
|
|
->merge($this->getPermissionsViaRoles()) |
213
|
|
|
->sort() |
214
|
|
|
->values(); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
/** |
218
|
|
|
* Grant the given permission(s) to a role. |
219
|
|
|
* |
220
|
|
|
* @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
221
|
|
|
* |
222
|
|
|
* @return $this |
223
|
|
|
*/ |
224
|
|
View Code Duplication |
public function givePermissionTo(...$permissions) |
|
|
|
|
225
|
|
|
{ |
226
|
|
|
$permissions = collect($permissions) |
227
|
|
|
->flatten() |
228
|
|
|
->map(function ($permission) { |
229
|
|
|
return $this->getStoredPermission($permission); |
230
|
|
|
}) |
231
|
|
|
->filter(function ($permission) { |
232
|
|
|
return $permission instanceof Permission; |
233
|
|
|
}) |
234
|
|
|
->each(function ($permission) { |
235
|
|
|
$this->ensureModelSharesGuard($permission); |
236
|
|
|
}) |
237
|
|
|
->all(); |
238
|
|
|
|
239
|
|
|
$this->permissions()->saveMany($permissions); |
240
|
|
|
|
241
|
|
|
$this->forgetCachedPermissions(); |
242
|
|
|
|
243
|
|
|
return $this; |
244
|
|
|
} |
245
|
|
|
|
246
|
|
|
/** |
247
|
|
|
* Remove all current permissions and set the given ones. |
248
|
|
|
* |
249
|
|
|
* @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
250
|
|
|
* |
251
|
|
|
* @return $this |
252
|
|
|
*/ |
253
|
|
|
public function syncPermissions(...$permissions) |
254
|
|
|
{ |
255
|
|
|
$this->permissions()->detach(); |
256
|
|
|
|
257
|
|
|
return $this->givePermissionTo($permissions); |
258
|
|
|
} |
259
|
|
|
|
260
|
|
|
/** |
261
|
|
|
* Revoke the given permission. |
262
|
|
|
* |
263
|
|
|
* @param \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Permission[]|string|string[] $permission |
264
|
|
|
* |
265
|
|
|
* @return $this |
266
|
|
|
*/ |
267
|
|
|
public function revokePermissionTo($permission) |
268
|
|
|
{ |
269
|
|
|
$this->permissions()->detach($this->getStoredPermission($permission)); |
270
|
|
|
|
271
|
|
|
$this->forgetCachedPermissions(); |
272
|
|
|
|
273
|
|
|
return $this; |
274
|
|
|
} |
275
|
|
|
|
276
|
|
|
/** |
277
|
|
|
* @param string|array|\Spatie\Permission\Contracts\Permission|\Illuminate\Support\Collection $permissions |
278
|
|
|
* |
279
|
|
|
* @return \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Permission[]|\Illuminate\Support\Collection |
280
|
|
|
*/ |
281
|
|
|
protected function getStoredPermission($permissions) |
282
|
|
|
{ |
283
|
|
|
if (is_numeric($permissions)) { |
284
|
|
|
return app(Permission::class)->findById($permissions, $this->getDefaultGuardName()); |
285
|
|
|
} |
286
|
|
|
|
287
|
|
|
if (is_string($permissions)) { |
288
|
|
|
return app(Permission::class)->findByName($permissions, $this->getDefaultGuardName()); |
289
|
|
|
} |
290
|
|
|
|
291
|
|
|
if (is_array($permissions)) { |
292
|
|
|
return app(Permission::class) |
293
|
|
|
->whereIn('name', $permissions) |
294
|
|
|
->whereIn('guard_name', $this->getGuardNames()) |
295
|
|
|
->get(); |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
return $permissions; |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
/** |
302
|
|
|
* @param \Spatie\Permission\Contracts\Permission|\Spatie\Permission\Contracts\Role $roleOrPermission |
303
|
|
|
* |
304
|
|
|
* @throws \Spatie\Permission\Exceptions\GuardDoesNotMatch |
305
|
|
|
*/ |
306
|
|
|
protected function ensureModelSharesGuard($roleOrPermission) |
307
|
|
|
{ |
308
|
|
|
if (! $this->getGuardNames()->contains($roleOrPermission->guard_name)) { |
309
|
|
|
throw GuardDoesNotMatch::create($roleOrPermission->guard_name, $this->getGuardNames()); |
310
|
|
|
} |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
protected function getGuardNames(): Collection |
314
|
|
|
{ |
315
|
|
|
return Guard::getNames($this); |
316
|
|
|
} |
317
|
|
|
|
318
|
|
|
protected function getDefaultGuardName(): string |
319
|
|
|
{ |
320
|
|
|
return Guard::getDefaultName($this); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Forget the cached permissions. |
325
|
|
|
*/ |
326
|
|
|
public function forgetCachedPermissions() |
327
|
|
|
{ |
328
|
|
|
app(PermissionRegistrar::class)->forgetCachedPermissions(); |
329
|
|
|
} |
330
|
|
|
} |
331
|
|
|
|
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.