Passed
Push — master ( dad11e...8233a2 )
by Adrien
07:43
created

User   F

Complexity

Total Complexity 92

Size/Duplication

Total Lines 807
Duplicated Lines 0 %

Test Coverage

Coverage 73.18%

Importance

Changes 4
Bugs 0 Features 0
Metric Value
wmc 92
eloc 162
c 4
b 0
f 0
dl 0
loc 807
rs 2
ccs 161
cts 220
cp 0.7318

68 Methods

Rating   Name   Duplication   Size   Complexity  
A getRole() 0 3 1
A setRole() 0 9 3
A setFirstName() 0 3 1
A setEmail() 0 3 1
A setLogin() 0 3 1
A getLogin() 0 3 1
A getLastName() 0 3 1
A getEmail() 0 3 1
A getCurrent() 0 3 1
A getName() 0 3 1
A __construct() 0 9 1
A getFirstName() 0 3 1
A setLastName() 0 3 1
A setCurrent() 0 11 1
A setWelcomeSessionDate() 0 3 1
A licenseRemoved() 0 3 1
A setSwissWindsurfType() 0 3 1
A getBookings() 0 3 1
A getCanOpenDoor() 0 14 5
A getLastLogin() 0 6 1
A messageRemoved() 0 3 1
A getAge() 0 7 2
A getUserTags() 0 3 1
A getMobilePhone() 0 3 1
A isFamilyOwner() 0 3 1
A accountAdded() 0 4 1
A getBirthday() 0 3 1
A getReceivesNewsletter() 0 3 1
A isTermsAgreement() 0 3 1
A userTagAdded() 0 3 1
A getStatus() 0 3 1
A getMessages() 0 3 1
A userTagRemoved() 0 3 1
A initialize() 0 4 1
A setMobilePhone() 0 3 1
A hasInsurance() 0 3 1
B setStatus() 0 14 7
A getLicenses() 0 3 1
A getPhone() 0 3 1
A setHasInsurance() 0 3 1
A bookingRemoved() 0 3 1
A setBillingType() 0 3 1
A getOwnerForCreation() 0 3 1
A getSwissSailingType() 0 3 1
A bookingAdded() 0 3 1
A getSwissSailing() 0 3 1
A getSex() 0 3 1
A getRunningBookings() 0 4 2
A getResignDate() 0 3 1
A setSwissSailingType() 0 3 1
A accountRemoved() 0 3 1
A setTermsAgreement() 0 3 1
A getAccount() 0 7 4
B setOwner() 0 25 8
A getFirstLogin() 0 6 1
A setReceivesNewsletter() 0 3 1
A setBirthday() 0 3 1
A setResignDate() 0 3 1
A setSwissSailing() 0 3 1
A licenseAdded() 0 3 1
A getWelcomeSessionDate() 0 3 1
A getFamilyRelationship() 0 3 1
A setFamilyRelationship() 0 3 1
A setPhone() 0 3 1
A getSwissWindsurfType() 0 3 1
A setSex() 0 3 1
A getBillingType() 0 3 1
A messageAdded() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like User often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use User, and based on these observations, apply Extract Interface, too.

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