User::initialize()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 3
cts 3
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\Api\Enum\SexType;
8
use Application\Api\Enum\UserRoleType;
9
use Application\Api\Input\Operator\AccountBalance\AccountBalanceEqualOperatorType;
10
use Application\Api\Input\Operator\AccountBalance\AccountBalanceGreaterOperatorType;
11
use Application\Api\Input\Operator\AccountBalance\AccountBalanceGreaterOrEqualOperatorType;
12
use Application\Api\Input\Operator\AccountBalance\AccountBalanceLessOperatorType;
13
use Application\Api\Input\Operator\AccountBalance\AccountBalanceLessOrEqualOperatorType;
14
use Application\Api\Input\Operator\BookingCount\BookingCountEqualOperatorType;
15
use Application\Api\Input\Operator\BookingCount\BookingCountGreaterOperatorType;
16
use Application\Api\Input\Operator\BookingCount\BookingCountGreaterOrEqualOperatorType;
17
use Application\Api\Input\Operator\BookingCount\BookingCountLessOperatorType;
18
use Application\Api\Input\Operator\BookingCount\BookingCountLessOrEqualOperatorType;
19
use Application\Api\Input\Operator\BookingDate\BookingDateEqualOperatorType;
20
use Application\Api\Input\Operator\BookingDate\BookingDateGreaterOperatorType;
21
use Application\Api\Input\Operator\BookingDate\BookingDateGreaterOrEqualOperatorType;
22
use Application\Api\Input\Operator\BookingDate\BookingDateLessOperatorType;
23
use Application\Api\Input\Operator\BookingDate\BookingDateLessOrEqualOperatorType;
24
use Application\Api\Input\Operator\HasBookingCompletedOperatorType;
25
use Application\Api\Input\Operator\HasBookingStatusOperatorType;
26
use Application\Api\Input\Operator\HasBookingWithBookableOperatorType;
27
use Application\Api\Input\Operator\HasBookingWithTaggedBookableOperatorType;
28
use Application\Api\Input\Sorting\Age;
29
use Application\Api\Input\Sorting\Balance;
30
use Application\Enum\BillingType;
31
use Application\Enum\BookingStatus;
32
use Application\Enum\Door;
33
use Application\Enum\Relationship;
34
use Application\Enum\SwissSailingType;
35
use Application\Enum\SwissWindsurfType;
36
use Application\Enum\UserStatus;
37
use Application\Repository\LogRepository;
38
use Application\Repository\UserRepository;
39
use Application\Service\Role;
40
use Application\Traits\HasAddress;
41
use Application\Traits\HasDoorAccess;
42
use Application\Traits\HasIban;
43
use Application\Traits\HasRemarks;
44
use Cake\Chronos\Chronos;
45
use Cake\Chronos\ChronosDate;
46
use Doctrine\Common\Collections\ArrayCollection;
47
use Doctrine\Common\Collections\Collection;
48
use Doctrine\Common\Collections\ReadableCollection;
49
use Doctrine\ORM\Mapping as ORM;
50
use Ecodev\Felix\Api\Exception;
51
use Ecodev\Felix\Api\Scalar\LoginType;
52
use Ecodev\Felix\Model\CurrentUser;
53
use Ecodev\Felix\Model\Traits\HasInternalRemarks;
54
use Ecodev\Felix\Model\Traits\HasPassword;
55
use GraphQL\Doctrine\Attribute as API;
56
57
/**
58
 * User.
59
 */
60
#[API\Sorting(Age::class)]
61
#[API\Sorting(Balance::class)]
62
#[API\Filter(field: 'custom', operator: HasBookingWithTaggedBookableOperatorType::class, type: 'id')]
63
#[API\Filter(field: 'custom', operator: HasBookingWithBookableOperatorType::class, type: 'id')]
64
#[API\Filter(field: 'custom', operator: HasBookingStatusOperatorType::class, type: 'id')]
65
#[API\Filter(field: 'custom', operator: HasBookingCompletedOperatorType::class, type: 'boolean')]
66
#[API\Filter(field: 'bookingCount', operator: BookingCountEqualOperatorType::class, type: 'int')]
67
#[API\Filter(field: 'bookingCount', operator: BookingCountGreaterOperatorType::class, type: 'int')]
68
#[API\Filter(field: 'bookingCount', operator: BookingCountGreaterOrEqualOperatorType::class, type: 'int')]
69
#[API\Filter(field: 'bookingCount', operator: BookingCountLessOperatorType::class, type: 'int')]
70
#[API\Filter(field: 'bookingCount', operator: BookingCountLessOrEqualOperatorType::class, type: 'int')]
71
#[API\Filter(field: 'accountBalance', operator: AccountBalanceEqualOperatorType::class, type: 'Money')]
72
#[API\Filter(field: 'accountBalance', operator: AccountBalanceGreaterOperatorType::class, type: 'Money')]
73
#[API\Filter(field: 'accountBalance', operator: AccountBalanceGreaterOrEqualOperatorType::class, type: 'Money')]
74
#[API\Filter(field: 'accountBalance', operator: AccountBalanceLessOperatorType::class, type: 'Money')]
75
#[API\Filter(field: 'accountBalance', operator: AccountBalanceLessOrEqualOperatorType::class, type: 'Money')]
76
#[API\Filter(field: 'bookingDate', operator: BookingDateEqualOperatorType::class, type: 'Date')]
77
#[API\Filter(field: 'bookingDate', operator: BookingDateGreaterOperatorType::class, type: 'Date')]
78
#[API\Filter(field: 'bookingDate', operator: BookingDateGreaterOrEqualOperatorType::class, type: 'Date')]
79
#[API\Filter(field: 'bookingDate', operator: BookingDateLessOperatorType::class, type: 'Date')]
80
#[API\Filter(field: 'bookingDate', operator: BookingDateLessOrEqualOperatorType::class, type: 'Date')]
81
#[ORM\Entity(UserRepository::class)]
82
#[ORM\HasLifecycleCallbacks]
83
#[ORM\AssociationOverrides([new ORM\AssociationOverride(name: 'owner', inversedBy: 'users')])]
84
class User extends AbstractModel implements \Ecodev\Felix\Model\User
85
{
86
    final public const ROLE_ANONYMOUS = 'anonymous';
87
    final public const ROLE_BOOKING_ONLY = 'booking_only';
88
    final public const ROLE_INDIVIDUAL = 'individual';
89
    final public const ROLE_ACCOUNTING_VERIFICATOR = 'accounting_verificator';
90
    final public const ROLE_MEMBER = 'member';
91
    final public const ROLE_TRAINER = 'trainer';
92
    final public const ROLE_FORMATION_RESPONSIBLE = 'formation_responsible';
93
    final public const ROLE_RESPONSIBLE = 'responsible';
94
    final public const ROLE_ADMINISTRATOR = 'administrator';
95
96
    use HasAddress;
97
    use HasDoorAccess;
98
    use HasIban;
99
    use HasInternalRemarks;
100
    use HasPassword;
101
    use HasRemarks;
102
103
    private static ?User $currentUser = null;
104
105
    /**
106
     * Set currently logged in user
107
     * WARNING: this method should only be called from \Application\Authentication\AuthenticationListener.
108
     */
109 334
    public static function setCurrent(?self $user): void
110
    {
111 334
        self::$currentUser = $user;
112
113
        // Initialize ACL filter with current user if a logged in one exists
114
        /** @var UserRepository $userRepository */
115 334
        $userRepository = _em()->getRepository(self::class);
116 334
        $aclFilter = $userRepository->getAclFilter();
117 334
        $aclFilter->setUser($user);
118
119 334
        CurrentUser::set($user);
120
    }
121
122
    /**
123
     * Returns currently logged user or null.
124
     */
125 126
    public static function getCurrent(): ?self
126
    {
127 126
        return self::$currentUser;
128
    }
129
130
    #[ORM\Column(type: 'string', length: 50, nullable: true, unique: true)]
131
    private ?string $login = null;
132
133
    #[ORM\Column(type: 'string', length: 191)]
134
    private string $firstName = '';
135
136
    #[ORM\Column(type: 'string', length: 191)]
137
    private string $lastName = '';
138
139
    #[ORM\Column(type: 'string', length: 191, nullable: true, unique: true)]
140
    private ?string $email = null;
141
142
    #[ORM\Column(type: 'UserRole', options: ['default' => self::ROLE_INDIVIDUAL])]
143
    private string $role = self::ROLE_INDIVIDUAL;
144
145
    #[ORM\Column(type: 'enum', options: ['default' => UserStatus::New])]
146
    private UserStatus $status = UserStatus::New;
147
148
    #[ORM\Column(type: 'datetime', nullable: true)]
149
    private ?Chronos $welcomeSessionDate = null;
150
151
    #[ORM\Column(type: 'datetime', nullable: true)]
152
    private ?Chronos $resignDate = null;
153
154
    /**
155
     * @var int sex
156
     */
157
    #[ORM\Column(type: 'smallint', options: ['default' => 0])]
158
    private int $sex = 0;
159
160
    #[ORM\Column(type: 'string', length: 25, options: ['default' => ''])]
161
    private string $phone = '';
162
163
    #[ORM\Column(type: 'string', length: 25, options: ['default' => ''])]
164
    private string $mobilePhone = '';
165
166
    #[ORM\Column(type: 'string', length: 25, options: ['default' => ''])]
167
    private string $swissSailing = '';
168
169
    #[ORM\Column(type: 'enum', nullable: true)]
170
    private ?SwissSailingType $swissSailingType = null;
171
172
    #[ORM\Column(type: 'enum', nullable: true)]
173
    private ?SwissWindsurfType $swissWindsurfType = null;
174
175
    #[ORM\Column(type: 'date', nullable: true)]
176
    private ?ChronosDate $birthday = null;
177
178
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
179
    private bool $termsAgreement = false;
180
181
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
182
    private bool $hasInsurance = false;
183
184
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
185
    private bool $receivesNewsletter = false;
186
187
    #[ORM\Column(type: 'enum', options: ['default' => Relationship::Householder])]
188
    private Relationship $familyRelationship = Relationship::Householder;
189
190
    #[ORM\Column(type: 'enum', options: ['default' => BillingType::Electronic])]
191
    private BillingType $billingType = BillingType::Electronic;
192
193
    #[ORM\Column(type: 'datetime', nullable: true)]
194
    private ?Chronos $firstLogin = null;
195
196
    #[ORM\Column(type: 'datetime', nullable: true)]
197
    private ?Chronos $lastLogin = null;
198
199
    /**
200
     * @var Collection<int, Booking>
201
     */
202
    #[ORM\OneToMany(targetEntity: Booking::class, mappedBy: 'owner')]
203
    private Collection $bookings;
204
205
    /**
206
     * @var Collection<int, License>
207
     */
208
    #[ORM\ManyToMany(targetEntity: License::class, mappedBy: 'users')]
209
    private Collection $licenses;
210
211
    /**
212
     * @var Collection<int, UserTag>
213
     */
214
    #[ORM\ManyToMany(targetEntity: UserTag::class, mappedBy: 'users')]
215
    private Collection $userTags;
216
217
    /**
218
     * @var Collection<int, Message>
219
     */
220
    #[ORM\OneToMany(targetEntity: Message::class, mappedBy: 'recipient')]
221
    private Collection $messages;
222
223
    /**
224
     * There is actually 0 to 1 account, never more. And this is
225
     * enforced by DB unique constraints.
226
     *
227
     * @var Collection<int, Account>
228
     */
229
    #[ORM\OneToMany(targetEntity: Account::class, mappedBy: 'owner')]
230
    private Collection $accounts;
231
232
    /**
233
     * @var Collection<int, User>
234
     */
235
    #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'owner')]
236
    private Collection $users;
237
238
    /**
239
     * @param string $role role for new user
240
     */
241 151
    public function __construct(string $role = self::ROLE_INDIVIDUAL)
242
    {
243 151
        $this->role = $role;
244 151
        $this->bookings = new ArrayCollection();
245 151
        $this->accounts = new ArrayCollection();
246 151
        $this->licenses = new ArrayCollection();
247 151
        $this->userTags = new ArrayCollection();
248 151
        $this->messages = new ArrayCollection();
249 151
        $this->users = new ArrayCollection();
250
    }
251
252
    /**
253
     * Set login (eg: johndoe).
254
     */
255 16
    #[API\Input(type: LoginType::class)]
256
    public function setLogin(string $login): void
257
    {
258 16
        $this->login = $login;
259
    }
260
261
    /**
262
     * Get login (eg: johndoe).
263
     */
264 36
    #[API\Field(type: '?Login')]
265
    public function getLogin(): ?string
266
    {
267 36
        return $this->login;
268
    }
269
270
    /**
271
     * Set first name.
272
     */
273 11
    public function setFirstName(string $firstName): void
274
    {
275 11
        $this->firstName = $firstName;
276
    }
277
278
    /**
279
     * Get first name.
280
     */
281 36
    public function getFirstName(): string
282
    {
283 36
        return $this->firstName;
284
    }
285
286
    /**
287
     * Set last name.
288
     */
289 11
    public function setLastName(string $lastName): void
290
    {
291 11
        $this->lastName = $lastName;
292
    }
293
294
    /**
295
     * Get last name.
296
     */
297 28
    public function getLastName(): string
298
    {
299 28
        return $this->lastName;
300
    }
301
302
    /**
303
     * Get full name.
304
     */
305 28
    public function getName(): string
306
    {
307 28
        return implode(' ', [$this->getFirstName(), $this->getLastName()]);
308
    }
309
310
    /**
311
     * Set email.
312
     */
313 6
    #[API\Input(type: '?Email')]
314
    public function setEmail(?string $email): void
315
    {
316 6
        $this->email = $email;
317
    }
318
319
    /**
320
     * Get email.
321
     */
322 18
    #[API\Field(type: '?Email')]
323
    public function getEmail(): ?string
324
    {
325 18
        return $this->email;
326
    }
327
328
    /**
329
     * Get the user role.
330
     */
331 105
    #[API\Field(type: UserRoleType::class)]
332
    public function getRole(): string
333
    {
334 105
        return $this->role;
335
    }
336
337
    /**
338
     * Sets the user role.
339
     */
340 8
    #[API\Input(type: UserRoleType::class)]
341
    public function setRole(string $role): void
342
    {
343 8
        if (!Role::canUpdate(self::getCurrent(), $this->role, $role)) {
344 3
            $currentRole = self::getCurrent() ? self::getCurrent()->getRole() : self::ROLE_ANONYMOUS;
345
346 3
            throw new Exception($currentRole . ' is not allowed to change role from ' . $this->role . ' to ' . $role);
347
        }
348
349 5
        $this->role = $role;
350
    }
351
352 11
    public function setOwner(?self $owner = null): void
353
    {
354 11
        if ($owner === $this) {
355 1
            throw new Exception('This user cannot be owned by himself');
356
        }
357
358 10
        if ($owner && $owner->getOwner()) {
359 1
            throw new Exception('This user cannot be owned by a user who is himself owned by somebody else');
360
        }
361
362 10
        if ($owner && $this->users->count()) {
363 1
            throw new Exception('This user owns other users, so he cannot himself be owned by somebody else');
364
        }
365
366 10
        if ($this->getOwner()) {
367 3
            $this->getOwner()->getEmail(); // Trigger lazy loading
368 3
            $this->getOwner()->users->removeElement($this);
369
        }
370
371 10
        parent::setOwner($owner);
372
373 10
        if ($this->getOwner()) {
374 5
            $this->getOwner()->getEmail(); // Trigger lazy loading
375 5
            $this->getOwner()->users->add($this);
376 5
            $this->setStatus($this->getOwner()->getStatus());
377
        }
378
    }
379
380 12
    public function getStatus(): UserStatus
381
    {
382 12
        return $this->status;
383
    }
384
385
    /**
386
     * Whether the user is allowed to log in or stay logged in.
387
     */
388 5
    public function canLogin(): bool
389
    {
390 5
        return in_array($this->getStatus(), [UserStatus::Active, UserStatus::Inactive, UserStatus::New], true);
391
    }
392
393 17
    public function setStatus(UserStatus $newStatus): void
394
    {
395 17
        if ($newStatus === UserStatus::Archived && $this->status !== UserStatus::Archived) {
396 3
            $this->setResignDate(Chronos::NOW());
397 15
        } elseif ($this->status === UserStatus::Archived && $newStatus !== UserStatus::Archived) {
398
            $this->setResignDate(null);
399
        }
400
401 17
        $this->status = $newStatus;
402 17
        $this->revokeToken();
403
404 17
        foreach ($this->users as $user) {
405 1
            if ($user !== $this) {
406 1
                $user->setStatus($newStatus);
407
            }
408
        }
409
    }
410
411
    /**
412
     * Whether this user is a family owner or not.
413
     *
414
     * This is used for our internal logic and should
415
     * NEVER be related to `familyRelationship`. That field
416
     * is purely informative for humans.
417
     */
418 1
    public function isFamilyOwner(): bool
419
    {
420 1
        return !$this->getOwner();
421
    }
422
423 1
    public function initialize(): void
424
    {
425 1
        $this->role = self::ROLE_MEMBER; // Bypass security
426 1
        $this->setStatus(UserStatus::New);
427
    }
428
429
    public function getPhone(): string
430
    {
431
        return $this->phone;
432
    }
433
434 1
    public function setPhone(string $phone): void
435
    {
436 1
        $this->phone = $phone;
437
    }
438
439
    public function getMobilePhone(): string
440
    {
441
        return $this->mobilePhone;
442
    }
443
444 2
    public function setMobilePhone(string $mobilePhone): void
445
    {
446 2
        $this->mobilePhone = $mobilePhone;
447
    }
448
449
    public function getBirthday(): ?ChronosDate
450
    {
451
        return $this->birthday;
452
    }
453
454 1
    public function setBirthday(?ChronosDate $birthday): void
455
    {
456 1
        $this->birthday = $birthday;
457
    }
458
459
    /**
460
     * return null|int.
461
     */
462
    public function getAge(): ?int
463
    {
464
        if ($this->birthday) {
465
            return (new ChronosDate())->diffInYears($this->birthday);
466
        }
467
468
        return null;
469
    }
470
471
    /**
472
     * Get bookings.
473
     */
474 3
    public function getBookings(): Collection
475
    {
476 3
        return $this->bookings;
477
    }
478
479
    /**
480
     * Get active bookings (confirmed and non-terminated).
481
     */
482 2
    #[API\Exclude]
483
    public function getRunningBookings(): ReadableCollection
484
    {
485 2
        return $this->bookings->filter(fn (Booking $booking) => $booking->getStatus() === BookingStatus::Booked && $booking->getEndDate() === null);
486
    }
487
488
    /**
489
     * Notify the user that it has a new booking.
490
     * This should only be called by Booking::setResponsible().
491
     */
492 17
    public function bookingAdded(Booking $booking): void
493
    {
494 17
        $this->bookings->add($booking);
495
    }
496
497
    /**
498
     * Notify the user that it has a booking was removed.
499
     * This should only be called by Booking::setResponsible().
500
     */
501 4
    public function bookingRemoved(Booking $booking): void
502
    {
503 4
        $this->bookings->removeElement($booking);
504
    }
505
506 4
    public function getLicenses(): Collection
507
    {
508 4
        return $this->licenses;
509
    }
510
511 1
    public function getUserTags(): Collection
512
    {
513 1
        return $this->userTags;
514
    }
515
516
    /**
517
     * Notify the user that it has a new license.
518
     * This should only be called by License::addUser().
519
     */
520 2
    public function licenseAdded(License $license): void
521
    {
522 2
        $this->licenses->add($license);
523
    }
524
525
    /**
526
     * Notify the user that it a license was removed.
527
     * This should only be called by License::removeUser().
528
     */
529 1
    public function licenseRemoved(License $license): void
530
    {
531 1
        $this->licenses->removeElement($license);
532
    }
533
534
    /**
535
     * Notify the user that it has a new userTag.
536
     * This should only be called by UserTag::addUser().
537
     */
538 1
    public function userTagAdded(UserTag $userTag): void
539
    {
540 1
        $this->userTags->add($userTag);
541
    }
542
543
    /**
544
     * Notify the user that a userTag was removed.
545
     * This should only be called by UserTag::removeUser().
546
     */
547 1
    public function userTagRemoved(UserTag $userTag): void
548
    {
549 1
        $this->userTags->removeElement($userTag);
550
    }
551
552
    public function isTermsAgreement(): bool
553
    {
554
        return $this->termsAgreement;
555
    }
556
557 2
    public function setTermsAgreement(bool $termsAgreement): void
558
    {
559 2
        $this->termsAgreement = $termsAgreement;
560
    }
561
562
    public function hasInsurance(): bool
563
    {
564
        return $this->hasInsurance;
565
    }
566
567 2
    public function setHasInsurance(bool $hasInsurance): void
568
    {
569 2
        $this->hasInsurance = $hasInsurance;
570
    }
571
572
    public function getWelcomeSessionDate(): ?Chronos
573
    {
574
        return $this->welcomeSessionDate;
575
    }
576
577
    public function setWelcomeSessionDate(?Chronos $welcomeSessionDate): void
578
    {
579
        $this->welcomeSessionDate = $welcomeSessionDate;
580
    }
581
582 1
    public function getResignDate(): ?Chronos
583
    {
584 1
        return $this->resignDate;
585
    }
586
587 3
    public function setResignDate(?Chronos $resignDate): void
588
    {
589 3
        $this->resignDate = $resignDate;
590
    }
591
592
    public function getReceivesNewsletter(): bool
593
    {
594
        return $this->receivesNewsletter;
595
    }
596
597 1
    public function setReceivesNewsletter(bool $receivesNewsletter): void
598
    {
599 1
        $this->receivesNewsletter = $receivesNewsletter;
600
    }
601
602
    /**
603
     * Get the sex.
604
     */
605
    #[API\Field(type: SexType::class)]
606
    public function getSex(): int
607
    {
608
        return $this->sex;
609
    }
610
611
    /**
612
     * Set the sex.
613
     */
614 1
    #[API\Input(type: SexType::class)]
615
    public function setSex(int $sex): void
616
    {
617 1
        $this->sex = $sex;
618
    }
619
620
    /**
621
     * Get the Swiss Sailing licence number.
622
     */
623
    public function getSwissSailing(): string
624
    {
625
        return $this->swissSailing;
626
    }
627
628 1
    public function setSwissSailing(string $swissSailing): void
629
    {
630 1
        $this->swissSailing = $swissSailing;
631
    }
632
633
    /**
634
     * Get the Swiss Sailing licence type.
635
     */
636
    public function getSwissSailingType(): ?SwissSailingType
637
    {
638
        return $this->swissSailingType;
639
    }
640
641
    /**
642
     * Set the Swiss Sailing licence type.
643
     */
644
    public function setSwissSailingType(?SwissSailingType $swissSailingType): void
645
    {
646
        $this->swissSailingType = $swissSailingType;
647
    }
648
649
    /**
650
     * Get the Swiss Windsurf licence type.
651
     */
652
    public function getSwissWindsurfType(): ?SwissWindsurfType
653
    {
654
        return $this->swissWindsurfType;
655
    }
656
657
    /**
658
     * Set the Swiss Windsurf licence type.
659
     */
660
    #[API\Input(type: '?SwissWindsurfType')]
661
    public function setSwissWindsurfType(?SwissWindsurfType $swissWindsurfType): void
662
    {
663
        $this->swissWindsurfType = $swissWindsurfType;
664
    }
665
666
    /**
667
     * Get the first login date.
668
     */
669 1
    public function getFirstLogin(): ?Chronos
670
    {
671 1
        return $this->firstLogin;
672
    }
673
674
    /**
675
     * Get the last login date.
676
     */
677 1
    public function getLastLogin(): ?Chronos
678
    {
679 1
        return $this->lastLogin;
680
    }
681
682 4
    public function recordLogin(): void
683
    {
684 4
        _log()->info(LogRepository::LOGIN);
685
686 4
        $now = new Chronos();
687 4
        if (!$this->firstLogin) {
688 4
            $this->firstLogin = $now;
689
        }
690
691 4
        $this->lastLogin = $now;
692
    }
693
694
    public function getFamilyRelationship(): Relationship
695
    {
696
        return $this->familyRelationship;
697
    }
698
699 3
    public function setFamilyRelationship(Relationship $familyRelationship): void
700
    {
701 3
        $this->familyRelationship = $familyRelationship;
702
    }
703
704
    public function getBillingType(): BillingType
705
    {
706
        return $this->billingType;
707
    }
708
709 1
    public function setBillingType(BillingType $billingType): void
710
    {
711 1
        $this->billingType = $billingType;
712
    }
713
714
    /**
715
     * Get the user transaction account.
716
     */
717 41
    public function getAccount(): ?Account
718
    {
719 41
        if ($this->getOwner() && $this->getOwner() !== $this) {
720 8
            return $this->getOwner()->getAccount();
721
        }
722
723 41
        return $this->accounts->first() ?: null;
724
    }
725
726
    /**
727
     * Notify the user that it has a new account
728
     * This should only be called by Account::setOwner().
729
     */
730 21
    public function accountAdded(Account $account): void
731
    {
732 21
        $this->accounts->clear();
733 21
        $this->accounts->add($account);
734
    }
735
736
    /**
737
     * Notify the user that a account was removed
738
     * This should only be called by Account::setOwner().
739
     */
740 1
    public function accountRemoved(): void
741
    {
742 1
        $this->accounts->clear();
743
    }
744
745
    /**
746
     * Get messages sent to the user.
747
     */
748 1
    #[API\Exclude]
749
    public function getMessages(): Collection
750
    {
751 1
        return $this->messages;
752
    }
753
754
    /**
755
     * Notify the user that it has a new message
756
     * This should only be called by Message::setRecipient().
757
     */
758 12
    public function messageAdded(Message $message): void
759
    {
760 12
        $this->messages->add($message);
761
    }
762
763
    /**
764
     * Notify the user that a message was removed
765
     * This should only be called by Message::setRecipient().
766
     */
767 1
    public function messageRemoved(Message $message): void
768
    {
769 1
        $this->messages->removeElement($message);
770
    }
771
772
    /**
773
     * Check if the user can *really* open a door
774
     * This also takes into account the user status and role.
775
     *
776
     * @param null|Door $door a particular door, or null for any
777
     */
778 6
    public function getCanOpenDoor(?Door $door = null): bool
779
    {
780 6
        $allowedStatus = [UserStatus::Active];
781 6
        $allowedRoles = [
782 6
            self::ROLE_ACCOUNTING_VERIFICATOR,
783 6
            self::ROLE_INDIVIDUAL,
784 6
            self::ROLE_MEMBER,
785 6
            self::ROLE_TRAINER,
786 6
            self::ROLE_FORMATION_RESPONSIBLE,
787 6
            self::ROLE_RESPONSIBLE,
788 6
            self::ROLE_ADMINISTRATOR,
789 6
        ];
790
791 6
        if ($door && !$this->{$door->value}) {
792 3
            return false;
793
        }
794
795 6
        if (!in_array($this->status, $allowedStatus, true) || !in_array($this->role, $allowedRoles, true)) {
796 2
            return false;
797
        }
798
799 4
        return true;
800
    }
801
802
    /**
803
     * Override parent to prevents users created from administration to be family of the administrator.
804
     *
805
     * The owner must be explicitly set for all users.
806
     */
807 3
    protected function getOwnerForCreation(): ?self
808
    {
809 3
        return null;
810
    }
811
}
812