Passed
Push — master ( c3754f...384d2b )
by Stephen
01:41 queued 11s
created

User   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 519
Duplicated Lines 0 %

Importance

Changes 19
Bugs 3 Features 0
Metric Value
wmc 57
eloc 99
c 19
b 3
f 0
dl 0
loc 519
rs 5.04

41 Methods

Rating   Name   Duplication   Size   Complexity  
A getRateFormattedAttribute() 0 3 2
A isEmployee() 0 3 1
A getListNameAttribute() 0 3 1
A getLastNameAttribute() 0 3 1
A getPhoneWorkLinkAttribute() 0 3 2
A setFirstNameAttribute() 0 4 2
A getTextareaAttribute() 0 3 1
A boot() 0 7 1
A notificationSubscriptions() 0 3 1
A getPhoneMobileLinkAttribute() 0 3 2
A getNameFullAttribute() 0 8 2
A newEloquentBuilder() 0 3 1
A getCityAttribute() 0 3 1
A isNicknamePreferred() 0 3 1
A setMiddleNameAttribute() 0 8 3
A getAddress1Attribute() 0 3 1
A getInitialsAttribute() 0 9 1
A isAdmin() 0 4 2
A getCityStateAttribute() 0 3 1
A getFirstNameAttribute() 0 3 1
A getNameSuffixAttribute() 0 3 2
A getNameAttribute() 0 7 3
A getEmailLinkAttribute() 0 3 2
A getEmailFooterAttribute() 0 9 3
A setLastNameAttribute() 0 4 2
A role() 0 3 1
A team() 0 3 1
A isRoleId() 0 3 1
A query() 0 3 1
A getUploadDirectory() 0 3 1
A setPasswordAttribute() 0 4 2
A getStateAttribute() 0 3 1
A isWebDeveloper() 0 3 1
A getZipAttribute() 0 3 1
A getNameLinkAttribute() 0 3 1
A address() 0 3 1
A getAddress2Attribute() 0 3 1
A isActive() 0 3 1
A isContractor() 0 3 1
A isRole() 0 3 1
A newFactory() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like User often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use User, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Sfneal\Users\Models;
4
5
use Database\Factories\UserFactory;
6
use Illuminate\Database\Eloquent\Builder;
7
use Illuminate\Database\Eloquent\Factories\HasFactory;
8
use Illuminate\Database\Eloquent\Relations\BelongsTo;
9
use Illuminate\Database\Eloquent\Relations\HasMany;
10
use Illuminate\Database\Eloquent\Relations\HasOne;
11
use Illuminate\Database\Eloquent\Relations\MorphOne;
12
use Sfneal\Address\Models\Address;
13
use Sfneal\Casts\NewlineCast;
14
use Sfneal\Currency\Currency;
15
use Sfneal\Helpers\Strings\StringHelpers;
16
use Sfneal\Models\AuthModel;
17
use Sfneal\Scopes\OrderScope;
18
use Sfneal\Users\Builders\UserBuilder;
19
use Sfneal\Users\Scopes\UserActiveScope;
20
use Sfneal\Users\Services\OrganizationService;
21
use Vkovic\LaravelCustomCasts\HasCustomCasts;
22
23
class User extends AuthModel
24
{
25
    // todo: refactor status to use Status model?
26
    use HasCustomCasts;
27
    use HasFactory;
28
29
    /**
30
     * The "booting" method of the model.
31
     *
32
     * @return void
33
     */
34
    public static function boot()
35
    {
36
        parent::boot();
37
38
        // Global scopes
39
        static::addGlobalScope(new UserActiveScope());
40
        static::addGlobalScope(new OrderScope('last_name', 'asc'));
41
    }
42
43
    protected $dates = ['deleted_at'];
44
    protected $table = 'user';
45
    protected $primaryKey = 'id';
46
47
    /**
48
     * The attributes that are mass assignable.
49
     *
50
     * @var array
51
     */
52
    protected $fillable = [
53
        'role_id',
54
        'first_name',
55
        'middle_name',
56
        'last_name',
57
        'nickname',
58
        'nickname_preferred',
59
        'title',
60
        'suffix',
61
        'email',
62
        'phone_work',
63
        'phone_mobile',
64
        'fax',
65
        'website',
66
        'bio',
67
        'username',
68
        'password',
69
        'status',
70
        'rate',
71
    ];
72
73
    /**
74
     * The attributes that should be hidden from arrays.
75
     *
76
     * @var array
77
     */
78
    protected $hidden = [
79
        'password',
80
        'remember_token',
81
    ];
82
83
    /**
84
     * The attributes that should type cast.
85
     *
86
     * @var array
87
     */
88
    protected $casts = [
89
        'role_id' => 'int',
90
        'nickname_preferred' => 'int',
91
        'bio' => NewlineCast::class,
92
        'status' => 'int',
93
        'rate' => 'int',
94
    ];
95
96
    /**
97
     * @var array Attributes that should be appended to collections
98
     */
99
    protected $appends = [
100
        'name',
101
    ];
102
103
    /**
104
     * Create a new factory instance for the model.
105
     *
106
     * @return UserFactory
107
     */
108
    protected static function newFactory(): UserFactory
109
    {
110
        return new UserFactory();
111
    }
112
113
    /**
114
     * Query Builder.
115
     * @param $query
116
     * @return UserBuilder
117
     */
118
    public function newEloquentBuilder($query)
119
    {
120
        return new UserBuilder($query);
121
    }
122
123
    /**
124
     * Custom User query Builder.
125
     *
126
     * @return UserBuilder|Builder
127
     */
128
    public static function query(): UserBuilder
129
    {
130
        return parent::query();
131
    }
132
133
    /**
134
     * User's 'role' relationship.
135
     *
136
     * @return BelongsTo
137
     */
138
    public function role()
139
    {
140
        return $this->belongsTo(Role::class, 'role_id', 'role_id');
141
    }
142
143
    /**
144
     * User's Notification Subscriptions.
145
     *
146
     * @return HasMany
147
     */
148
    public function notificationSubscriptions()
149
    {
150
        return $this->hasMany(UserNotification::class, 'user_id', 'id');
151
    }
152
153
    /**
154
     * User's 'team' relationship - indicates user is a member of the public team.
155
     *
156
     * @return HasOne
157
     */
158
    public function team()
159
    {
160
        return $this->hasOne(Team::class, 'user_id', 'id');
161
    }
162
163
    /**
164
     * User's address.
165
     *
166
     * @return MorphOne
167
     */
168
    public function address()
169
    {
170
        return $this->morphOne(Address::class, 'addressable');
171
    }
172
173
    /**
174
     * Determine if a User has a particular 'role_id'.
175
     *
176
     * @param int $role_id
177
     * @return bool
178
     */
179
    public function isRoleId(int $role_id): bool
180
    {
181
        return $this->role_id == $role_id;
0 ignored issues
show
Bug introduced by
The property role_id does not exist on Sfneal\Users\Models\User. Did you mean role?
Loading history...
182
    }
183
184
    /**
185
     * Determine if a User has a particular 'role name'.
186
     *
187
     * @param string $role
188
     * @return bool
189
     */
190
    public function isRole(string $role): bool
191
    {
192
        return strtolower($this->role->name) == strtolower($role);
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on Sfneal\Users\Models\Role. 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...
193
    }
194
195
    /**
196
     * Determine if a User has an 'admin' role.
197
     *
198
     * @return bool
199
     */
200
    public function isAdmin(): bool
201
    {
202
        // User is considered an 'admin' if user is a 'web developer'
203
        return $this->isRoleId(3) || $this->isRoleId(4);
204
    }
205
206
    /**
207
     * Determine if a User has a 'web developer' role.
208
     *
209
     * @return bool
210
     */
211
    public function isWebDeveloper(): bool
212
    {
213
        return $this->isRoleId(4);
214
    }
215
216
    /**
217
     * Determine if a User has an 'employee' role.
218
     *
219
     * @return bool
220
     */
221
    public function isEmployee(): bool
222
    {
223
        return $this->isRoleId(1);
224
    }
225
226
    /**
227
     * Determine if a User has an 'contractor' role.
228
     *
229
     * @return bool
230
     */
231
    public function isContractor(): bool
232
    {
233
        return $this->isRoleId(2);
234
    }
235
236
    /**
237
     * Determine if a User is 'active'.
238
     *
239
     * @return bool
240
     */
241
    public function isActive(): bool
242
    {
243
        return $this->status == 1;
0 ignored issues
show
Bug introduced by
The property status does not seem to exist on Sfneal\Users\Models\User. 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...
244
    }
245
246
    /**
247
     * Determine if a User's $nickname is preferred over their $first_name.
248
     *
249
     * @return bool
250
     */
251
    public function isNicknamePreferred(): bool
252
    {
253
        return $this->nickname_preferred == 1;
0 ignored issues
show
Bug introduced by
The property nickname_preferred does not seem to exist on Sfneal\Users\Models\User. 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...
254
    }
255
256
    /**
257
     * Retrieve a User's initials.
258
     *
259
     * @return string
260
     */
261
    public function getInitialsAttribute()
262
    {
263
        return StringHelpers::implodeFiltered('', collect([
264
            $this->first_name,
265
            $this->middle_name,
0 ignored issues
show
Bug introduced by
The property middle_name does not seem to exist on Sfneal\Users\Models\User. 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...
266
            $this->last_name,
267
        ])->map(function ($name) {
268
            return substr($name, 0, 1);
269
        })->toArray());
270
    }
271
272
    /**
273
     * Get the AWS S3 file upload directory for an Inquiry model by retrieving the table name and primary key.
274
     *
275
     * @param string $base_dir
276
     * @return string
277
     */
278
    public function getUploadDirectory($base_dir = 'images'): string
279
    {
280
        return $base_dir.'/'.str_replace('_', '-', $this->getTable()).'/'.$this->getKey();
281
    }
282
283
    /**
284
     * Get the 'city_state' attribute.
285
     *
286
     * @return string
287
     */
288
    public function getCityStateAttribute()
289
    {
290
        return $this->address->city_state ?? null;
291
    }
292
293
    /**
294
     * Set the 'password' attribute.
295
     *
296
     * @param $value
297
     */
298
    public function setPasswordAttribute($value)
299
    {
300
        if (! empty($value)) {
301
            $this->attributes['password'] = bcrypt($value);
302
        }
303
    }
304
305
    /**
306
     * Mutate the 'middle_name' attribute.
307
     *
308
     * @param string|null $value
309
     */
310
    public function setMiddleNameAttribute(string $value = null)
311
    {
312
        if (! is_null($value)) {
313
            // Remove leading & trailing whitespace
314
            $middle_name = trim($value);
315
316
            // Append '.' to the middle name if's a single letter
317
            $this->attributes['middle_name'] = strlen($middle_name) == 1 ? "{$middle_name}." : $middle_name;
318
        }
319
    }
320
321
    /**
322
     * Mutate the 'first_name' attribute.
323
     *
324
     * @param string|null $value
325
     */
326
    public function setFirstNameAttribute(string $value = null)
327
    {
328
        if (! is_null($value)) {
329
            $this->attributes['first_name'] = trim($value);
330
        }
331
    }
332
333
    /**
334
     * Mutate the 'last_name' attribute.
335
     *
336
     * @param string|null $value
337
     */
338
    public function setLastNameAttribute(string $value = null)
339
    {
340
        if (! is_null($value)) {
341
            $this->attributes['last_name'] = trim($value);
342
        }
343
    }
344
345
    /**
346
     * Access the 'first_name' attribute.
347
     *
348
     * @param string|null $value
349
     * @return string
350
     */
351
    public function getFirstNameAttribute(string $value = null): string
352
    {
353
        return trim($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

353
        return trim(/** @scrutinizer ignore-type */ $value);
Loading history...
354
    }
355
356
    /**
357
     * Access the 'last_name' attribute.
358
     *
359
     * @param string|null $value
360
     * @return string
361
     */
362
    public function getLastNameAttribute(string $value = null): string
363
    {
364
        return trim($value);
0 ignored issues
show
Bug introduced by
It seems like $value can also be of type null; however, parameter $string of trim() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

364
        return trim(/** @scrutinizer ignore-type */ $value);
Loading history...
365
    }
366
367
    /**
368
     * Retrieve the User's name (first & last).
369
     *
370
     * @return string
371
     */
372
    public function getNameAttribute(): string
373
    {
374
        // Use nickname instead of first if it is set & preferred
375
        $first = (isset($this->nickname) && $this->isNicknamePreferred()) ? $this->nickname : $this->first_name;
0 ignored issues
show
Bug introduced by
The property nickname does not seem to exist on Sfneal\Users\Models\User. 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...
376
377
        // Return concatenated name
378
        return "{$first} {$this->last_name}";
379
    }
380
381
    /**
382
     * Retrieve the User's full name with middle initial.
383
     *
384
     * @return string
385
     */
386
    public function getNameFullAttribute(): string
387
    {
388
        $name = $this->first_name;
389
        if ($this->middle_name) {
0 ignored issues
show
Bug introduced by
The property middle_name does not seem to exist on Sfneal\Users\Models\User. 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...
390
            $name .= ' '.$this->middle_name;
391
        }
392
393
        return "{$name} {$this->last_name}";
394
    }
395
396
    /**
397
     * Retrieve the User's name with their suffix.
398
     *
399
     * @return string
400
     */
401
    public function getNameSuffixAttribute(): string
402
    {
403
        return $this->name_full.($this->suffix ? ", {$this->suffix}" : '');
0 ignored issues
show
Bug introduced by
The property suffix does not seem to exist on Sfneal\Users\Models\User. 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...
404
    }
405
406
    /**
407
     * Get the 'list_name' attribute.
408
     *
409
     * @return string
410
     */
411
    public function getListNameAttribute()
412
    {
413
        return implode(', ', array_reverse(explode(' ', $this->name)));
414
    }
415
416
    /**
417
     * Get the 'name_link' attribute that returns a url to the User's team.show page.
418
     *
419
     * @return string
420
     */
421
    public function getNameLinkAttribute()
422
    {
423
        return '<a href="'.route('user.show', ['user'=>$this->id]).'">'.$this->name.'</a>';
424
    }
425
426
    // todo: add address accessor method to a sfneal/address trait
427
428
    /**
429
     * Retrieve the User's 'address1' attribute.
430
     *
431
     * @return mixed
432
     */
433
    public function getAddress1Attribute()
434
    {
435
        return $this->address->address_1 ?? null;
0 ignored issues
show
Bug introduced by
The property address_1 does not exist on Sfneal\Address\Models\Address. Did you mean addressable?
Loading history...
436
    }
437
438
    /**
439
     * Retrieve the User's 'address2' attribute.
440
     *
441
     * @return mixed
442
     */
443
    public function getAddress2Attribute()
444
    {
445
        return $this->address->address_2 ?? null;
0 ignored issues
show
Bug introduced by
The property address_2 does not exist on Sfneal\Address\Models\Address. Did you mean addressable?
Loading history...
446
    }
447
448
    /**
449
     * Retrieve the User's 'city' attribute.
450
     *
451
     * @return mixed
452
     */
453
    public function getCityAttribute()
454
    {
455
        return $this->address->city ?? null;
0 ignored issues
show
Bug introduced by
The property city does not seem to exist on Sfneal\Address\Models\Address. 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...
456
    }
457
458
    /**
459
     * Retrieve the User's 'state' attribute.
460
     *
461
     * @return mixed
462
     */
463
    public function getStateAttribute()
464
    {
465
        return $this->address->state ?? null;
0 ignored issues
show
Bug introduced by
The property state does not seem to exist on Sfneal\Address\Models\Address. 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...
466
    }
467
468
    /**
469
     * Retrieve the User's 'zip' attribute.
470
     *
471
     * @return mixed
472
     */
473
    public function getZipAttribute()
474
    {
475
        return $this->address->zip ?? null;
0 ignored issues
show
Bug introduced by
The property zip does not seem to exist on Sfneal\Address\Models\Address. 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...
476
    }
477
478
    /**
479
     * Retrieve an email link.
480
     *
481
     * @return string
482
     */
483
    public function getEmailLinkAttribute(): string
484
    {
485
        return $this->email ? ('mailto:'.$this->email) : '#!';
0 ignored issues
show
Bug introduced by
The property email does not seem to exist on Sfneal\Users\Models\User. 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...
486
    }
487
488
    /**
489
     * Retrieve a work phone link.
490
     *
491
     * @return string
492
     */
493
    public function getPhoneWorkLinkAttribute(): string
494
    {
495
        return $this->phone_work ? ('tel:'.$this->phone_work) : '#!';
0 ignored issues
show
Bug introduced by
The property phone_work does not seem to exist on Sfneal\Users\Models\User. 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...
496
    }
497
498
    /**
499
     * Retrieve a mobile phone link.
500
     *
501
     * @return string
502
     */
503
    public function getPhoneMobileLinkAttribute(): string
504
    {
505
        return $this->phone_mobile ? ('tel:'.$this->phone_mobile) : '#!';
0 ignored issues
show
Bug introduced by
The property phone_mobile does not seem to exist on Sfneal\Users\Models\User. 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...
506
    }
507
508
    /**
509
     * Retrieve the User's rate formatted as dollars.
510
     *
511
     * @return string
512
     */
513
    public function getRateFormattedAttribute(): string
514
    {
515
        return (! empty($this->rate)) ? Currency::dollars($this->rate) : '-';
0 ignored issues
show
Bug introduced by
The property rate does not seem to exist on Sfneal\Users\Models\User. 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...
516
    }
517
518
    /**
519
     * Retrieve the raw 'text' attribute with newline chars.
520
     *
521
     * @return mixed
522
     */
523
    public function getTextareaAttribute()
524
    {
525
        return $this->attributes['bio'];
526
    }
527
528
    /**
529
     * Retrieve a User's custom email footer.
530
     *
531
     * @return string
532
     */
533
    public function getEmailFooterAttribute(): string
534
    {
535
        $footer = "{$this->name}";
536
        $footer .= $this->title ? "\n{$this->title}" : '';
0 ignored issues
show
Bug introduced by
The property title does not seem to exist on Sfneal\Users\Models\User. 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...
537
        $footer .= "\n".OrganizationService::name() ?? '';
538
        $footer .= "\n".($this->phone_work ?? OrganizationService::phone()) ?? '';
0 ignored issues
show
Bug introduced by
The property phone_work does not seem to exist on Sfneal\Users\Models\User. 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...
539
        $footer .= $this->email ? "\n{$this->email}" : '';
0 ignored issues
show
Bug introduced by
The property email does not seem to exist on Sfneal\Users\Models\User. 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...
540
541
        return $footer;
542
    }
543
}
544