Completed
Push — master ( 95222a...95222a )
by ARCANEDEV
12:27 queued 09:59
created

User   B

Complexity

Total Complexity 35

Size/Duplication

Total Lines 472
Duplicated Lines 0 %

Coupling/Cohesion

Components 7
Dependencies 17

Test Coverage

Coverage 98.23%

Importance

Changes 0
Metric Value
wmc 35
lcom 7
cbo 17
dl 0
loc 472
ccs 111
cts 113
cp 0.9823
rs 7.0714
c 0
b 0
f 0

27 Methods

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