Completed
Pull Request — master (#27)
by ARCANEDEV
04:07
created

User::detachRole()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 10
ccs 0
cts 6
cp 0
rs 9.4285
cc 1
eloc 6
nc 1
nop 2
crap 2
1
<?php namespace Arcanedev\LaravelAuth\Models;
2
3
use Arcanedev\LaravelAuth\Events\Users\ActivatedUser;
4
use Arcanedev\LaravelAuth\Events\Users\ActivatingUser;
5
use Arcanedev\LaravelAuth\Events\Users\AttachedRoleToUser;
6
use Arcanedev\LaravelAuth\Events\Users\AttachingRoleToUser;
7
use Arcanedev\LaravelAuth\Events\Users\CreatedUser;
8
use Arcanedev\LaravelAuth\Events\Users\CreatingUser;
9
use Arcanedev\LaravelAuth\Events\Users\DeactivatedUser;
10
use Arcanedev\LaravelAuth\Events\Users\DeactivatingUser;
11
use Arcanedev\LaravelAuth\Events\Users\DeletedUser;
12
use Arcanedev\LaravelAuth\Events\Users\DeletingUser;
13
use Arcanedev\LaravelAuth\Events\Users\DetachedRoleFromUser;
14
use Arcanedev\LaravelAuth\Events\Users\DetachedRolesFromUser;
15
use Arcanedev\LaravelAuth\Events\Users\DetachingRoleFromUser;
16
use Arcanedev\LaravelAuth\Events\Users\DetachingRolesFromUser;
17
use Arcanedev\LaravelAuth\Events\Users\RestoredUser;
18
use Arcanedev\LaravelAuth\Events\Users\RestoringUser;
19
use Arcanedev\LaravelAuth\Events\Users\SavedUser;
20
use Arcanedev\LaravelAuth\Events\Users\SavingUser;
21
use Arcanedev\LaravelAuth\Events\Users\SyncedUserWithRoles;
22
use Arcanedev\LaravelAuth\Events\Users\SyncingUserWithRoles;
23
use Arcanedev\LaravelAuth\Events\Users\UpdatedUser;
24
use Arcanedev\LaravelAuth\Events\Users\UpdatingUser;
25
use Arcanedev\LaravelAuth\Exceptions\UserConfirmationException;
26
use Arcanedev\LaravelAuth\Models\Traits\Activatable;
27
use Arcanedev\LaravelAuth\Models\Traits\Roleable;
28
use Arcanedev\LaravelAuth\Services\SocialAuthenticator;
29
use Arcanedev\LaravelAuth\Services\UserConfirmator;
30
use Arcanesoft\Contracts\Auth\Models\Permission as PermissionContract;
31
use Arcanesoft\Contracts\Auth\Models\Role as RoleContract;
32
use Arcanesoft\Contracts\Auth\Models\User as UserContract;
33
use Carbon\Carbon;
34
use Illuminate\Auth\Authenticatable;
35
use Illuminate\Auth\Passwords\CanResetPassword;
36
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
37
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
38
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
39
use Illuminate\Database\Eloquent\SoftDeletes;
40
use Illuminate\Foundation\Auth\Access\Authorizable;
41
use Illuminate\Support\Collection;
42
use Illuminate\Support\Str;
43
44
/**
45
 * Class     User
46
 *
47
 * @package  Arcanedev\LaravelAuth\Models
48
 * @author   ARCANEDEV <[email protected]>
49
 *
50
 * @property  int                                       id
51
 * @property  string                                    username
52
 * @property  string                                    first_name
53
 * @property  string                                    last_name
54
 * @property  string                                    full_name
55
 * @property  string                                    email
56
 * @property  string                                    password
57
 * @property  string                                    remember_token
58
 * @property  bool                                      is_admin
59
 * @property  bool                                      is_active
60
 * @property  bool                                      is_confirmed       (Optional)
61
 * @property  string                                    confirmation_code  (Optional)
62
 * @property  \Carbon\Carbon                            confirmed_at       (Optional)
63
 * @property  \Carbon\Carbon                            last_activity
64
 * @property  \Carbon\Carbon                            created_at
65
 * @property  \Carbon\Carbon                            updated_at
66
 * @property  \Carbon\Carbon                            deleted_at
67
 *
68
 * @property  \Illuminate\Database\Eloquent\Collection       roles
69
 * @property  \Illuminate\Support\Collection                 permissions
70
 * @property  \Arcanedev\LaravelAuth\Models\Pivots\RoleUser  pivot
71
 *
72
 * @method    \Illuminate\Database\Eloquent\Builder  unconfirmed(string $code)
73
 * @method    \Illuminate\Database\Eloquent\Builder  lastActive(int $minutes = null)
74
 */
75
class User
76
    extends AbstractModel
77
    implements UserContract, AuthenticatableContract, AuthorizableContract, CanResetPasswordContract
78
{
79
    /* -----------------------------------------------------------------
80
     |  Traits
81
     | -----------------------------------------------------------------
82
     */
83
84
    use Roleable,
85
        Authenticatable,
86
        Authorizable,
87
        CanResetPassword,
88
        Activatable,
89
        SoftDeletes;
90
91
    /* -----------------------------------------------------------------
92
     |  Properties
93
     | -----------------------------------------------------------------
94
95
     */
96
    /**
97
     * The attributes that are mass assignable.
98
     *
99
     * @var array
100
     */
101
    protected $fillable = [
102
        'username',
103
        'first_name',
104
        'last_name',
105
        'email',
106
        'password',
107
        'confirmation_code',
108
    ];
109
110
    /**
111
     * The attributes excluded from the model's JSON form.
112
     *
113
     * @var array
114
     */
115
    protected $hidden   = [
116
        'password',
117
        'remember_token',
118
        'confirmation_code',
119
    ];
120
121
    /**
122
     * The attributes that should be casted to native types.
123
     *
124
     * @var array
125
     */
126
    protected $casts = [
127
        'id'           => 'id',
128
        'is_admin'     => 'boolean',
129
        'is_active'    => 'boolean',
130
        'is_confirmed' => 'boolean',
131
    ];
132
133
    /**
134
     * The attributes that should be mutated to dates.
135
     *
136
     * @var array
137
     */
138
    protected $dates = [
139
        'confirmed_at',
140
        'last_activity',
141
        'deleted_at',
142
    ];
143
144
    /**
145
     * The event map for the model.
146
     *
147
     * @var array
148
     */
149
    protected $dispatchesEvents = [
150
        'creating'  => CreatingUser::class,
151
        'created'   => CreatedUser::class,
152
        'updating'  => UpdatingUser::class,
153
        'updated'   => UpdatedUser::class,
154
        'saving'    => SavingUser::class,
155
        'saved'     => SavedUser::class,
156
        'deleting'  => DeletingUser::class,
157
        'deleted'   => DeletedUser::class,
158
        'restoring' => RestoringUser::class,
159
        'restored'  => RestoredUser::class,
160
    ];
161
162
    /* -----------------------------------------------------------------
163
     |  Constructor
164
     | -----------------------------------------------------------------
165
     */
166
167
    /**
168
     * Create a new Eloquent model instance.
169
     *
170
     * @param  array  $attributes
171
     */
172 68
    public function __construct(array $attributes = [])
173
    {
174 68
        parent::__construct($attributes);
175
176 68
        $this->setupModel();
177 68
    }
178
179
    /**
180
     * Setup the model.
181
     */
182 68
    protected function setupModel()
183
    {
184 68
        $this->setTable(config('laravel-auth.users.table', 'users'));
185
186 68
        if (SocialAuthenticator::isEnabled()) {
187 68
            $this->hidden   = array_merge($this->hidden, ['social_provider_id']);
188 68
            $this->fillable = array_merge($this->fillable, ['social_provider', 'social_provider_id']);
189
        }
190 68
    }
191
192
    /* -----------------------------------------------------------------
193
     |  Relationships
194
     | -----------------------------------------------------------------
195
     */
196
197
    /**
198
     * User belongs to many roles.
199
     *
200
     * @return \Illuminate\Database\Eloquent\Relations\BelongsToMany
201
     */
202 28
    public function roles()
203
    {
204 28
        return $this->belongsToMany(
205 28
                config('laravel-auth.roles.model', Role::class),
206 28
                $this->getPrefix().config('laravel-auth.role-user.table', 'role_user')
207
            )
208 28
            ->using(Pivots\RoleUser::class)
209 28
            ->withTimestamps();
210
    }
211
212
    /**
213
     * Get all user permissions.
214
     *
215
     * @return \Illuminate\Support\Collection
216
     */
217 6
    public function getPermissionsAttribute()
218
    {
219 6
        return $this->active_roles
220 6
            ->pluck('permissions')
221 6
            ->flatten()
222 6
            ->unique(function (PermissionContract $permission) {
223 6
                return $permission->getKey();
224 6
            });
225
    }
226
227
    /* -----------------------------------------------------------------
228
     |  Scopes
229
     | -----------------------------------------------------------------
230
     */
231
232
    /**
233
     * Scope unconfirmed users by code.
234
     *
235
     * @param  \Illuminate\Database\Eloquent\Builder  $query
236
     * @param  string                                 $code
237
     *
238
     * @return \Illuminate\Database\Eloquent\Builder
239
     */
240 4
    public function scopeUnconfirmed($query, $code)
241
    {
242 4
        return $query->where('is_confirmed', false)
243 4
                     ->where('confirmation_code', $code)
244 4
                     ->whereNull('confirmed_at');
245
    }
246
247
    /**
248
     * Scope last active users.
249
     *
250
     * @param  \Illuminate\Database\Eloquent\Builder  $query
251
     * @param  int|null                               $minutes
252
     *
253
     * @return \Illuminate\Database\Eloquent\Builder
254
     */
255 2
    public function scopeLastActive($query, $minutes = null)
256
    {
257 2
        $date = Carbon::now()->subMinutes(
258 2
            $minutes ?: config('laravel_auth.track-activity.minutes', 5)
259
        );
260
261 2
        return $query->where('last_activity', '>=', $date->toDateTimeString());
262
    }
263
264
    /* -----------------------------------------------------------------
265
     |  Getters & Setters
266
     | -----------------------------------------------------------------
267
     */
268
269
    /**
270
     * Set the `email` attribute.
271
     *
272
     * @param  string  $email
273
     */
274 54
    public function setEmailAttribute($email)
275
    {
276 54
        $this->attributes['email'] = Str::lower($email);
277 54
    }
278
279
    /**
280
     * Set the `username` attribute.
281
     *
282
     * @param  string  $username
283
     */
284 52
    public function setUsernameAttribute($username)
285
    {
286 52
        $this->attributes['username'] = Str::slug($username, config('laravel-auth.users.slug-separator', '.'));
287 52
    }
288
289
    /**
290
     * Set the `first_name` attribute.
291
     *
292
     * @param  string  $firstName
293
     */
294 54
    public function setFirstNameAttribute($firstName)
295
    {
296 54
        $this->attributes['first_name'] = Str::title(Str::lower($firstName));
297 54
    }
298
299
    /**
300
     * Set the `last_name` attribute.
301
     *
302
     * @param  string  $lastName
303
     */
304 54
    public function setLastNameAttribute($lastName)
305
    {
306 54
        $this->attributes['last_name'] = Str::upper($lastName);
307 54
    }
308
309
    /**
310
     * Get the `full_name` attribute.
311
     *
312
     * @return string
313
     */
314 4
    public function getFullNameAttribute()
315
    {
316 4
        return $this->first_name.' '.$this->last_name;
317
    }
318
319
    /**
320
     * Set the `password` attribute.
321
     *
322
     * @param  string  $password
323
     */
324 52
    public function setPasswordAttribute($password)
325
    {
326 52
        $this->attributes['password'] = bcrypt($password);
327 52
    }
328
329
    /* -----------------------------------------------------------------
330
     |  Main Methods
331
     | -----------------------------------------------------------------
332
     */
333
334
    /**
335
     * Activate the model.
336
     *
337
     * @param  bool  $save
338
     *
339
     * @return bool
340
     */
341 2
    public function activate($save = true)
342
    {
343 2
        event(new ActivatingUser($this));
344 2
        $result = $this->switchActive(true, $save);
345 2
        event(new ActivatedUser($this));
346
347 2
        return $result;
348
    }
349
350
    /**
351
     * Deactivate the model.
352
     *
353
     * @param  bool  $save
354
     *
355
     * @return bool
356
     */
357 2
    public function deactivate($save = true)
358
    {
359 2
        event(new DeactivatingUser($this));
360 2
        $result = $this->switchActive(false, $save);
361 2
        event(new DeactivatedUser($this));
362
363 2
        return $result;
364
    }
365
366
    /**
367
     * Attach a role to a user.
368
     *
369
     * @param  \Arcanesoft\Contracts\Auth\Models\Role|int  $role
370
     * @param  bool                                        $reload
371
     */
372 22
    public function attachRole($role, $reload = true)
373
    {
374 22
        if ($this->hasRole($role)) return;
375
376 22
        event(new AttachingRoleToUser($this, $role));
377 22
        $this->roles()->attach($role);
378 22
        event(new AttachedRoleToUser($this, $role));
379
380 22
        $this->loadRoles($reload);
381 22
    }
382
383
    /**
384
     * Sync the roles by its slugs.
385
     *
386
     * @param  array|\Illuminate\Support\Collection  $slugs
387
     * @param  bool                                  $reload
388
     *
389
     * @return array
390
     */
391 2
    public function syncRoles($slugs, $reload = true)
392
    {
393
        /** @var  \Illuminate\Database\Eloquent\Collection  $roles */
394 2
        $roles = app(RoleContract::class)->whereIn('slug', $slugs)->get();
395
396 2
        event(new SyncingUserWithRoles($this, $roles));
397 2
        $synced = $this->roles()->sync($roles->pluck('id'));
398 2
        event(new SyncedUserWithRoles($this, $roles, $synced));
399
400 2
        $this->loadRoles($reload);
401
402 2
        return $synced;
403
    }
404
405
    /**
406
     * Detach a role from a user.
407
     *
408
     * @param  \Arcanesoft\Contracts\Auth\Models\Role|int  $role
409
     * @param  bool                                        $reload
410
     *
411
     * @return int
412
     */
413
    public function detachRole($role, $reload = true)
414
    {
415
        event(new DetachingRoleFromUser($this, $role));
416
        $results = $this->roles()->detach($role);
417
        event(new DetachedRoleFromUser($this, $role, $results));
418
419
        $this->loadRoles($reload);
420
421
        return $results;
422
    }
423
424
    /**
425
     * Detach all roles from a user.
426
     *
427
     * @param  bool  $reload
428
     *
429
     * @return int
430
     */
431 2
    public function detachAllRoles($reload = true)
432
    {
433 2
        event(new DetachingRolesFromUser($this));
434 2
        $results = $this->roles()->detach();
435 2
        event(new DetachedRolesFromUser($this, $results));
436
437 2
        $this->loadRoles($reload);
438
439 2
        return $results;
440
    }
441
442
    /**
443
     * Confirm the unconfirmed user account by confirmation code.
444
     *
445
     * @param  string  $code
446
     *
447
     * @return \Arcanesoft\Contracts\Auth\Models\User
448
     *
449
     * @throws \Arcanedev\LaravelAuth\Exceptions\UserConfirmationException
450
     */
451 4
    public function findUnconfirmed($code)
452
    {
453
        /** @var  \Arcanesoft\Contracts\Auth\Models\User|null  $unconfirmed */
454 4
        $unconfirmed = static::unconfirmed($code)->first();
455
456 4
        if ( ! $unconfirmed instanceof self)
457 2
            throw (new UserConfirmationException)->setModel(static::class);
458
459 2
        return $unconfirmed;
460
    }
461
462
    /**
463
     * Confirm the new user account.
464
     *
465
     * @param  \Arcanesoft\Contracts\Auth\Models\User|string  $code
466
     *
467
     * @return \Arcanesoft\Contracts\Auth\Models\User
468
     */
469
    public function confirm($code)
470
    {
471
        if ($code instanceof self)
472
            $code = $code->confirmation_code;
473
474
        return (new UserConfirmator)->confirm(
475
            $this->findUnconfirmed($code)
476
        );
477
    }
478
479
    /**
480
     * Update the user's last activity.
481
     *
482
     * @param  bool  $save
483
     */
484 2
    public function updateLastActivity($save = true)
485
    {
486 2
        $this->forceFill(['last_activity' => Carbon::now()]);
487
488 2
        if ($save) $this->save();
489 2
    }
490
491
    /* -----------------------------------------------------------------
492
     |  Permission Check Methods
493
     | -----------------------------------------------------------------
494
     */
495
    /**
496
     * Check if the user has a permission.
497
     *
498
     * @param  string  $slug
499
     *
500
     * @return bool
501
     */
502
    public function may($slug)
503
    {
504 6
        return ! $this->permissions->filter(function (PermissionContract $permission) use ($slug) {
505 6
            return $permission->hasSlug($slug);
506 6
        })->isEmpty();
507
    }
508
509
    /**
510
     * Check if the user has at least one permission.
511
     *
512
     * @param  \Illuminate\Support\Collection|array  $permissions
513
     * @param  \Illuminate\Support\Collection        &$failed
514
     *
515
     * @return bool
516
     */
517 4
    public function mayOne($permissions, &$failed = null)
518
    {
519 4
        $permissions = is_array($permissions) ? collect($permissions) : $permissions;
520
521 4
        $failed = $permissions->reject(function ($permission) {
522 4
            return $this->may($permission);
523 4
        })->values();
524
525 4
        return $permissions->count() !== $failed->count();
526
    }
527
528
    /**
529
     * Check if the user has all permissions.
530
     *
531
     * @param  \Illuminate\Support\Collection|array  $permissions
532
     * @param  \Illuminate\Support\Collection        &$failed
533
     *
534
     * @return bool
535
     */
536 2
    public function mayAll($permissions, &$failed = null)
537
    {
538 2
        $this->mayOne($permissions, $failed);
539
540 2
        return $failed instanceof Collection ? $failed->isEmpty() : false;
541
    }
542
543
    /* -----------------------------------------------------------------
544
     |  Check Methods
545
     | -----------------------------------------------------------------
546
     */
547
548
    /**
549
     * Check if user is an administrator.
550
     *
551
     * @return bool
552
     */
553 10
    public function isAdmin()
554
    {
555 10
        return $this->is_admin;
556
    }
557
558
    /**
559
     * Check if user is a moderator.
560
     *
561
     * @return bool
562
     */
563 4
    public function isModerator()
564
    {
565
        // Override this method to give more privileges than members.
566 4
        return false;
567
    }
568
569
    /**
570
     * Check if user is a member.
571
     *
572
     * @return bool
573
     */
574 6
    public function isMember()
575
    {
576 6
        return ! $this->isAdmin();
577
    }
578
579
    /**
580
     * Check if user has a confirmed account.
581
     *
582
     * @return bool
583
     */
584 2
    public function isConfirmed()
585
    {
586 2
        return $this->is_confirmed;
587
    }
588
589
    /**
590
     * Check if user can be impersonated.
591
     *
592
     * @return bool
593
     */
594 2
    public function canBeImpersonated()
595
    {
596 2
        return $this->isMember();
597
    }
598
}
599