User   B
last analyzed

Complexity

Total Complexity 42

Size/Duplication

Total Lines 297
Duplicated Lines 5.72 %

Coupling/Cohesion

Components 4
Dependencies 0

Importance

Changes 13
Bugs 0 Features 4
Metric Value
wmc 42
c 13
b 0
f 4
lcom 4
cbo 0
dl 17
loc 297
rs 8.295

21 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A getUsername() 0 4 1
A getEmail() 0 4 1
A eraseCredentials() 0 4 1
A getPassword() 0 4 1
A getSalt() 0 4 1
A getFirstname() 0 4 1
A getLastname() 0 4 1
A regenerateConfirmationToken() 0 17 4
A getCreatedAt() 0 4 1
A getUpdatedAt() 0 4 1
A __toString() 0 4 2
A getRoles() 0 10 3
A setPassword() 0 5 1
A setFirstname() 0 6 1
A setLastname() 0 6 1
A confirm() 0 5 1
A setCreatedAt() 0 5 1
A setUpdatedAt() 0 5 1
A serialize() 0 7 1
A unserialize() 0 8 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
3
namespace AppBundle\Entity;
4
5
use AppBundle\Mailer\ContactInterface;
6
use Doctrine\ORM\Mapping as ORM;
7
use Gedmo\Mapping\Annotation as Gedmo;
8
use Symfony\Component\Security\Core\User\UserInterface;
9
use Symfony\Component\Validator\Constraints as Assert;
10
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
11
12
/**
13
 * @ORM\Entity
14
 * @ORM\Table(name="users")
15
 * @UniqueEntity("email")
16
 */
17
class User implements UserInterface, \Serializable, ContactInterface
18
{
19
    static public $roleMap = [
20
        'ROLE_USER' => 1,
21
        'ROLE_ADMIN' => 2,
22
    ];
23
24
    /**
25
     * @ORM\Id
26
     * @ORM\Column(type="integer")
27
     * @ORM\GeneratedValue
28
     */
29
    private $id;
30
31
    /**
32
     * @ORM\Column(length=255, unique=true)
33
     * @Assert\NotBlank(message="Email address cannot be empty", groups={"signup", "reset"})
34
     * @Assert\Email(message="Email address is not valid", groups={"signup", "reset"})
35
     */
36
    private $email;
37
38
    /**
39
     * @ORM\Column(length=48)
40
     */
41
    private $salt;
42
43
    /**
44
     * @ORM\Column(length=64, nullable=true)
45
     * @Assert\NotBlank(message="First Name cannot be empty", groups={"confirm", "profile"})
46
     */
47
    private $firstname;
48
49
    /**
50
     * @ORM\Column(length=64, nullable=true)
51
     * @Assert\NotBlank(message="Last name cannot be empty", groups={"confirm", "profile"})
52
     */
53
    private $lastname;
54
55
    /**
56
     * @ORM\Column(name="confirmation_token", length=48, nullable=true)
57
     */
58
    private $confirmationToken;
59
60
    /**
61
     * @ORM\Column(type="integer")
62
     */
63
    private $roles = 0; // has no roles by default
64
65
    /**
66
     * @Gedmo\Timestampable(on="create")
67
     * @ORM\Column(type="datetime", name="created_at")
68
     */
69
    private $createdAt;
70
71
    /**
72
     * @Gedmo\Timestampable(on="update")
73
     * @ORM\Column(type="datetime", name="updated_at")
74
     */
75
    private $updatedAt;
76
77
    /**
78
     * @ORM\Column(length=64, nullable=true)
79
     */
80
    private $password;
81
82
    /**
83
     * Plain password. Used for model validation. Must not be persisted.
84
     *
85
     * @Assert\NotBlank(message="Password cannot be empty", groups={"confirm"})
86
     * @Assert\Length(
87
     *   min=8,
88
     *   max=4096,
89
     *   minMessage="Password is too short",
90
     *   maxMessage="Password is too long",
91
     *   groups={"confirm", "profile"}
92
     * )
93
     */
94
    private $plainPassword;
95
96
    public function __construct()
97
    {
98
        $this->salt = base_convert(sha1(uniqid(mt_rand(), true)), 16, 36);
99
    }
100
101
    public function getId()
102
    {
103
        return $this->id;
104
    }
105
106
    public function getUsername()
107
    {
108
        return $this->email;
109
    }
110
111
    public function setEmail($email)
112
    {
113
        $this->email = $email;
114
        return $this;
115
    }
116
117
    public function getEmail()
118
    {
119
        return $this->email;
120
    }
121
122
    public function eraseCredentials()
123
    {
124
        $this->plainPassword = null;
125
    }
126
127
    public function setPlainPassword($plainPassword)
128
    {
129
        $this->plainPassword = $plainPassword;
130
        return $this;
131
    }
132
133
    public function getPlainPassword()
134
    {
135
        return $this->plainPassword;
136
    }
137
138
    public function getRoles()
139
    {
140
        $roles = [];
141
        foreach (self::$roleMap as $role => $flag) {
142
            if ($flag === ($this->roles & $flag)) {
143
                $roles[] = $role;
144
            }
145
        }
146
        return $roles;
147
    }
148
149
    public function hasRole($role)
150
    {
151
        return in_array($role, $this->getRoles(), true);
152
    }
153
154 View Code Duplication
    public function removeRole($role)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
155
    {
156
        $role = strtoupper($role);
157
        if (array_key_exists($role, self::$roleMap)) {
158
            $this->roles ^= self::$roleMap[$role];
159
        }
160
        return $this;
161
    }
162
163
    public function setRoles(array $roles)
164
    {
165
        $this->roles = 0;
166
        foreach ($roles as $role) {
167
            $this->addRole($role);
168
        }
169
        return $this;
170
    }
171
172 View Code Duplication
    public function addRole($role)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
173
    {
174
        $role = strtoupper($role);
175
        if (!array_key_exists($role, self::$roleMap)) {
176
            return $this;
177
        }
178
        $this->roles |= self::$roleMap[$role];
179
        return $this;
180
    }
181
182
    public function setPassword($password)
183
    {
184
        $this->password = $password;
185
        return $this;
186
    }
187
188
    public function getPassword()
189
    {
190
        return $this->password;
191
    }
192
193
    public function getSalt()
194
    {
195
        return $this->salt;
196
    }
197
198
    public function getFirstname()
199
    {
200
        return $this->firstname;
201
    }
202
203
    public function getLastname()
204
    {
205
        return $this->lastname;
206
    }
207
208
    public function setFirstname($firstname)
209
    {
210
        $this->firstname = $firstname;
211
212
        return $this;
213
    }
214
215
    public function setLastname($lastname)
216
    {
217
        $this->lastname = $lastname;
218
219
        return $this;
220
    }
221
222
    public function setConfirmationToken($confirmationToken)
223
    {
224
        $this->confirmationToken = $confirmationToken;
225
        return $this;
226
    }
227
228
    public function getConfirmationToken()
229
    {
230
        return $this->confirmationToken;
231
    }
232
233
    public function regenerateConfirmationToken()
234
    {
235
        if (function_exists('openssl_random_pseudo_bytes')) {
236
            $bytes = openssl_random_pseudo_bytes(32, $strong);
237
238
            if (false !== $bytes && true === $strong) {
239
                $num = $bytes;
240
            } else {
241
                $num = hash('sha256', uniqid(mt_rand(), true), true);
242
            }
243
        } else {
244
            $num = hash('sha256', uniqid(mt_rand(), true), true);
245
        }
246
247
        $this->confirmationToken = rtrim(strtr(base64_encode($num), '+/', '-_'), '=');
248
        return $this;
249
    }
250
251
    public function isConfirmed()
252
    {
253
        return $this->password !== null;
254
    }
255
256
    public function confirm()
257
    {
258
        $this->addRole('ROLE_USER');
259
        $this->confirmationToken = null;
260
    }
261
262
    public function setCreatedAt(\DateTime $createdAt)
263
    {
264
        $this->createdAt = $createdAt;
265
        return $this;
266
    }
267
268
    public function getCreatedAt()
269
    {
270
        return $this->createdAt;
271
    }
272
273
    public function setUpdatedAt(\DateTime $updatedAt)
274
    {
275
        $this->updatedAt = $updatedAt;
276
        return $this;
277
    }
278
279
    public function getUpdatedAt()
280
    {
281
        return $this->updatedAt;
282
    }
283
284
    public function __toString()
285
    {
286
        return $this->firstname ? trim($this->firstname . ' ' . $this->lastname) : $this->email;
287
    }
288
289
    public function serialize()
290
    {
291
        return serialize([
292
            $this->email,
293
            $this->id,
294
        ]);
295
    }
296
297
    public function unserialize($serialized)
298
    {
299
        // add a few extra elements in the array to ensure that we have enough keys when unserializing
300
        // older data which does not include all properties.
301
        $data = array_merge(unserialize($serialized), array_fill(0, 2, null));
302
303
        list($this->email, $this->id) = $data;
304
    }
305
306
    /**
307
     * @return string
308
     */
309
    public function getFullName()
310
    {
311
        return trim($this->firstname . ' ' . $this->lastname);
312
    }
313
}
314