Failed Conditions
Push — master ( 4252f4...9d8e13 )
by Adrien
07:13
created

User::getFamilyRelationship()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 3
ccs 2
cts 2
cp 1
crap 1
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\Acl\Acl;
8
use Application\Api\Exception;
9
use Application\DBAL\Types\BillingTypeType;
10
use Application\DBAL\Types\RelationshipType;
11
use Application\ORM\Query\Filter\AclFilter;
12
use Application\Traits\HasAddress;
13
use Application\Traits\HasDoorAccess;
14
use Application\Traits\HasRemarks;
15
use Application\Utility;
16
use Cake\Chronos\Chronos;
17
use Cake\Chronos\Date;
18
use Doctrine\Common\Collections\ArrayCollection;
19
use Doctrine\Common\Collections\Collection;
20
use Doctrine\ORM\Mapping as ORM;
21
use GraphQL\Doctrine\Annotation as API;
22
23
/**
24
 * User
25
 *
26
 * @ORM\Entity(repositoryClass="Application\Repository\UserRepository")
27
 * @ORM\AssociationOverrides({
28
 *     @ORM\AssociationOverride(name="owner", inversedBy="users")
29
 * })
30
 */
31
class User extends AbstractModel
32
{
33
    const ROLE_ANONYMOUS = 'anonymous';
34
    const ROLE_BOOKING_ONLY = 'booking_only';
35
    const ROLE_INDIVIDUAL = 'individual';
36
    const ROLE_MEMBER = 'member';
37
    const ROLE_RESPONSIBLE = 'responsible';
38
    const ROLE_ADMINISTRATOR = 'administrator';
39
40
    const STATUS_INACTIVE = 'inactive';
41
    const STATUS_NEW = 'new';
42
    const STATUS_ACTIVE = 'active';
43
    const STATUS_ARCHIVED = 'archived';
44
45
    use HasDoorAccess;
46
    use HasRemarks;
47
    use HasAddress;
48
49
    /**
50
     * @var User
51
     */
52
    private static $currentUser;
53
54
    /**
55
     * Set currently logged in user
56
     * WARNING: this method should only be called from \Application\Authentication\AuthenticationListener
57
     *
58
     * @param \Application\Model\User $user
59
     */
60 54
    public static function setCurrent(?self $user): void
61
    {
62 54
        self::$currentUser = $user;
63
64
        // Initalize ACL filter with current user if a logged in one exists
65 54
        _em()->getFilters()->getFilter(AclFilter::class)->setUser($user);
66 54
    }
67
68
    /**
69
     * Returns currently logged user or null
70
     *
71
     * @return null|self
72
     */
73 42
    public static function getCurrent(): ?self
74
    {
75 42
        return self::$currentUser;
76
    }
77
78
    /**
79
     * @var string
80
     *
81
     * @ORM\Column(type="string", length=50, unique=true)
82
     */
83
    private $login;
84
85
    /**
86
     * @var string
87
     * @ORM\Column(type="string", length=191)
88
     */
89
    private $firstName;
90
91
    /**
92
     * @var string
93
     * @ORM\Column(type="string", length=191)
94
     */
95
    private $lastName;
96
97
    /**
98
     * @var null|string
99
     *
100
     * @ORM\Column(type="string", length=255)
101
     */
102
    private $password;
103
104
    /**
105
     * @var null|string
106
     * @ORM\Column(type="string", length=191, nullable=true, unique=true)
107
     */
108
    private $email;
109
110
    /**
111
     * @var string
112
     * @ORM\Column(type="UserRole", options={"default" = User::ROLE_INDIVIDUAL})
113
     */
114
    private $role = self::ROLE_INDIVIDUAL;
115
116
    /**
117
     * @var string
118
     * @ORM\Column(type="UserStatus", options={"default" = User::STATUS_NEW})
119
     */
120
    private $status = self::STATUS_NEW;
121
122
    /**
123
     * @var null|Chronos
124
     * @ORM\Column(type="datetime", nullable=true)
125
     */
126
    private $lastLogin;
127
128
    /**
129
     * @var null|Chronos
130
     * @ORM\Column(type="datetime", nullable=true)
131
     */
132
    private $welcomeSessionDate;
133
134
    /**
135
     * @var int sex according to ISO/IEC 5218
136
     * @ORM\Column(type="smallint", options={"default" = 0}))
137
     */
138
    private $sex = 0;
139
140
    /**
141
     * @var string
142
     * @ORM\Column(type="string", length=25, options={"default" = ""})
143
     */
144
    private $phone = '';
145
146
    /**
147
     * @var string
148
     * @ORM\Column(type="string", length=25, options={"default" = ""})
149
     */
150
    private $mobilePhone = '';
151
152
    /**
153
     * @var string
154
     * @ORM\Column(type="string", length=25, options={"default" = ""})
155
     */
156
    private $ichtusSwissSailing = '';
157
158
    /**
159
     * @var null|Date
160
     * @ORM\Column(type="date", nullable=true)
161
     */
162
    private $birthday;
163
164
    /**
165
     * @var bool
166
     * @ORM\Column(type="boolean", options={"default" = 0})
167
     */
168
    private $termsAgreement = false;
169
170
    /**
171
     * @var bool
172
     * @ORM\Column(type="boolean", options={"default" = 0})
173
     */
174
    private $hasInsurance = false;
175
176
    /**
177
     * @var bool
178
     * @ORM\Column(type="boolean", options={"default" = 0})
179
     */
180
    private $receivesNewsletter = false;
181
182
    /**
183
     * @var string
184
     * @ORM\Column(type="Relationship", options={"default" = RelationshipType::HOUSEHOLDER})
185
     */
186
    private $familyRelationship = RelationshipType::HOUSEHOLDER;
187
188
    /**
189
     * @var string
190
     * @ORM\Column(type="BillingType", options={"default" = BillingTypeType::ALL_ELECTRONIC})
191
     */
192
    private $billingType = BillingTypeType::ALL_ELECTRONIC;
193
194
    /**
195
     * @var null|string
196
     * @ORM\Column(type="string", length=32, nullable=true, unique=true)
197
     */
198
    private $token;
199
200
    /**
201
     * @var null|Chronos
202
     *
203
     * @ORM\Column(type="datetime", nullable=true)
204
     */
205
    private $tokenCreationDate;
206
207
    /**
208
     * @var Collection
209
     * @ORM\OneToMany(targetEntity="Booking", mappedBy="owner")
210
     */
211
    private $bookings;
212
213
    /**
214
     * @var Collection
215
     * @ORM\ManyToMany(targetEntity="License", mappedBy="users")
216
     */
217
    private $licenses;
218
219
    /**
220
     * @var Collection
221
     * @ORM\ManyToMany(targetEntity="UserTag", mappedBy="users")
222
     */
223
    private $userTags;
224
225
    /**
226
     * @var Collection
227
     * @ORM\OneToMany(targetEntity="Message", mappedBy="recipient")
228
     */
229
    private $messages;
230
231
    /**
232
     * There is actually 0 to 1 account, never more. And this is
233
     * enforced by DB unique constraints
234
     *
235
     * @var Collection
236
     * @ORM\OneToMany(targetEntity="Account", mappedBy="owner")
237
     */
238
    private $accounts;
239
240
    /**
241
     * @var Collection
242
     * @ORM\OneToMany(targetEntity="User", mappedBy="owner")
243
     */
244
    private $users;
245
246
    /**
247
     * Constructor
248
     *
249
     * @param string $role role for new user
250
     */
251 27
    public function __construct(string $role = self::ROLE_INDIVIDUAL)
252
    {
253 27
        $this->role = $role;
254 27
        $this->bookings = new ArrayCollection();
255 27
        $this->accounts = new ArrayCollection();
256 27
        $this->licenses = new ArrayCollection();
257 27
        $this->userTags = new ArrayCollection();
258 27
        $this->messages = new ArrayCollection();
259 27
        $this->users = new ArrayCollection();
260 27
    }
261
262
    /**
263
     * Set login (eg: johndoe)
264
     *
265
     * @API\Input(type="Application\Api\Scalar\LoginType")
266
     *
267
     * @param string $login
268
     */
269 1
    public function setLogin(string $login): void
270
    {
271 1
        $this->login = $login;
272 1
    }
273
274
    /**
275
     * Get login (eg: johndoe)
276
     *
277
     * @API\Field(type="Application\Api\Scalar\LoginType")
278
     *
279
     * @return string
280
     */
281 12
    public function getLogin(): string
282
    {
283 12
        return (string) $this->login;
284
    }
285
286
    /**
287
     * Hash and change the user password
288
     *
289
     * @API\Exclude
290
     *
291
     * @param string $password
292
     */
293 5
    public function setPassword(string $password): void
294
    {
295 5
        $this->revokeToken();
296
297 5
        $this->password = password_hash($password, PASSWORD_DEFAULT);
298 5
    }
299
300
    /**
301
     * Returns the hashed password
302
     *
303
     * @API\Exclude
304
     *
305
     * @return null|string
306
     */
307 3
    public function getPassword(): ?string
308
    {
309 3
        return $this->password;
310
    }
311
312
    /**
313
     * Set first name
314
     *
315
     * @param string $firstName
316
     */
317 1
    public function setFirstName($firstName): void
318
    {
319 1
        $this->firstName = $firstName;
320 1
    }
321
322
    /**
323
     * Get first name
324
     *
325
     * @return string
326
     */
327 3
    public function getFirstName(): string
328
    {
329 3
        return (string) $this->firstName;
330
    }
331
332
    /**
333
     * Set last name
334
     *
335
     * @param string $lastName
336
     */
337 1
    public function setLastName($lastName): void
338
    {
339 1
        $this->lastName = $lastName;
340 1
    }
341
342
    /**
343
     * Get last name
344
     *
345
     * @return string
346
     */
347 1
    public function getLastName(): string
348
    {
349 1
        return (string) $this->lastName;
350
    }
351
352
    /**
353
     * Get full name
354
     *
355
     * @return string
356
     */
357 1
    public function getName(): string
358
    {
359 1
        return implode(' ', [$this->getFirstName(), $this->getLastName()]);
360
    }
361
362
    /**
363
     * Set email
364
     *
365
     * @API\Input(type="?Email")
366
     *
367
     * @param string $email
368
     */
369 2
    public function setEmail(string $email): void
370
    {
371 2
        $this->email = $email;
372 2
    }
373
374
    /**
375
     * Get email
376
     *
377
     * @API\Field(type="?Email")
378
     *
379
     * @return null|string
380
     */
381 4
    public function getEmail(): ?string
382
    {
383 4
        return $this->email;
384
    }
385
386
    /**
387
     * Returns whether the user is administrator and thus have can do anything.
388
     *
389
     * @API\Field(type="Application\Api\Enum\UserRoleType")
390
     */
391 30
    public function getRole(): string
392
    {
393 30
        return $this->role;
394
    }
395
396
    /**
397
     * Sets the user role
398
     *
399
     * The current user is allowed to promote another user up to the same role as himself. So
400
     * a Senior can promote a Student to Senior. Or an Admin can promote a Junior to Admin.
401
     *
402
     * But the current user is **not** allowed to demote a user who has a higher role than himself.
403
     * That means that a Senior cannot demote an Admin to Student.
404
     *
405
     * @param string $role
406
     */
407 7
    public function setRole(string $role): void
408
    {
409 7
        if ($role === $this->role) {
410 2
            return;
411
        }
412
413 5
        $currentRole = self::getCurrent() ? self::getCurrent()->getRole() : self::ROLE_ANONYMOUS;
414
        $orderedRoles = [
415 5
            self::ROLE_ANONYMOUS,
416 5
            self::ROLE_INDIVIDUAL,
417 5
            self::ROLE_MEMBER,
418 5
            self::ROLE_RESPONSIBLE,
419 5
            self::ROLE_ADMINISTRATOR,
420
        ];
421
422 5
        $newFound = false;
423 5
        $oldFound = false;
424 5
        foreach ($orderedRoles as $r) {
425 5
            if ($r === $this->role) {
426 3
                $oldFound = true;
427
            }
428 5
            if ($r === $role) {
429 2
                $newFound = true;
430
            }
431
432 5
            if ($r === $currentRole) {
433 5
                break;
434
            }
435
        }
436
437 5
        if (!$newFound || !$oldFound) {
438 3
            throw new Exception($currentRole . ' is not allowed to change role to ' . $role);
439
        }
440
441 2
        $this->role = $role;
442 2
    }
443
444 4
    public function setOwner(self $owner = null): void
445
    {
446 4
        if ($owner && $owner !== $this) {
447 4
            if ($owner->getOwner() && $owner !== $owner->getOwner()) {
448 1
                throw new Exception('This user cannot be owned by a user who is himself owned by somebody else');
449
            }
450
451 4
            if ($this->users->count()) {
452 1
                throw new Exception('This user owns other users, so he cannot himself be owned by somebody else');
453
            }
454
        }
455
456 4
        if ($this->getOwner()) {
457
            $this->getOwner()->users->removeElement($this);
458
        }
459
460 4
        parent::setOwner($owner);
461
462 4
        if ($this->getOwner()) {
463 4
            $this->getOwner()->users->add($this);
464 4
            $this->setStatus($this->getOwner()->getStatus());
465
        }
466 4
    }
467
468
    /**
469
     * @API\Field(type="Application\Api\Enum\UserStatusType")
470
     *
471
     * @return string
472
     */
473 4
    public function getStatus(): string
474
    {
475 4
        return $this->status;
476
    }
477
478
    /**
479
     * @API\Input(type="Application\Api\Enum\UserStatusType")
480
     *
481
     * @param string $status
482
     */
483 5
    public function setStatus(string $status): void
484
    {
485 5
        $this->status = $status;
486 5
        $this->revokeToken();
487
488 5
        foreach ($this->users as $user) {
489 3
            if ($user !== $this) {
490 1
                $user->setStatus($status);
491
            }
492
        }
493 5
    }
494
495
    /**
496
     * Get a list of global permissions for this user
497
     *
498
     * @API\Field(type="GlobalPermissionsList")
499
     *
500
     * @return array
501
     */
502 3
    public function getGlobalPermissions(): array
503
    {
504 3
        $acl = new Acl();
505
        $types = [
506 3
            Account::class,
507
            AccountingDocument::class,
508
            Bookable::class,
509
            BookableMetadata::class,
510
            BookableTag::class,
511
            Booking::class,
512
            Category::class,
513
            Country::class,
514
            ExpenseClaim::class,
515
            Image::class,
516
            License::class,
517
            Message::class,
518
            self::class,
519
            UserTag::class,
520
        ];
521
522 3
        $permissions = ['create'];
523 3
        $result = [];
524
525 3
        $previousUser = self::getCurrent();
526 3
        self::setCurrent($this);
527 3
        foreach ($types as $type) {
528 3
            $instance = new $type();
529
530 3
            if ($instance instanceof AccountingDocument) {
531 3
                $instance->setExpenseClaim(new ExpenseClaim());
532
            }
533
534 3
            $sh = lcfirst(Utility::getShortClassName($instance));
535 3
            $result[$sh] = [];
536
537 3
            foreach ($permissions as $p) {
538 3
                $result[$sh][$p] = $acl->isCurrentUserAllowed($instance, $p);
539
            }
540
        }
541
542 3
        self::setCurrent($previousUser);
543
544 3
        return $result;
545
    }
546
547
    /**
548
     * @return string
549
     */
550
    public function getPhone(): string
551
    {
552
        return $this->phone;
553
    }
554
555
    /**
556
     * @param string $phone
557
     */
558
    public function setPhone(string $phone): void
559
    {
560
        $this->phone = $phone;
561
    }
562
563
    /**
564
     * @return string
565
     */
566
    public function getMobilePhone(): string
567
    {
568
        return $this->mobilePhone;
569
    }
570
571
    /**
572
     * @param string $mobilePhone
573
     */
574
    public function setMobilePhone(string $mobilePhone): void
575
    {
576
        $this->mobilePhone = $mobilePhone;
577
    }
578
579
    /**
580
     * @return null|Date
581
     */
582
    public function getBirthday(): ?Date
583
    {
584
        return $this->birthday;
585
    }
586
587
    /**
588
     * @param null|Date $birthday
589
     */
590
    public function setBirthday(?Date $birthday): void
591
    {
592
        $this->birthday = $birthday;
593
    }
594
595
    /**
596
     * Get bookings
597
     *
598
     * @return Collection
599
     */
600 1
    public function getBookings(): Collection
601
    {
602 1
        return $this->bookings;
603
    }
604
605
    /**
606
     * Notify the user that it has a new booking.
607
     * This should only be called by Booking::setResponsible()
608
     *
609
     * @param Booking $booking
610
     */
611 7
    public function bookingAdded(Booking $booking): void
612
    {
613 7
        $this->bookings->add($booking);
614 7
    }
615
616
    /**
617
     * Notify the user that it has a booking was removed.
618
     * This should only be called by Booking::setResponsible()
619
     *
620
     * @param Booking $booking
621
     */
622 3
    public function bookingRemoved(Booking $booking): void
623
    {
624 3
        $this->bookings->removeElement($booking);
625 3
    }
626
627
    /**
628
     * @return Collection
629
     */
630 1
    public function getLicenses(): Collection
631
    {
632 1
        return $this->licenses;
633
    }
634
635
    /**
636
     * @return Collection
637
     */
638 1
    public function getUserTags(): Collection
639
    {
640 1
        return $this->userTags;
641
    }
642
643
    /**
644
     * Notify the user that it has a new license.
645
     * This should only be called by License::addUser()
646
     *
647
     * @param License $license
648
     */
649 1
    public function licenseAdded(License $license): void
650
    {
651 1
        $this->licenses->add($license);
652 1
    }
653
654
    /**
655
     * Notify the user that it a license was removed.
656
     * This should only be called by License::removeUser()
657
     *
658
     * @param License $license
659
     */
660 1
    public function licenseRemoved(License $license): void
661
    {
662 1
        $this->licenses->removeElement($license);
663 1
    }
664
665
    /**
666
     * Notify the user that it has a new userTag.
667
     * This should only be called by UserTag::addUser()
668
     *
669
     * @param UserTag $userTag
670
     */
671 1
    public function userTagAdded(UserTag $userTag): void
672
    {
673 1
        $this->userTags->add($userTag);
674 1
    }
675
676
    /**
677
     * Notify the user that a userTag was removed.
678
     * This should only be called by UserTag::removeUser()
679
     *
680
     * @param UserTag $userTag
681
     */
682 1
    public function userTagRemoved(UserTag $userTag): void
683
    {
684 1
        $this->userTags->removeElement($userTag);
685 1
    }
686
687
    /**
688
     * @return bool
689
     */
690
    public function isTermsAgreement(): bool
691
    {
692
        return $this->termsAgreement;
693
    }
694
695
    /**
696
     * @param bool $termsAgreement
697
     */
698
    public function setTermsAgreement(bool $termsAgreement): void
699
    {
700
        $this->termsAgreement = $termsAgreement;
701
    }
702
703
    /**
704
     * @return bool
705
     */
706
    public function getHasInsurance(): bool
707
    {
708
        return $this->hasInsurance;
709
    }
710
711
    /**
712
     * @param bool $hasInsurance
713
     */
714
    public function setHasInsurance(bool $hasInsurance): void
715
    {
716
        $this->hasInsurance = $hasInsurance;
717
    }
718
719
    /**
720
     * @return null|Chronos
721
     */
722
    public function getWelcomeSessionDate(): ?Chronos
723
    {
724
        return $this->welcomeSessionDate;
725
    }
726
727
    /**
728
     * @param null|Chronos $welcomeSessionDate
729
     */
730
    public function setWelcomeSessionDate(?Chronos $welcomeSessionDate): void
731
    {
732
        $this->welcomeSessionDate = $welcomeSessionDate;
733
    }
734
735
    /**
736
     * @return bool
737
     */
738
    public function isReceivesNewsletter(): bool
739
    {
740
        return $this->receivesNewsletter;
741
    }
742
743
    /**
744
     * @param bool $receivesNewsletter
745
     */
746
    public function setReceivesNewsletter(bool $receivesNewsletter): void
747
    {
748
        $this->receivesNewsletter = $receivesNewsletter;
749
    }
750
751
    /**
752
     * Get the ISO/IEC 5218 sex
753
     *
754
     * @API\Field(type="Sex")
755
     *
756
     * @return int
757
     */
758
    public function getSex(): int
759
    {
760
        return $this->sex;
761
    }
762
763
    /**
764
     * Set the ISO/IEC 5218 sex
765
     *
766
     * @API\Input(type="Sex")
767
     *
768
     * @param int $sex
769
     */
770
    public function setSex(int $sex): void
771
    {
772
        $this->sex = $sex;
773
    }
774
775
    /**
776
     * @return string
777
     */
778
    public function getIchtusSwissSailing(): string
779
    {
780
        return $this->ichtusSwissSailing;
781
    }
782
783
    /**
784
     * @param string $ichtusSwissSailing
785
     */
786
    public function setIchtusSwissSailing(string $ichtusSwissSailing): void
787
    {
788
        $this->ichtusSwissSailing = $ichtusSwissSailing;
789
    }
790
791
    /**
792
     * Get the last login
793
     *
794
     * @return null|Chronos
795
     */
796
    public function getLastLogin(): ?Chronos
797
    {
798
        return $this->lastLogin;
799
    }
800
801
    /**
802
     * @param null|Chronos $lastLogin
803
     */
804 3
    public function setLastLogin(?Chronos $lastLogin): void
805
    {
806 3
        $this->lastLogin = $lastLogin;
807 3
        $this->revokeToken();
808 3
    }
809
810
    /**
811
     * @API\Field(type="Relationship")
812
     *
813
     * @return string
814
     */
815 1
    public function getFamilyRelationship(): string
816
    {
817 1
        return $this->familyRelationship;
818
    }
819
820
    /**
821
     * @API\Input(type="Relationship")
822
     *
823
     * @param string $familyRelationship
824
     */
825
    public function setFamilyRelationship(string $familyRelationship): void
826
    {
827
        $this->familyRelationship = $familyRelationship;
828
    }
829
830
    /**
831
     * @return string
832
     */
833
    public function getBillingType(): string
834
    {
835
        return $this->billingType;
836
    }
837
838
    /**
839
     * @param string $billingType
840
     */
841
    public function setBillingType(string $billingType): void
842
    {
843
        $this->billingType = $billingType;
844
    }
845
846
    /**
847
     * Get the user transaction account
848
     *
849
     * @return null|Account
850
     */
851 1
    public function getAccount(): ?Account
852
    {
853 1
        return $this->accounts->count() ? $this->accounts->first() : null;
854
    }
855
856
    /**
857
     * Notify the user that it has a new account
858
     * This should only be called by Account::setOwner()
859
     *
860
     * @param Account $account
861
     */
862 1
    public function accountAdded(Account $account): void
863
    {
864 1
        $this->accounts->clear();
865 1
        $this->accounts->add($account);
866 1
    }
867
868
    /**
869
     * Notify the user that a account was removed
870
     * This should only be called by Account::setOwner()
871
     */
872 1
    public function accountRemoved(): void
873
    {
874 1
        $this->accounts->clear();
875 1
    }
876
877
    /**
878
     * Get messages sent to the user
879
     *
880
     * @return Collection
881
     */
882 1
    public function getMessages(): Collection
883
    {
884 1
        return $this->messages;
885
    }
886
887
    /**
888
     * Notify the user that it has a new message
889
     * This should only be called by Message::setRecipient()
890
     *
891
     * @param Message $message
892
     */
893 3
    public function messageAdded(Message $message): void
894
    {
895 3
        $this->messages->add($message);
896 3
    }
897
898
    /**
899
     * Notify the user that a message was removed
900
     * This should only be called by Message::setRecipient()
901
     *
902
     * @param Message $message
903
     */
904 1
    public function messageRemoved(Message $message): void
905
    {
906 1
        $this->messages->removeElement($message);
907 1
    }
908
909
    /**
910
     * Generate a new random token to reset password
911
     */
912 3
    public function createToken(): string
913
    {
914 3
        $this->token = bin2hex(random_bytes(16));
915 3
        $this->tokenCreationDate = new Chronos();
916
917 3
        return $this->token;
918
    }
919
920
    /**
921
     * Destroy existing token
922
     */
923 9
    private function revokeToken(): void
924
    {
925 9
        $this->token = null;
926 9
        $this->tokenCreationDate = null;
927 9
    }
928
929
    /**
930
     * Check if token is valid.
931
     *
932
     * @API\Exclude
933
     *
934
     * @return bool
935
     */
936 2
    public function isTokenValid(): bool
937
    {
938 2
        if (!$this->tokenCreationDate) {
939 1
            return false;
940
        }
941
942 2
        $timeLimit = $this->tokenCreationDate->addMinutes(30);
943
944 2
        return $timeLimit->isFuture();
945
    }
946
}
947