User::bookingRemoved()   A
last analyzed

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