User   F
last analyzed

Complexity

Total Complexity 62

Size/Duplication

Total Lines 504
Duplicated Lines 0 %

Test Coverage

Coverage 51.45%

Importance

Changes 0
Metric Value
wmc 62
eloc 120
c 0
b 0
f 0
dl 0
loc 504
ccs 71
cts 138
cp 0.5145
rs 3.44

36 Methods

Rating   Name   Duplication   Size   Complexity  
A setTokens() 0 3 1
A getRoleId() 0 3 1
A getGroup() 0 15 4
A getStatus() 0 7 2
A removeSessionData() 0 11 4
A getCredential() 0 3 1
A getEmail() 0 3 2
A setInfo() 0 4 1
A addProfile() 0 4 1
A getTokens() 0 7 2
A getSecret() 0 6 2
A __construct() 0 3 1
A getAuthSession() 0 11 3
A setStatus() 0 7 2
A isActive() 0 3 1
A getOrganization() 0 3 1
A getLogin() 0 3 1
A hasOrganization() 0 5 2
A updateAuthSession() 0 18 4
A setSettingsEntityResolver() 0 3 1
A setOrganization() 0 5 1
A getGroups() 0 6 2
A getInfo() 0 6 2
A setIsDraft() 0 5 1
A getSettings() 0 19 5
A setProfile() 0 4 1
A setEmail() 0 4 1
A removeProfile() 0 4 1
A getRole() 0 6 2
A setCredential() 0 4 1
A getProfile() 0 8 3
A setRole() 0 4 1
A isDraft() 0 3 1
A setPassword() 0 5 1
A setLogin() 0 4 1
A setSecret() 0 4 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
 * YAWIK
4
 *
5
 * @copyright (c) 2013 - 2016 Cross Solution (http://cross-solution.de)
6
 * @license       MIT
7
 */
8
9
namespace Auth\Entity;
10
11
use Core\Entity\AbstractIdentifiableEntity;
12
use Core\Entity\AttachableEntityInterface;
13
use Core\Entity\AttachableEntityTrait;
14
use Core\Entity\Collection\ArrayCollection;
15
use Core\Entity\DraftableEntityInterface;
16
use Doctrine\Common\Collections\Collection;
17
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;
18
use MongoDB\BSON\ObjectId;
19
use Organizations\Entity\OrganizationReferenceInterface;
20
use Settings\Repository\SettingsEntityResolver;
21
22
/**
23
 * Defines an user model
24
 *
25
 * @ODM\Document(collection="users", repositoryClass="Auth\Repository\User")
26
 *  * @ODM\Indexes({
27
 *      @ODM\Index(keys={
28
 *                  "login"="text",
29
 *                  "role"="text",
30
 *                    "info.email"="text",
31
 *                    "info.firstName"="text",
32
 *                    "info.lastName"="text"
33
 *                 }, name="fulltext")
34
 * })
35
 */
36
class User extends AbstractIdentifiableEntity implements UserInterface, DraftableEntityInterface, AttachableEntityInterface
37
{
38
    use AttachableEntityTrait;
39
40
    /**
41
     * Users login name
42
     *
43
     * @var string
44
     * @ODM\Field(type="string")
45
     * @ODM\Index(unique=true, sparse=true, order="asc")
46
     */
47
    protected $login;
48
49
    /**
50
     * Role of an user. Currently "user" or "recruiter"
51
     *
52
     * @ODM\Field(type="string")
53
     */
54
    protected $role;
55
56
    /**
57
     * Users contact data.
58
     *
59
     * @ODM\EmbedOne(targetDocument="Auth\Entity\Info")
60
     */
61
    protected $info;
62
63
    /**
64
     * Authentification Sessions like oAuth
65
     * After Authentification with OAuth sessions can be stored like a password/key pair
66
     *
67
     * @ODM\EmbedMany(targetDocument="Auth\Entity\AuthSession")
68
     */
69
    protected $authSessions;
70
71
    /**
72
     * Users login password
73
     *
74
     * @ODM\Field(type="string")
75
     */
76
    protected $credential;
77
78
    /**
79
     * Users primary email address
80
     *
81
     * @ODM\Field(type="string")
82
     */
83
    protected $email;
84
85
    /**
86
     * pre-shared key, which allows an external application to authenticate
87
     *
88
     * @var String
89
     * @ODM\Field(type="string")
90
     */
91
    protected $secret;
92
93
    /**
94
     * Can contain various HybridAuth profiles.
95
     * Deprecated: replaced by User::$profiles
96
     *
97
     * @var array
98
     * @deprecated
99
     * @ODM\Field(type="hash")
100
     */
101
    protected $profile = array();
102
103
    /**
104
     * Can contain various HybridAuth profiles.
105
     *
106
     * @var array
107
     * @ODM\Field(type="hash")
108
     */
109
    protected $profiles = [];
110
111
    /** @var array
112
     * @ODM\EmbedMany(discriminatorField="_entity")
113
     */
114
    protected $settings;
115
116
    /**
117
     * This is not a persistent property!
118
     *
119
     * @var SettingsEntityResolver
120
     */
121
    protected $settingsEntityResolver;
122
123
    /**
124
     * User groups.
125
     *
126
     * @var Collection
127
     * @ODM\ReferenceMany(targetDocument="Auth\Entity\Group", mappedBy="owner", storeAs="id", cascade="all")
128
     */
129
    protected $groups;
130
131
    /**
132
     * User tokens. Is generated when recovering Passwords as a short term key.
133
     *
134
     * @var Collection
135
     * @ODM\EmbedMany(targetDocument="Auth\Entity\Token")
136
     */
137
    protected $tokens;
138
139
    /**
140
     * The organization reference for the user.
141
     *
142
     * This field is not stored in the database, but injected on postLoad via
143
     * {@link \Organizations\Repository\Event\InjectOrganizationReferenceListener}
144
     *
145
     * @var OrganizationReferenceInterface
146
     *
147
     * @since 0.18
148
     */
149
    protected $organization;
150
151
    /**
152
     * Is this entity a draft or not?
153
     *
154
     * @var bool
155
     * @ODM\Field(type="bool")
156
     */
157
    protected $isDraft = false;
158
    
159
    /**
160
     * Status of user
161
     *
162
     * @var Status
163
     * @ODM\EmbedOne(targetDocument="Auth\Entity\Status")
164
     * @ODM\Index
165
     */
166
    protected $status;
167
168
    /**
169
     * @see http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/best-practices.html
170
     * It is recommended best practice to initialize any business collections in documents in the constructor.
171
     * {mg: What about lazy loading? Initialize the Collection in the getter, if none is set? Reduce overload.}
172 49
     */
173
    public function __construct()
174 49
    {
175
        $this->status = new Status();
176
    }
177
178
    /**
179
     * @return bool
180 1
     */
181
    public function isDraft()
182 1
    {
183
        return $this->isDraft;
184
    }
185
186
    /**
187
     * @param bool $flag
188
     * @return $this
189 1
     */
190
    public function setIsDraft($flag)
191 1
    {
192
        $this->isDraft = (bool) $flag;
193 1
194
        return $this;
195
    }
196
197
198 15
    /** {@inheritdoc} */
199
    public function setLogin($login)
200 15
    {
201 15
        $this->login = trim((String)$login);
202
        return $this;
203
    }
204
205 2
    /** {@inheritdoc} */
206
    public function getLogin()
207 2
    {
208
        return $this->login;
209
    }
210
211
    /**
212
     * {@inheritdoc}
213 18
     */
214
    public function setRole($role)
215 18
    {
216 18
        $this->role = $role;
217
        return $this;
218
    }
219
220
    /**
221
     * {@inheritdoc}
222 6
     */
223
    public function getRole()
224 6
    {
225 1
        if (!$this->role) {
226
            $this->setRole('user');
227 6
        }
228
        return $this->role;
229
    }
230
231
    /**
232
     * {@inheritdoc}
233 4
     */
234
    public function getRoleId()
235 4
    {
236
        return $this->getRole();
237
    }
238
239
    /**
240
     * {@inheritdoc}
241 16
     */
242
    public function setInfo(InfoInterface $info)
243 16
    {
244 16
        $this->info = $info;
245
        return $this;
246
    }
247
248 8
    /** {@inheritdoc} */
249
    public function getInfo()
250 8
    {
251 1
        if (null == $this->info) {
252
            $this->setInfo(new Info());
253 8
        }
254
        return $this->info;
255
    }
256
257
    /**
258
     * @param $key
259
     * @param $sessionParameter
260
     * @return $this
261
     */
262
    public function updateAuthSession($key, $sessionParameter)
263
    {
264
        $notExists = true;
265
266
        foreach ($this->authSessions as $authSession) {
267
            /* @var $authSession AuthSession */
268
            if ($key == $authSession->getName()) {
269
                $authSession->setSession($sessionParameter);
270
                $notExists = false;
271
            }
272
        }
273
        if ($notExists) {
274
            $authSession = new AuthSession();
275
            $authSession->setName($key);
276
            $authSession->setSession($sessionParameter);
277
            $this->authSessions[] = $authSession;
278
        }
279
        return $this;
280
    }
281
282
    /**
283
     * @param $key
284
     * @return null
285
     */
286
    public function getAuthSession($key)
287
    {
288
        $result = null;
289
290
        foreach ($this->authSessions as $authSession) {
291
            /* @var $authSession AuthSession */
292
            if ($key == $authSession->getName()) {
293
                $result = $authSession->getSession();
294
            }
295
        }
296
        return $result;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $result also could return the type array which is incompatible with the documented return type null.
Loading history...
297
    }
298
299
    /**
300
     * removes a stored Session
301
     * @param string|null $key providerName, if null, remove all sessions
302
     * @return $this
303
     */
304
    public function removeSessionData($key = null)
305
    {
306
        $authSessionRefresh = array();
307
        foreach ($this->authSessions as $authSession) {
308
            /* @var $authSession AuthSession */
309
            if (isset($key) && $key != $authSession->getName()) {
310
                $authSessionRefresh[] = $authSession;
311
            }
312
        }
313
        $this->authSessions = $authSessionRefresh;
314
        return $this;
315
    }
316
317 2
    /** {@inheritdoc} */
318
    public function getCredential()
319 2
    {
320
        return $this->credential;
321
    }
322
323 14
    /** {@inheritdoc} */
324
    public function setPassword($password)
325 14
    {
326 14
        $filter = new Filter\CredentialFilter();
327 14
        $credential = $filter->filter($password);
328
        return $this->setCredential($credential);
329
    }
330
331 14
    /** {@inheritdoc} */
332
    public function setCredential($credential)
333 14
    {
334 14
        $this->credential = $credential;
335
        return $this;
336
    }
337
338 4
    /** {@inheritdoc} */
339
    public function getSecret()
340 4
    {
341 1
        if (isset($this->secret)) {
342
            return $this->secret;
343 3
        }
344
        return $this->credential;
345
    }
346
347 1
    /** {@inheritdoc} */
348
    public function setSecret($secret)
349 1
    {
350 1
        $this->secret = $secret;
351
        return $this;
352
    }
353
354 3
    /** {@inheritdoc} */
355
    public function getEmail()
356 3
    {
357
        return $this->email ?: $this->getInfo()->getEmail();
358
    }
359
360 15
    /** {@inheritdoc} */
361
    public function setEmail($email)
362 15
    {
363 15
        $this->email = $email;
364
        return $this;
365
    }
366
367
    /** {@inheritdoc} */
368
    public function setProfile(array $profile)
369
    {
370
        $this->profile = $profile;
0 ignored issues
show
Deprecated Code introduced by
The property Auth\Entity\User::$profile has been deprecated. ( Ignorable by Annotation )

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

370
        /** @scrutinizer ignore-deprecated */ $this->profile = $profile;
Loading history...
371
        return $this;
372
    }
373
374 2
    /** {@inheritdoc} */
375
    public function getProfile($provider = null)
376 2
    {
377
        if (!isset($provider))
378 2
        {
379
            return $this->profiles;
380
        }
381
        
382
        return isset($this->profiles[$provider]) ? $this->profiles[$provider] : [];
383
    }
384
385
    /**
386
     * @param string $provider
387
     * @param array $data
388
     * @return \Auth\Entity\User
389
     */
390
    public function addProfile($provider, array $data)
391
    {
392
        $this->profiles[$provider] = $data;
393
        return $this;
394
    }
395
    
396
    /**
397
     * @param string $provider
398
     * @return \Auth\Entity\User
399
     */
400
    public function removeProfile($provider)
401
    {
402
        unset($this->profiles[$provider]);
403
        return $this;
404
    }
405
406
    /** {@inheritdoc} */
407
    public function setSettingsEntityResolver($resolver)
408
    {
409
        $this->settingsEntityResolver = $resolver;
410
    }
411
412
    /** {@inheritdoc} */
413
    public function getSettings($module)
414
    {
415
        if (!isset($module)) {
416
            throw new \InvalidArgumentException('$module must not be null.');
417
        }
418
419
        if (!$this->settings) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->settings of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
420
            $this->settings = new ArrayCollection();
0 ignored issues
show
Documentation Bug introduced by
It seems like new Core\Entity\Collection\ArrayCollection() of type Core\Entity\Collection\ArrayCollection is incompatible with the declared type array of property $settings.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
421
        }
422
423
        foreach ($this->settings as $settings) {
424
            if ($settings->moduleName == $module) {
425
                return $settings;
426
            }
427
        }
428
429
        $settings = $this->settingsEntityResolver->getNewSettingsEntity($module);
430
        $this->settings->add($settings);
431
        return $settings;
432
    }
433
434
    /** {@inheritdoc} */
435
    public function getGroups()
436
    {
437
        if (!$this->groups) {
438
            $this->groups = new ArrayCollection();
439
        }
440
        return $this->groups;
441
    }
442
443
    /** {@inheritdoc} */
444
    public function getGroup($name, $create = false)
445
    {
446
        $groups = $this->getGroups();
447
        foreach ($groups as $group) {
448
            /* @var $group GroupInterface */
449
            if ($group->getName() == $name) {
450
                return $group;
451
            }
452
        }
453
        if ($create) {
454
            $group = new Group($name, $this);
455
            $groups->add($group);
456
            return $group;
457
        }
458
        return null;
459
    }
460
461
    /**
462
     * @return Collection
463 4
     */
464
    public function getTokens()
465 4
    {
466 3
        if (!$this->tokens) {
467
            $this->tokens = new ArrayCollection();
468
        }
469 4
470
        return $this->tokens;
471
    }
472
473
    /**
474
     * @param Collection $tokens
475 1
     */
476
    public function setTokens($tokens)
477 1
    {
478
        $this->tokens = $tokens;
479
    }
480
481
    /**
482
     * @param OrganizationReferenceInterface $organization
483
     * @return $this
484 18
     */
485
    public function setOrganization(OrganizationReferenceInterface $organization)
486 18
    {
487
        $this->organization = $organization;
488 18
489
        return $this;
490
    }
491
492
    /**
493
     * @return bool
494 1
     */
495
    public function hasOrganization()
496
    {
497 1
        /* @var $this->organization \Organizations\Entity\OrganizationReference */
498 1
        return $this->organization &&
499
               $this->organization->hasAssociation();
500
    }
501
502
    /**
503
     * @return OrganizationReferenceInterface
504 6
     */
505
    public function getOrganization()
506 6
    {
507
        return $this->organization;
508
    }
509
    
510
    /**
511
     * @return Status
512 2
     */
513
    public function getStatus()
514 2
    {
515
        if (!isset($this->status)) {
516
            $this->status = new Status();
517
        }
518 2
        
519
        return $this->status;
520
    }
521
    
522
    /**
523
     * @param Status $status
524
     */
525
    public function setStatus($status)
526
    {
527
        if (!$status instanceof Status) {
0 ignored issues
show
introduced by
$status is always a sub-type of Auth\Entity\Status.
Loading history...
528
            $status = new Status($status);
529
        }
530
        
531
        $this->status = $status;
532
    }
533
    
534
    /**
535
     * @return boolean
536 2
     */
537
    public function isActive()
538 2
    {
539
        return $this->getStatus()->getName() === \Jobs\Entity\StatusInterface::ACTIVE;
540
    }
541
}
542