Passed
Push — master ( 8116cf...9d59f1 )
by Adrien
06:29
created

User::setAccount()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 4.0218

Importance

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