Completed
Push — master ( e30c7e...3fd9b3 )
by Alexis
01:37
created

User::addRole()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 13
rs 9.4285
cc 3
eloc 7
nc 3
nop 1
1
<?php
2
3
namespace AWurth\SilexUser\Entity;
4
5
use Doctrine\ORM\Mapping as ORM;
6
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
7
use Symfony\Component\Validator\Constraints\Email;
8
use Symfony\Component\Validator\Constraints\Length;
9
use Symfony\Component\Validator\Constraints\NotBlank;
10
use Symfony\Component\Validator\Constraints\Regex;
11
use Symfony\Component\Validator\Mapping\ClassMetadata;
12
13
/**
14
 * Base User class.
15
 *
16
 * @author Alexis Wurth <[email protected]>
17
 *
18
 * @ORM\MappedSuperclass
19
 */
20
abstract class User implements UserInterface
21
{
22
    /**
23
     * @var int
24
     *
25
     * @ORM\Id
26
     * @ORM\GeneratedValue
27
     * @ORM\Column(name="id", type="integer")
28
     */
29
    protected $id;
30
31
    /**
32
     * @var string
33
     *
34
     * @ORM\Column(name="username", type="string", length=30, unique=true)
35
     */
36
    protected $username;
37
38
    /**
39
     * @var string
40
     *
41
     * @ORM\Column(name="email", type="string", length=255, unique=true)
42
     */
43
    protected $email;
44
45
    /**
46
     * @var string
47
     *
48
     * @ORM\Column(name="password", type="string", length=255)
49
     */
50
    protected $password;
51
52
    /**
53
     * @var string
54
     */
55
    protected $plainPassword;
56
57
    /**
58
     * @var string
59
     *
60
     * @ORM\Column(name="salt", type="string", nullable=true)
61
     */
62
    protected $salt;
63
64
    /**
65
     * @var bool
66
     *
67
     * @ORM\Column(name="enabled", type="boolean")
68
     */
69
    protected $enabled = false;
70
71
    /**
72
     * @var array
73
     *
74
     * @ORM\Column(name="roles", type="array")
75
     */
76
    protected $roles = [];
77
78
    /**
79
     * @var string
80
     *
81
     * @ORM\Column(name="confirmation_token", type="string", unique=true, nullable=true)
82
     */
83
    protected $confirmationToken;
84
85
    public static function loadValidatorMetadata(ClassMetadata $metadata)
86
    {
87
        $metadata->addConstraint(new UniqueEntity([
88
            'fields' => 'username',
89
            'message' => 'silex_user.username.already_used'
90
        ]));
91
        $metadata->addConstraint(new UniqueEntity([
92
            'fields' => 'email',
93
            'message' => 'silex_user.email.already_used'
94
        ]));
95
96
        $metadata->addPropertyConstraint('username', new NotBlank(['message' => 'silex_user.username.blank']));
97
        $metadata->addPropertyConstraint('username', new Length([
98
            'min' => 3,
99
            'max' => 20,
100
            'minMessage' => 'silex_user.username.short',
101
            'maxMessage' => 'silex_user.username.long'
102
        ]));
103
        $metadata->addPropertyConstraint('username', new Regex([
104
            'pattern' => '/^[a-z0-9._-]+$/i',
105
            'message' => 'silex_user.username.invalid'
106
        ]));
107
108
        $metadata->addPropertyConstraint('email', new NotBlank(['message' => 'silex_user.username.blank']));
109
        $metadata->addPropertyConstraint('email', new Length([
110
            'max' => 100,
111
            'maxMessage' => 'silex_user.email.long'
112
        ]));
113
        $metadata->addPropertyConstraint('email', new Email(['message' => 'silex_user.email.invalid']));
114
115
        $metadata->addPropertyConstraint('plainPassword', new NotBlank(['message' => 'silex_user.password.blank']));
116
        $metadata->addPropertyConstraint('plainPassword', new Length([
117
            'min' => 8,
118
            'max' => 32,
119
            'minMessage' => 'silex_user.password.short',
120
            'maxMessage' => 'silex_user.password.long'
121
        ]));
122
    }
123
124
    /**
125
     * {@inheritdoc}
126
     */
127
    public function isAccountNonExpired()
128
    {
129
        return true;
130
    }
131
132
    /**
133
     * {@inheritdoc}
134
     */
135
    public function isAccountNonLocked()
136
    {
137
        return true;
138
    }
139
140
    /**
141
     * {@inheritdoc}
142
     */
143
    public function isCredentialsNonExpired()
144
    {
145
        return true;
146
    }
147
148
    /**
149
     * {@inheritdoc}
150
     */
151
    public function eraseCredentials()
152
    {
153
        $this->plainPassword = null;
154
    }
155
156
    /**
157
     * {@inheritdoc}
158
     */
159
    public function isEnabled()
160
    {
161
        return $this->enabled;
162
    }
163
164
    /**
165
     * {@inheritdoc}
166
     */
167
    public function setEnabled($enabled)
168
    {
169
        $this->enabled = (bool) $enabled;
170
171
        return $this;
172
    }
173
174
    /**
175
     * {@inheritdoc}
176
     */
177
    public function getId()
178
    {
179
        return $this->id;
180
    }
181
182
    /**
183
     * {@inheritdoc}
184
     */
185
    public function setUsername($username)
186
    {
187
        $this->username = $username;
188
189
        return $this;
190
    }
191
192
    /**
193
     * {@inheritdoc}
194
     */
195
    public function getUsername()
196
    {
197
        return $this->username;
198
    }
199
200
    /**
201
     * {@inheritdoc}
202
     */
203
    public function setEmail($email)
204
    {
205
        $this->email = $email;
206
207
        return $this;
208
    }
209
210
    /**
211
     * {@inheritdoc}
212
     */
213
    public function getEmail()
214
    {
215
        return $this->email;
216
    }
217
218
    /**
219
     * {@inheritdoc}
220
     */
221
    public function setPassword($password)
222
    {
223
        $this->password = $password;
224
225
        return $this;
226
    }
227
228
    /**
229
     * {@inheritdoc}
230
     */
231
    public function getPassword()
232
    {
233
        return $this->password;
234
    }
235
236
    /**
237
     * {@inheritdoc}
238
     */
239
    public function setPlainPassword($password)
240
    {
241
        $this->plainPassword = $password;
242
243
        return $this;
244
    }
245
246
    /**
247
     * {@inheritdoc}
248
     */
249
    public function getPlainPassword()
250
    {
251
        return $this->plainPassword;
252
    }
253
254
    /**
255
     * {@inheritdoc}
256
     */
257
    public function setSalt($salt)
258
    {
259
        $this->salt = $salt;
260
261
        return $this;
262
    }
263
264
    /**
265
     * {@inheritdoc}
266
     */
267
    public function getSalt()
268
    {
269
        return $this->salt;
270
    }
271
272
    /**
273
     * {@inheritdoc}
274
     */
275
    public function setRoles(array $roles)
276
    {
277
        $this->roles = $roles;
278
279
        return $this;
280
    }
281
282
    /**
283
     * {@inheritdoc}
284
     */
285
    public function getRoles()
286
    {
287
        $roles = $this->roles;
288
289
        $roles[] = self::ROLE_DEFAULT;
290
291
        return array_unique($roles);
292
    }
293
294
    /**
295
     * {@inheritdoc}
296
     */
297
    public function hasRole($role)
298
    {
299
        return in_array(strtoupper($role), $this->getRoles(), true);
0 ignored issues
show
Bug Best Practice introduced by
The return type of return in_array(strtoupp...his->getRoles(), true); (boolean) is incompatible with the return type declared by the interface AWurth\SilexUser\Entity\UserInterface::hasRole of type AWurth\SilexUser\Entity\UserInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
300
    }
301
302
    /**
303
     * {@inheritdoc}
304
     */
305
    public function addRole($role)
306
    {
307
        $role = strtoupper($role);
308
        if (static::ROLE_DEFAULT === $role) {
309
            return $this;
310
        }
311
312
        if (!in_array($role, $this->roles, true)) {
313
            $this->roles[] = $role;
314
        }
315
316
        return $this;
317
    }
318
319
    /**
320
     * {@inheritdoc}
321
     */
322
    public function removeRole($role)
323
    {
324
        $key = array_search(strtoupper($role), $this->roles, true);
325
        if (false !== $key) {
326
            unset($this->roles[$key]);
327
            $this->roles = array_values($this->roles);
328
        }
329
330
        return $this;
331
    }
332
333
    /**
334
     * {@inheritdoc}
335
     */
336
    public function setConfirmationToken($token)
337
    {
338
        $this->confirmationToken = $token;
339
340
        return $this;
341
    }
342
343
    /**
344
     * {@inheritdoc}
345
     */
346
    public function getConfirmationToken()
347
    {
348
        return $this->confirmationToken;
349
    }
350
}
351