1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
* This file is part of the BenGorUser package. |
5
|
|
|
* |
6
|
|
|
* (c) Beñat Espiña <[email protected]> |
7
|
|
|
* (c) Gorka Laucirica <[email protected]> |
8
|
|
|
* |
9
|
|
|
* For the full copyright and license information, please view the LICENSE |
10
|
|
|
* file that was distributed with this source code. |
11
|
|
|
*/ |
12
|
|
|
|
13
|
|
|
namespace BenGorUser\User\Domain\Model; |
14
|
|
|
|
15
|
|
|
use BenGorUser\User\Domain\Model\Event\UserEnabled; |
16
|
|
|
use BenGorUser\User\Domain\Model\Event\UserInvitationTokenRegenerated; |
17
|
|
|
use BenGorUser\User\Domain\Model\Event\UserInvited; |
18
|
|
|
use BenGorUser\User\Domain\Model\Event\UserLoggedIn; |
19
|
|
|
use BenGorUser\User\Domain\Model\Event\UserLoggedOut; |
20
|
|
|
use BenGorUser\User\Domain\Model\Event\UserRegistered; |
21
|
|
|
use BenGorUser\User\Domain\Model\Event\UserRememberPasswordRequested; |
22
|
|
|
use BenGorUser\User\Domain\Model\Event\UserRoleGranted; |
23
|
|
|
use BenGorUser\User\Domain\Model\Event\UserRoleRevoked; |
24
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserInactiveException; |
25
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserInvitationAlreadyAcceptedException; |
26
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserPasswordInvalidException; |
27
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserRoleAlreadyGrantedException; |
28
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserRoleAlreadyRevokedException; |
29
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserRoleInvalidException; |
30
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserTokenExpiredException; |
31
|
|
|
use BenGorUser\User\Domain\Model\Exception\UserTokenNotFoundException; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* User domain class. |
35
|
|
|
* |
36
|
|
|
* @author Beñat Espiña <[email protected]> |
37
|
|
|
* @author Gorka Laucirica <[email protected]> |
38
|
|
|
*/ |
39
|
|
|
class User extends UserAggregateRoot |
40
|
|
|
{ |
41
|
|
|
/** |
42
|
|
|
* The id. |
43
|
|
|
* |
44
|
|
|
* @var UserId |
45
|
|
|
*/ |
46
|
|
|
protected $id; |
47
|
|
|
|
48
|
|
|
/** |
49
|
|
|
* The confirmation token. |
50
|
|
|
* |
51
|
|
|
* @var UserToken |
52
|
|
|
*/ |
53
|
|
|
protected $confirmationToken; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* Created on. |
57
|
|
|
* |
58
|
|
|
* @var \DateTimeInterface |
59
|
|
|
*/ |
60
|
|
|
protected $createdOn; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* The email. |
64
|
|
|
* |
65
|
|
|
* @var UserEmail |
66
|
|
|
*/ |
67
|
|
|
protected $email; |
68
|
|
|
|
69
|
|
|
/** |
70
|
|
|
* The invitation token. |
71
|
|
|
* |
72
|
|
|
* @var UserToken |
73
|
|
|
*/ |
74
|
|
|
protected $invitationToken; |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* The last login. |
78
|
|
|
* |
79
|
|
|
* @var \DateTimeInterface|null |
80
|
|
|
*/ |
81
|
|
|
protected $lastLogin; |
82
|
|
|
|
83
|
|
|
/** |
84
|
|
|
* The password. |
85
|
|
|
* |
86
|
|
|
* @var UserPassword |
87
|
|
|
*/ |
88
|
|
|
protected $password; |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* The remember password token. |
92
|
|
|
* |
93
|
|
|
* @var UserToken |
94
|
|
|
*/ |
95
|
|
|
protected $rememberPasswordToken; |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* Array which contains roles. |
99
|
|
|
* |
100
|
|
|
* @var UserRole[] |
101
|
|
|
*/ |
102
|
|
|
protected $roles; |
103
|
|
|
|
104
|
|
|
/** |
105
|
|
|
* Updated on. |
106
|
|
|
* |
107
|
|
|
* @var \DateTimeInterface |
108
|
|
|
*/ |
109
|
|
|
protected $updatedOn; |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Constructor. |
113
|
|
|
* |
114
|
|
|
* @param UserId $anId The id |
115
|
|
|
* @param UserEmail $anEmail The email |
116
|
|
|
* @param array $userRoles Array which contains the roles |
117
|
|
|
* @param UserPassword|null $aPassword The encoded password |
118
|
|
|
*/ |
119
|
|
|
protected function __construct(UserId $anId, UserEmail $anEmail, array $userRoles, UserPassword $aPassword = null) |
120
|
|
|
{ |
121
|
|
|
$this->id = $anId; |
122
|
|
|
$this->email = $anEmail; |
123
|
|
|
$this->password = $aPassword; |
124
|
|
|
$this->createdOn = new \DateTimeImmutable(); |
125
|
|
|
$this->updatedOn = new \DateTimeImmutable(); |
126
|
|
|
|
127
|
|
|
$this->roles = []; |
128
|
|
|
foreach ($userRoles as $userRole) { |
129
|
|
|
$this->grant($userRole); |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Sign up user. |
135
|
|
|
* |
136
|
|
|
* @param UserId $anId The id |
137
|
|
|
* @param UserEmail $anEmail The email |
138
|
|
|
* @param UserPassword $aPassword The encoded password |
139
|
|
|
* @param array $userRoles Array which contains the roles |
140
|
|
|
* |
141
|
|
|
* @return static |
142
|
|
|
*/ |
143
|
|
View Code Duplication |
public static function signUp(UserId $anId, UserEmail $anEmail, UserPassword $aPassword, array $userRoles) |
|
|
|
|
144
|
|
|
{ |
145
|
|
|
$user = new static($anId, $anEmail, $userRoles, $aPassword); |
146
|
|
|
$user->confirmationToken = new UserToken(); |
147
|
|
|
$user->publish( |
148
|
|
|
new UserRegistered( |
149
|
|
|
$user->id(), |
150
|
|
|
$user->email(), |
151
|
|
|
$user->confirmationToken() |
152
|
|
|
) |
153
|
|
|
); |
154
|
|
|
|
155
|
|
|
return $user; |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* Invites user. |
160
|
|
|
* |
161
|
|
|
* @param UserId $anId The id |
162
|
|
|
* @param UserEmail $anEmail The email |
163
|
|
|
* @param array $userRoles Array which contains the roles |
164
|
|
|
* |
165
|
|
|
* @return static |
166
|
|
|
*/ |
167
|
|
View Code Duplication |
public static function invite(UserId $anId, UserEmail $anEmail, array $userRoles) |
|
|
|
|
168
|
|
|
{ |
169
|
|
|
$user = new static($anId, $anEmail, $userRoles); |
170
|
|
|
$user->invitationToken = new UserToken(); |
171
|
|
|
$user->publish( |
172
|
|
|
new UserInvited( |
173
|
|
|
$user->id(), |
174
|
|
|
$user->email(), |
175
|
|
|
$user->invitationToken() |
176
|
|
|
) |
177
|
|
|
); |
178
|
|
|
|
179
|
|
|
return $user; |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Gets the id. |
184
|
|
|
* |
185
|
|
|
* @return UserId |
186
|
|
|
*/ |
187
|
|
|
public function id() |
188
|
|
|
{ |
189
|
|
|
return $this->id; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* Accepts the invitation request. |
194
|
|
|
* |
195
|
|
|
* @throws UserTokenExpiredException when the token is expired |
196
|
|
|
*/ |
197
|
|
|
public function acceptInvitation() |
198
|
|
|
{ |
199
|
|
|
if ($this->isInvitationTokenAccepted()) { |
200
|
|
|
throw new UserInvitationAlreadyAcceptedException(); |
201
|
|
|
} |
202
|
|
|
if ($this->isInvitationTokenExpired()) { |
203
|
|
|
throw new UserTokenExpiredException(); |
204
|
|
|
} |
205
|
|
|
$this->invitationToken = null; |
206
|
|
|
$this->updatedOn = new \DateTimeImmutable(); |
207
|
|
|
$this->publish( |
208
|
|
|
new UserRegistered( |
209
|
|
|
$this->id(), |
210
|
|
|
$this->email() |
211
|
|
|
) |
212
|
|
|
); |
213
|
|
|
} |
214
|
|
|
|
215
|
|
|
/** |
216
|
|
|
* Updates the user password. |
217
|
|
|
* |
218
|
|
|
* @param UserPassword $aPassword The old password |
219
|
|
|
* |
220
|
|
|
* @throws UserTokenExpiredException when the token is expired |
221
|
|
|
*/ |
222
|
|
|
public function changePassword(UserPassword $aPassword) |
223
|
|
|
{ |
224
|
|
|
$this->password = $aPassword; |
225
|
|
|
$this->rememberPasswordToken = null; |
226
|
|
|
$this->updatedOn = new \DateTimeImmutable(); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
/** |
230
|
|
|
* Gets the confirmation token. |
231
|
|
|
* |
232
|
|
|
* @return UserToken |
233
|
|
|
*/ |
234
|
|
|
public function confirmationToken() |
235
|
|
|
{ |
236
|
|
|
return $this->confirmationToken; |
237
|
|
|
} |
238
|
|
|
|
239
|
|
|
/** |
240
|
|
|
* Gets the created on. |
241
|
|
|
* |
242
|
|
|
* @return \DateTimeInterface |
243
|
|
|
*/ |
244
|
|
|
public function createdOn() |
245
|
|
|
{ |
246
|
|
|
return $this->createdOn; |
247
|
|
|
} |
248
|
|
|
|
249
|
|
|
/** |
250
|
|
|
* Gets the email. |
251
|
|
|
* |
252
|
|
|
* @return UserEmail |
253
|
|
|
*/ |
254
|
|
|
public function email() |
255
|
|
|
{ |
256
|
|
|
return $this->email; |
257
|
|
|
} |
258
|
|
|
|
259
|
|
|
/** |
260
|
|
|
* Enables the user account. |
261
|
|
|
*/ |
262
|
|
|
public function enableAccount() |
263
|
|
|
{ |
264
|
|
|
$this->confirmationToken = null; |
265
|
|
|
$this->updatedOn = new \DateTimeImmutable(); |
266
|
|
|
|
267
|
|
|
$this->publish( |
268
|
|
|
new UserEnabled( |
269
|
|
|
$this->id, |
270
|
|
|
$this->email |
271
|
|
|
) |
272
|
|
|
); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Adds the given role. |
277
|
|
|
* |
278
|
|
|
* @param UserRole $aRole The user role |
279
|
|
|
* |
280
|
|
|
* @throws UserRoleInvalidException when the user is role is invalid |
281
|
|
|
* @throws UserRoleAlreadyGrantedException when the user role is already granted |
282
|
|
|
*/ |
283
|
|
|
public function grant(UserRole $aRole) |
284
|
|
|
{ |
285
|
|
|
if (false === $this->isRoleAllowed($aRole)) { |
286
|
|
|
throw new UserRoleInvalidException(); |
287
|
|
|
} |
288
|
|
|
if (true === $this->isGranted($aRole)) { |
289
|
|
|
throw new UserRoleAlreadyGrantedException(); |
290
|
|
|
} |
291
|
|
|
$this->roles[] = $aRole; |
292
|
|
|
$this->updatedOn = new \DateTimeImmutable(); |
293
|
|
|
|
294
|
|
|
$this->publish( |
295
|
|
|
new UserRoleGranted( |
296
|
|
|
$this->id, |
297
|
|
|
$this->email, |
298
|
|
|
$aRole |
299
|
|
|
) |
300
|
|
|
); |
301
|
|
|
} |
302
|
|
|
|
303
|
|
|
/** |
304
|
|
|
* Gets the invitation token. |
305
|
|
|
* |
306
|
|
|
* @return UserToken |
307
|
|
|
*/ |
308
|
|
|
public function invitationToken() |
309
|
|
|
{ |
310
|
|
|
return $this->invitationToken; |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
/** |
314
|
|
|
* Checks if the user is enabled or not. |
315
|
|
|
* |
316
|
|
|
* @return bool |
317
|
|
|
*/ |
318
|
|
|
public function isEnabled() |
319
|
|
|
{ |
320
|
|
|
return null === $this->confirmationToken || null === $this->confirmationToken->token(); |
321
|
|
|
} |
322
|
|
|
|
323
|
|
|
/** |
324
|
|
|
* Checks if the user has the given role. |
325
|
|
|
* |
326
|
|
|
* @param UserRole $aRole The user role |
327
|
|
|
* |
328
|
|
|
* @return bool |
329
|
|
|
*/ |
330
|
|
|
public function isGranted(UserRole $aRole) |
331
|
|
|
{ |
332
|
|
|
foreach ($this->roles as $role) { |
333
|
|
|
if ($role->equals($aRole)) { |
334
|
|
|
return true; |
335
|
|
|
} |
336
|
|
|
} |
337
|
|
|
|
338
|
|
|
return false; |
339
|
|
|
} |
340
|
|
|
|
341
|
|
|
/** |
342
|
|
|
* Checks if the invitation token is accepted or not. |
343
|
|
|
* |
344
|
|
|
* @return bool |
345
|
|
|
*/ |
346
|
|
|
public function isInvitationTokenAccepted() |
347
|
|
|
{ |
348
|
|
|
return null === $this->invitationToken; |
349
|
|
|
} |
350
|
|
|
|
351
|
|
|
/** |
352
|
|
|
* Checks if the invitation token is expired or not. |
353
|
|
|
* |
354
|
|
|
* @throws UserTokenNotFoundException when the invitation token does not exist |
355
|
|
|
* |
356
|
|
|
* @return bool |
357
|
|
|
*/ |
358
|
|
|
public function isInvitationTokenExpired() |
359
|
|
|
{ |
360
|
|
|
if (!$this->invitationToken instanceof UserToken) { |
361
|
|
|
throw new UserTokenNotFoundException(); |
362
|
|
|
} |
363
|
|
|
|
364
|
|
|
return $this->invitationToken->isExpired( |
365
|
|
|
$this->invitationTokenLifetime() |
366
|
|
|
); |
367
|
|
|
} |
368
|
|
|
|
369
|
|
|
/** |
370
|
|
|
* Checks if the remember password token is expired or not. |
371
|
|
|
* |
372
|
|
|
* @throws UserTokenNotFoundException when the remember password token does not exist |
373
|
|
|
* |
374
|
|
|
* @return bool |
375
|
|
|
*/ |
376
|
|
|
public function isRememberPasswordTokenExpired() |
377
|
|
|
{ |
378
|
|
|
if (!$this->rememberPasswordToken instanceof UserToken) { |
379
|
|
|
throw new UserTokenNotFoundException(); |
380
|
|
|
} |
381
|
|
|
|
382
|
|
|
return $this->rememberPasswordToken->isExpired( |
383
|
|
|
$this->rememberPasswordTokenLifetime() |
384
|
|
|
); |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* Checks if the role given appears between allowed roles. |
389
|
|
|
* |
390
|
|
|
* @param UserRole $aRole The user role |
391
|
|
|
* |
392
|
|
|
* @return bool |
393
|
|
|
*/ |
394
|
|
|
public function isRoleAllowed(UserRole $aRole) |
395
|
|
|
{ |
396
|
|
|
return in_array($aRole->role(), static::availableRoles(), true); |
397
|
|
|
} |
398
|
|
|
|
399
|
|
|
/** |
400
|
|
|
* Gets the last login. |
401
|
|
|
* |
402
|
|
|
* @return \DateTimeInterface |
|
|
|
|
403
|
|
|
*/ |
404
|
|
|
public function lastLogin() |
405
|
|
|
{ |
406
|
|
|
return $this->lastLogin; |
407
|
|
|
} |
408
|
|
|
|
409
|
|
|
/** |
410
|
|
|
* Validates user login for the given password. |
411
|
|
|
* |
412
|
|
|
* @param string $aPlainPassword Plain password used to log in |
413
|
|
|
* @param UserPasswordEncoder $anEncoder The encoder used to encode the password |
414
|
|
|
* |
415
|
|
|
* @throws UserInactiveException when the user is not enabled |
416
|
|
|
* @throws UserPasswordInvalidException when the user password is invalid |
417
|
|
|
*/ |
418
|
|
|
public function login($aPlainPassword, UserPasswordEncoder $anEncoder) |
419
|
|
|
{ |
420
|
|
|
if (false === $this->isEnabled()) { |
421
|
|
|
throw new UserInactiveException(); |
422
|
|
|
} |
423
|
|
|
if (false === $this->password()->equals($aPlainPassword, $anEncoder)) { |
424
|
|
|
throw new UserPasswordInvalidException(); |
425
|
|
|
} |
426
|
|
|
$this->lastLogin = new \DateTimeImmutable(); |
427
|
|
|
|
428
|
|
|
$this->publish( |
429
|
|
|
new UserLoggedIn( |
430
|
|
|
$this->id, |
431
|
|
|
$this->email |
432
|
|
|
) |
433
|
|
|
); |
434
|
|
|
} |
435
|
|
|
|
436
|
|
|
/** |
437
|
|
|
* Updated the user state after logout. |
438
|
|
|
* |
439
|
|
|
* @throws UserInactiveException when the user is not enabled |
440
|
|
|
*/ |
441
|
|
|
public function logout() |
442
|
|
|
{ |
443
|
|
|
if (false === $this->isEnabled()) { |
444
|
|
|
throw new UserInactiveException(); |
445
|
|
|
} |
446
|
|
|
|
447
|
|
|
$this->publish( |
448
|
|
|
new UserLoggedOut( |
449
|
|
|
$this->id, |
450
|
|
|
$this->email |
451
|
|
|
) |
452
|
|
|
); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
|
/** |
456
|
|
|
* Gets the password. |
457
|
|
|
* |
458
|
|
|
* @return UserPassword |
459
|
|
|
*/ |
460
|
|
|
public function password() |
461
|
|
|
{ |
462
|
|
|
return $this->password; |
463
|
|
|
} |
464
|
|
|
|
465
|
|
|
/** |
466
|
|
|
* Updates the invitation token in case a user has |
467
|
|
|
* been already invited and has lost the token. |
468
|
|
|
* |
469
|
|
|
* @throws UserInvitationAlreadyAcceptedException in case user has already accepted the invitation |
470
|
|
|
*/ |
471
|
|
|
public function regenerateInvitationToken() |
472
|
|
|
{ |
473
|
|
|
if (null === $this->invitationToken) { |
474
|
|
|
throw new UserInvitationAlreadyAcceptedException(); |
475
|
|
|
} |
476
|
|
|
$this->invitationToken = new UserToken(); |
477
|
|
|
|
478
|
|
|
$this->publish( |
479
|
|
|
new UserInvitationTokenRegenerated( |
480
|
|
|
$this->id, |
481
|
|
|
$this->email, |
482
|
|
|
$this->invitationToken |
483
|
|
|
) |
484
|
|
|
); |
485
|
|
|
} |
486
|
|
|
|
487
|
|
|
/** |
488
|
|
|
* Gets the remember password token. |
489
|
|
|
* |
490
|
|
|
* @return UserToken |
491
|
|
|
*/ |
492
|
|
|
public function rememberPasswordToken() |
493
|
|
|
{ |
494
|
|
|
return $this->rememberPasswordToken; |
495
|
|
|
} |
496
|
|
|
|
497
|
|
|
/** |
498
|
|
|
* Remembers the password. |
499
|
|
|
*/ |
500
|
|
|
public function rememberPassword() |
501
|
|
|
{ |
502
|
|
|
$this->rememberPasswordToken = new UserToken(); |
503
|
|
|
|
504
|
|
|
$this->publish( |
505
|
|
|
new UserRememberPasswordRequested( |
506
|
|
|
$this->id, |
507
|
|
|
$this->email, |
508
|
|
|
$this->rememberPasswordToken |
509
|
|
|
) |
510
|
|
|
); |
511
|
|
|
} |
512
|
|
|
|
513
|
|
|
/** |
514
|
|
|
* Removes the given role. |
515
|
|
|
* |
516
|
|
|
* @param UserRole $aRole The user role |
517
|
|
|
* |
518
|
|
|
* @throws UserRoleInvalidException when the role is invalid |
519
|
|
|
* @throws UserRoleAlreadyRevokedException when the role is already revoked |
520
|
|
|
*/ |
521
|
|
|
public function revoke(UserRole $aRole) |
522
|
|
|
{ |
523
|
|
|
if (false === $this->isRoleAllowed($aRole)) { |
524
|
|
|
throw new UserRoleInvalidException(); |
525
|
|
|
} |
526
|
|
|
foreach ($this->roles as $key => $role) { |
527
|
|
|
if ($role->equals($aRole)) { |
528
|
|
|
unset($this->roles[$key]); |
529
|
|
|
$this->roles = array_values($this->roles); |
530
|
|
|
break; |
531
|
|
|
} |
532
|
|
|
throw new UserRoleAlreadyRevokedException(); |
533
|
|
|
} |
534
|
|
|
$this->updatedOn = new \DateTimeImmutable(); |
535
|
|
|
$this->publish( |
536
|
|
|
new UserRoleRevoked( |
537
|
|
|
$this->id, |
538
|
|
|
$this->email, |
539
|
|
|
$aRole |
540
|
|
|
) |
541
|
|
|
); |
542
|
|
|
} |
543
|
|
|
|
544
|
|
|
/** |
545
|
|
|
* Gets the roles. |
546
|
|
|
* |
547
|
|
|
* @return UserRole[] |
548
|
|
|
*/ |
549
|
|
|
public function roles() |
550
|
|
|
{ |
551
|
|
|
return $this->roles; |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* Gets the updated on. |
556
|
|
|
* |
557
|
|
|
* @return \DateTimeInterface |
558
|
|
|
*/ |
559
|
|
|
public function updatedOn() |
560
|
|
|
{ |
561
|
|
|
return $this->updatedOn; |
562
|
|
|
} |
563
|
|
|
|
564
|
|
|
/** |
565
|
|
|
* Gets the available roles in scalar type. |
566
|
|
|
* |
567
|
|
|
* This method is an extension point that it allows |
568
|
|
|
* to add more roles easily in the domain. |
569
|
|
|
* |
570
|
|
|
* @return array |
|
|
|
|
571
|
|
|
*/ |
572
|
|
|
public static function availableRoles() |
573
|
|
|
{ |
574
|
|
|
return ['ROLE_USER', 'ROLE_ADMIN']; |
575
|
|
|
} |
576
|
|
|
|
577
|
|
|
/** |
578
|
|
|
* Extension point that determines the lifetime |
579
|
|
|
* of the invitation token in seconds. |
580
|
|
|
* |
581
|
|
|
* @return int |
582
|
|
|
*/ |
583
|
|
|
protected function invitationTokenLifetime() |
584
|
|
|
{ |
585
|
|
|
return 604800; // 1 week |
586
|
|
|
} |
587
|
|
|
|
588
|
|
|
/** |
589
|
|
|
* Extension point that determines the lifetime |
590
|
|
|
* of the remember password token in seconds. |
591
|
|
|
* |
592
|
|
|
* @return int |
593
|
|
|
*/ |
594
|
|
|
protected function rememberPasswordTokenLifetime() |
595
|
|
|
{ |
596
|
|
|
return 3600; // 1 hour |
597
|
|
|
} |
598
|
|
|
} |
599
|
|
|
|
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.