Passed
Push — master ( 7eb298...3b4b3c )
by Stephen
01:09 queued 12s
created

User   B

Complexity

Total Complexity 49

Size/Duplication

Total Lines 446
Duplicated Lines 0 %

Importance

Changes 21
Bugs 3 Features 0
Metric Value
eloc 92
c 21
b 3
f 0
dl 0
loc 446
rs 8.48
wmc 49

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

333
        return trim(/** @scrutinizer ignore-type */ $value);
Loading history...
334
    }
335
336
    /**
337
     * Access the 'last_name' attribute.
338
     *
339
     * @param string|null $value
340
     * @return string
341
     */
342
    public function getLastNameAttribute(string $value = null): string
343
    {
344
        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

344
        return trim(/** @scrutinizer ignore-type */ $value);
Loading history...
345
    }
346
347
    /**
348
     * Retrieve the User's name (first & last).
349
     *
350
     * @return string
351
     */
352
    public function getNameAttribute(): string
353
    {
354
        // Use nickname instead of first if it is set & preferred
355
        $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...
356
357
        // Return concatenated name
358
        return "{$first} {$this->last_name}";
359
    }
360
361
    /**
362
     * Retrieve the User's full name with middle initial.
363
     *
364
     * @return string
365
     */
366
    public function getNameFullAttribute(): string
367
    {
368
        $name = $this->first_name;
369
        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...
370
            $name .= ' '.$this->middle_name;
371
        }
372
373
        return "{$name} {$this->last_name}";
374
    }
375
376
    /**
377
     * Retrieve the User's name with their suffix.
378
     *
379
     * @return string
380
     */
381
    public function getNameSuffixAttribute(): string
382
    {
383
        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...
384
    }
385
386
    /**
387
     * Get the 'list_name' attribute.
388
     *
389
     * @return string
390
     */
391
    public function getListNameAttribute()
392
    {
393
        return implode(', ', array_reverse(explode(' ', $this->name)));
394
    }
395
396
    /**
397
     * Get the 'name_link' attribute that returns a url to the User's team.show page.
398
     *
399
     * @return string
400
     */
401
    public function getNameLinkAttribute()
402
    {
403
        return '<a href="'.route('user.show', ['user'=>$this->id]).'">'.$this->name.'</a>';
404
    }
405
406
    /**
407
     * Retrieve an email link.
408
     *
409
     * @return string
410
     */
411
    public function getEmailLinkAttribute(): string
412
    {
413
        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...
414
    }
415
416
    /**
417
     * Retrieve a work phone link.
418
     *
419
     * @return string
420
     */
421
    public function getPhoneWorkLinkAttribute(): string
422
    {
423
        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...
424
    }
425
426
    /**
427
     * Retrieve a mobile phone link.
428
     *
429
     * @return string
430
     */
431
    public function getPhoneMobileLinkAttribute(): string
432
    {
433
        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...
434
    }
435
436
    /**
437
     * Retrieve the User's rate formatted as dollars.
438
     *
439
     * @return string
440
     */
441
    public function getRateFormattedAttribute(): string
442
    {
443
        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...
444
    }
445
446
    /**
447
     * Retrieve the raw 'text' attribute with newline chars.
448
     *
449
     * @return mixed
450
     */
451
    public function getTextareaAttribute()
452
    {
453
        return $this->attributes['bio'];
454
    }
455
456
    /**
457
     * Retrieve a User's custom email footer.
458
     *
459
     * @return string
460
     */
461
    public function getEmailFooterAttribute(): string
462
    {
463
        $footer = "{$this->name}";
464
        $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...
465
        $footer .= "\n".OrganizationService::name() ?? '';
466
        $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...
467
        $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...
468
469
        return $footer;
470
    }
471
}
472