Completed
Pull Request — master (#2737)
by
unknown
08:55
created

BaseUser   F

Complexity

Total Complexity 62

Size/Duplication

Total Lines 599
Duplicated Lines 0 %

Coupling/Cohesion

Components 5
Dependencies 6

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 62
lcom 5
cbo 6
dl 0
loc 599
ccs 48
cts 48
cp 1
rs 3.44
c 0
b 0
f 0

53 Methods

Rating   Name   Duplication   Size   Complexity  
A getId() 0 4 1
A setId() 0 6 1
A getGroups() 0 4 1
A getAdminLocale() 0 4 1
getFormTypeClass() 0 1 ?
A __construct() 0 5 1
A getGroupIds() 0 14 3
A setEnabled() 0 6 1
A setAdminLocale() 0 6 1
A isPasswordChanged() 0 4 1
A setPasswordChanged() 0 6 1
A getGoogleId() 0 4 1
A setGoogleId() 0 4 1
A loadValidatorMetadata() 0 21 1
A isAccountNonLocked() 0 4 1
A getEmail() 0 4 1
A setEmail() 0 6 1
A getPassword() 0 4 1
A setPassword() 0 6 1
A getPlainPassword() 0 4 1
A setPlainPassword() 0 6 1
A getRoles() 0 13 2
A hasRole() 0 4 1
A setRoles() 0 10 2
A removeRole() 0 9 2
A getSalt() 0 4 1
A setSalt() 0 6 1
A isEnabled() 0 4 1
A getUsername() 0 4 1
A setUsername() 0 6 1
A eraseCredentials() 0 4 1
A addRole() 0 13 3
A getGroupNames() 0 9 2
A hasGroup() 0 4 1
A addGroup() 0 8 2
A removeGroup() 0 8 2
A __toString() 0 4 1
A getUsernameCanonical() 0 7 1
A setUsernameCanonical() 0 7 1
A getEmailCanonical() 0 7 1
A setEmailCanonical() 0 7 1
A isSuperAdmin() 0 5 1
A setSuperAdmin() 0 5 1
A getConfirmationToken() 0 4 1
A setConfirmationToken() 0 4 1
A setPasswordRequestedAt() 0 5 1
A getLastLogin() 0 4 1
A setLastLogin() 0 6 1
A isAccountNonExpired() 0 7 1
A isCredentialsNonExpired() 0 7 1
A isPasswordRequestNonExpired() 0 7 1
A serialize() 0 11 1
A unserialize() 0 13 1

How to fix   Complexity   

Complex Class

Complex classes like BaseUser 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 BaseUser, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Kunstmaan\AdminBundle\Entity;
4
5
use Doctrine\Common\Collections\ArrayCollection;
6
use Doctrine\ORM\Mapping as ORM;
7
use FOS\UserBundle\Model\GroupInterface;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Kunstmaan\AdminBundle\Entity\GroupInterface.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
8
use Kunstmaan\AdminBundle\Validator\Constraints\PasswordRestrictions;
9
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
10
use Symfony\Component\Validator\Constraints\Email;
11
use Symfony\Component\Validator\Constraints\NotBlank;
12
use Symfony\Component\Validator\Mapping\ClassMetadata;
13
use DateTime;
14
15
abstract class BaseUser implements UserInterface
16
{
17
    /**
18
     * @ORM\Id
19
     * @ORM\Column(type="integer")
20
     * @ORM\GeneratedValue(strategy="AUTO")
21
     */
22
    protected $id;
23
24
    /**
25
     * @var string
26
     *
27
     * @ORM\Column(type="string", length=180, unique=true)
28
     */
29
    protected $username;
30
31
    /**
32
     * Next Major: Remove attribute
33
     *
34
     * @var string
35
     *
36
     * @ORM\Column(type="string", length=180, unique=true)
37
     */
38
    protected $usernameCanonical;
39
40
    /**
41
     * The doctrine metadata is set dynamically in Kunstmaan\AdminBundle\EventListener\MappingListener
42
     */
43
    protected $groups;
44
45
    /**
46
     * @ORM\Column(type="string", name="admin_locale", length=5, nullable=true)
47 35
     */
48
    protected $adminLocale;
49 35
50 35
    /**
51 35
     * @ORM\Column(type="boolean", name="password_changed", nullable=true)
52
     */
53
    protected $passwordChanged;
54
55
    /**
56
     * @ORM\Column(name="google_id", type="string", length=255, nullable=true)
57
     */
58 3
    protected $googleId;
59
60 3
    /**
61
     * @var string
62
     *
63
     * @ORM\Column(type="string", length=180, unique=true)
64
     */
65
    protected $email;
66
67
    /**
68
     * Next Major: Remove attribute
69
     *
70 8
     * @var string
71
     *
72 8
     * @ORM\Column(type="string", length=180, unique=true)
73
     */
74 8
    protected $emailCanonical;
75
76
    /**
77
     * @var string
78
     *
79
     * @ORM\Column(name="password", type="string", length=100)
80
     */
81
    protected $password;
82 1
83
    /**
84 1
     * @var string|null
85
     */
86 1
    protected $plainPassword;
87 1
88
    /**
89 1
     * @var string|null
90 1
     *
91
     * @ORM\Column(type="string", length=255, nullable=true)
92
     */
93
    protected $confirmationToken;
94 1
95
    /**
96
     * @var string
97
     *
98
     * @ORM\Column(name="salt", type="string", length=100)
99
     */
100
    protected $salt;
101
102 6
    /**
103
     * @var \DateTime
104 6
     *
105
     * @ORM\Column(name="last_login", type="datetime", nullable=true)
106
     */
107
    protected $lastLogin;
108
109
    /**
110
     * @var array
111
     *
112 1
     * @ORM\Column(name="roles", type="array")
113
     */
114 1
    protected $roles;
115
116
    /**
117
     * @ORM\Column(name="enabled", type="boolean")
118
     */
119
    protected $enabled;
120
121
    /**
122
     * Construct a new user
123
     */
124 2
    public function __construct()
125
    {
126 2
        $this->groups = new ArrayCollection();
127
        $this->roles = [];
128 2
    }
129
130
    /**
131
     * Get id
132
     *
133
     * @return int
134
     */
135
    public function getId()
136 1
    {
137
        return $this->id;
138 1
    }
139
140
    /**
141
     * Set id
142
     *
143
     * @param int $id
144
     *
145
     * @return BaseUser
146
     */
147
    public function setId($id)
148 2
    {
149
        $this->id = $id;
150 2
151
        return $this;
152 2
    }
153
154
    /**
155
     * Gets the groupIds for the user.
156
     *
157
     * @return array
158 1
     */
159
    public function getGroupIds()
160 1
    {
161
        $groups = $this->groups;
162
163
        $groupIds = array();
164
        if (\count($groups) > 0) {
165
            /* @var $group GroupInterface */
166 3
            foreach ($groups as $group) {
167
                $groupIds[] = $group->getId();
168 3
            }
169 3
        }
170
171
        return $groupIds;
172
    }
173
174 1
    /**
175
     * Gets the groups the user belongs to.
176 1
     *
177 1
     * @return ArrayCollection
178 1
     */
179
    public function getGroups()
180 1
    {
181 1
        return $this->groups;
182
    }
183
184 1
    /**
185 1
     * Get adminLocale
186 1
     *
187 1
     * @return string
188
     */
189
    public function getAdminLocale()
190 1
    {
191 1
        return $this->adminLocale;
192
    }
193
194 1
    /**
195
     * {@inheritdoc}
196
     */
197
    public function setEnabled($boolean)
198
    {
199
        $this->enabled = (bool) $boolean;
200
201
        return $this;
202
    }
203
204
    /**
205
     * Set adminLocale
206 1
     *
207
     * @param string $adminLocale
208 1
     *
209
     * @return BaseUser
210
     */
211
    public function setAdminLocale($adminLocale)
212
    {
213
        $this->adminLocale = $adminLocale;
214
215
        return $this;
216
    }
217
218
    /**
219
     * is passwordChanged
220
     *
221
     * @return bool
222
     */
223
    public function isPasswordChanged()
224
    {
225
        return $this->passwordChanged;
226
    }
227
228
    public function setPasswordChanged($passwordChanged)
229
    {
230
        $this->passwordChanged = $passwordChanged;
231
232
        return $this;
233
    }
234
235
    /**
236
     * @return mixed
237
     */
238
    public function getGoogleId()
239
    {
240
        return $this->googleId;
241
    }
242
243
    /**
244
     * @param mixed $googleId
245
     */
246
    public function setGoogleId($googleId)
247
    {
248
        $this->googleId = $googleId;
249
    }
250
251
    /**
252
     * @param ClassMetadata $metadata
253
     */
254
    public static function loadValidatorMetadata(ClassMetadata $metadata)
255
    {
256
        $metadata->addPropertyConstraint('username', new NotBlank());
257
        $metadata->addPropertyConstraints(
258
            'plainPassword',
259
            array(
260
                new NotBlank(array('groups' => array('Registration'))),
261
                new PasswordRestrictions(array('groups' => array('Registration', 'Default'))),
262
            )
263
        );
264
        $metadata->addPropertyConstraint('email', new NotBlank());
265
        $metadata->addPropertyConstraint('email', new Email());
266
        $metadata->addConstraint(new UniqueEntity(array(
267
            'fields' => 'username',
268
            'message' => 'errors.user.loginexists',
269
        )));
270
        $metadata->addConstraint(new UniqueEntity(array(
271
            'fields' => 'email',
272
            'message' => 'errors.user.emailexists',
273
        )));
274
    }
275
276
    /**
277
     * Return class name of form type used to add & edit users
278
     *
279
     * @return string
280
     */
281
    abstract public function getFormTypeClass();
282
283
    /**
284
     * {@inheritdoc}
285
     */
286
    public function isAccountNonLocked()
287
    {
288
        return $this->isEnabled();
289
    }
290
291
    /**
292
     * @return string
293
     */
294
    public function getEmail(): string
295
    {
296
        return $this->email;
297
    }
298
299
    public function setEmail($email)
300
    {
301
        $this->email = $email;
302
303
        return $this;
304
    }
305
306
    /**
307
     * @return string
308
     */
309
    public function getPassword(): string
310
    {
311
        return $this->password;
312
    }
313
314
    public function setPassword($password)
315
    {
316
        $this->password = $password;
317
318
        return $this;
319
    }
320
321
    public function getPlainPassword(): ?string
322
    {
323
        return $this->plainPassword;
324
    }
325
326
    public function setPlainPassword($plainPassword)
327
    {
328
        $this->plainPassword = $plainPassword;
329
330
        return $this;
331
    }
332
333
    /**
334
     * @return array
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use string[].

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
335
     */
336
    public function getRoles()
337
    {
338
        $roles = $this->roles;
339
340
        foreach ($this->getGroups() as $group) {
341
            $roles = array_merge($roles, $group->getRoles());
342
        }
343
344
        // we need to make sure to have at least one role
345
        $roles[] = static::ROLE_DEFAULT;
346
347
        return array_unique($roles);
348
    }
349
350
    public function hasRole($role)
351
    {
352
        return in_array(strtoupper($role), $this->getRoles(), true);
353
    }
354
355
    /**
356
     * {@inheritdoc}
357
     */
358
    public function setRoles(array $roles)
359
    {
360
        $this->roles = array();
361
362
        foreach ($roles as $role) {
363
            $this->addRole($role);
364
        }
365
366
        return $this;
367
    }
368
369
    public function removeRole($role)
370
    {
371
        if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
372
            unset($this->roles[$key]);
373
            $this->roles = array_values($this->roles);
374
        }
375
376
        return $this;
377
    }
378
379
    public function getSalt(): ?string
380
    {
381
        return $this->salt;
382
    }
383
384
    public function setSalt($salt)
385
    {
386
        $this->salt = $salt;
387
388
        return $this;
389
    }
390
391
    public function isEnabled()
392
    {
393
        return $this->enabled;
394
    }
395
396
    /**
397
     * @return string The username
398
     */
399
    public function getUsername(): string
400
    {
401
        return $this->username;
402
    }
403
404
    public function setUsername($username)
405
    {
406
        $this->username = $username;
407
408
        return $this;
409
    }
410
411
    /**
412
     * Removes sensitive data from the user.
413
     */
414
    public function eraseCredentials(): void
415
    {
416
        $this->plainPassword = null;
417
    }
418
419
    /**
420
     * {@inheritdoc}
421
     */
422
    public function addRole($role)
423
    {
424
        $role = strtoupper($role);
425
        if ($role === static::ROLE_DEFAULT) {
426
            return $this;
427
        }
428
429
        if (!in_array($role, $this->roles, true)) {
430
            $this->roles[] = $role;
431
        }
432
433
        return $this;
434
    }
435
436
    /**
437
     * {@inheritdoc}
438
     */
439
    public function getGroupNames()
440
    {
441
        $names = array();
442
        foreach ($this->getGroups() as $group) {
443
            $names[] = $group->getName();
444
        }
445
446
        return $names;
447
    }
448
449
    /**
450
     * {@inheritdoc}
451
     */
452
    public function hasGroup($name)
453
    {
454
        return in_array($name, $this->getGroupNames());
455
    }
456
457
    /**
458
     * {@inheritdoc}
459
     */
460
    public function addGroup(GroupInterface $group)
461
    {
462
        if (!$this->getGroups()->contains($group)) {
463
            $this->getGroups()->add($group);
464
        }
465
466
        return $this;
467
    }
468
469
    /**
470
     * {@inheritdoc}
471
     */
472
    public function removeGroup(GroupInterface $group)
473
    {
474
        if ($this->getGroups()->contains($group)) {
475
            $this->getGroups()->removeElement($group);
476
        }
477
478
        return $this;
479
    }
480
481
    public function __toString()
482
    {
483
        return (string) $this->getUsername();
484
    }
485
486
    public function getUsernameCanonical()
487
    {
488
        // NEXT_MAJOR remove method
489
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
490
491
        return $this->usernameCanonical;
492
    }
493
494
    public function setUsernameCanonical($usernameCanonical)
495
    {
496
        // NEXT_MAJOR remove method
497
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
498
499
        $this->usernameCanonical = $usernameCanonical;
500
    }
501
502
    public function getEmailCanonical()
503
    {
504
        // NEXT_MAJOR remove method
505
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
506
507
        return $this->emailCanonical;
508
    }
509
510
    public function setEmailCanonical($emailCanonical)
511
    {
512
        // NEXT_MAJOR remove method
513
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
514
515
        $this->emailCanonical = $emailCanonical;
516
    }
517
518
    public function isSuperAdmin()
519
    {
520
        // NEXT_MAJOR remove method
521
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
522
    }
523
524
    public function setSuperAdmin($boolean)
525
    {
526
        // NEXT_MAJOR remove method
527
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
528
    }
529
530
    public function getConfirmationToken()
531
    {
532
        return $this->confirmationToken;
533
    }
534
535
    public function setConfirmationToken($confirmationToken)
536
    {
537
        $this->confirmationToken = $confirmationToken;
538
    }
539
540
    public function setPasswordRequestedAt(DateTime $date = null)
541
    {
542
        // NEXT_MAJOR remove method
543
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
544
    }
545
546
    public function getLastLogin()
547
    {
548
        return $this->lastLogin;
549
    }
550
551
    public function setLastLogin(?DateTime $lastLogin = null)
552
    {
553
        $this->lastLogin = $lastLogin;
554
555
        return $this;
556
    }
557
558
    public function isAccountNonExpired()
559
    {
560
        // NEXT_MAJOR remove method
561
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
562
563
        return true;
564
    }
565
566
    public function isCredentialsNonExpired()
567
    {
568
        // NEXT_MAJOR remove method
569
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
570
571
        return true;
572
    }
573
574
    public function isPasswordRequestNonExpired($ttl)
575
    {
576
        // NEXT_MAJOR remove method
577
        @trigger_error(sprintf('Using method %s from class %s is deprecated since KunstmaanAdminBundle 5.8 and will be removed in KunstmaanAdminBundle 6.0.', __METHOD__, BaseUser::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
578
579
        return false;
580
    }
581
582
    /**
583
     * {@inheritdoc}
584
     */
585
    public function serialize()
586
    {
587
        return serialize(array(
588
            $this->password,
589
            $this->salt,
590
            $this->username,
591
            $this->enabled,
592
            $this->id,
593
            $this->email,
594
        ));
595
    }
596
597
    /**
598
     * {@inheritdoc}
599
     */
600
    public function unserialize($serialized)
601
    {
602
        $data = unserialize($serialized);
603
604
        [
605
            $this->password,
606
            $this->salt,
607
            $this->username,
608
            $this->enabled,
609
            $this->id,
610
            $this->email,
611
            ] = $data;
612
    }
613
}
614