User   A
last analyzed

Complexity

Total Complexity 30

Size/Duplication

Total Lines 274
Duplicated Lines 0 %

Test Coverage

Coverage 73.12%

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 30
eloc 84
c 2
b 0
f 0
dl 0
loc 274
ccs 49
cts 67
cp 0.7312
rs 10

27 Methods

Rating   Name   Duplication   Size   Complexity  
A getCurrent() 0 3 1
A setRole() 0 10 3
A setIsPublicFacilitator() 0 3 1
A setEmail() 0 4 1
A getLastLogin() 0 3 1
A getLogin() 0 4 1
A setMembership() 0 4 1
A getSessions() 0 3 1
A isPublicFacilitator() 0 3 1
A initialize() 0 3 1
A getEmail() 0 4 1
A getName() 0 3 1
A getPhone() 0 3 1
A recordLogin() 0 10 2
A __construct() 0 5 1
A setWebTemporaryAccess() 0 4 1
A getOwnerForCreation() 0 3 1
A getMembership() 0 3 1
A setSubscriptionType() 0 4 1
A sessionRemoved() 0 3 1
A getFirstLogin() 0 3 1
A getSubscriptionType() 0 3 1
A setCurrent() 0 11 1
A sessionAdded() 0 3 1
A getRole() 0 4 1
A setPhone() 0 3 1
A getWebTemporaryAccess() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Application\Model;
6
7
use Application\Api\Enum\UserRoleType;
8
use Application\Api\Input\Operator\RegexpOperatorType;
9
use Application\Enum\Membership;
10
use Application\Enum\ProductType;
11
use Application\Repository\LogRepository;
12
use Application\Repository\UserRepository;
13
use Application\Service\Role;
14
use Application\Traits\HasAddress;
15
use Application\Traits\HasSubscriptionLastReview;
16
use Application\Traits\IsImportable;
17
use Cake\Chronos\Chronos;
18
use Doctrine\Common\Collections\ArrayCollection;
19
use Doctrine\Common\Collections\Collection;
20
use Doctrine\ORM\Mapping as ORM;
21
use Ecodev\Felix\Api\Exception;
22
use Ecodev\Felix\Api\Scalar\EmailType;
23
use Ecodev\Felix\Model\CurrentUser;
24
use Ecodev\Felix\Model\Traits\HasPassword;
25
use GraphQL\Doctrine\Attribute as API;
26
27
/**
28
 * User.
29
 */
30
#[API\Filter(field: 'custom', operator: RegexpOperatorType::class, type: 'string')]
31
#[ORM\Entity(UserRepository::class)]
32
#[ORM\HasLifecycleCallbacks]
33
#[ORM\AssociationOverrides([new ORM\AssociationOverride(name: 'owner', inversedBy: 'users')])]
34
class User extends AbstractModel implements \Ecodev\Felix\Model\HasPassword, \Ecodev\Felix\Model\User
35
{
36
    final public const ROLE_ANONYMOUS = 'anonymous';
37
    final public const ROLE_MEMBER = 'member';
38
    final public const ROLE_FACILITATOR = 'facilitator';
39
    final public const ROLE_ADMINISTRATOR = 'administrator';
40
41
    use HasAddress;
42
    use HasPassword;
43
    use HasSubscriptionLastReview;
44
    use IsImportable;
45
46
    private static ?User $currentUser = null;
47
48
    /**
49
     * Set currently logged in user
50
     * WARNING: this method should only be called from \Application\Authentication\AuthenticationListener.
51
     */
52 138
    public static function setCurrent(?self $user): void
53
    {
54 138
        self::$currentUser = $user;
55
56
        // Initialize ACL filter with current user if a logged in one exists
57
        /** @var UserRepository $userRepository */
58 138
        $userRepository = _em()->getRepository(self::class);
59 138
        $aclFilter = $userRepository->getAclFilter();
60 138
        $aclFilter->setUser($user);
61
62 138
        CurrentUser::set($user);
63
    }
64
65
    /**
66
     * Returns currently logged user or null.
67
     */
68 84
    public static function getCurrent(): ?self
69
    {
70 84
        return self::$currentUser;
71
    }
72
73
    #[ORM\Column(type: 'string', length: 191, unique: true)]
74
    private ?string $email = null;
75
76
    #[ORM\Column(type: 'UserRole', options: ['default' => self::ROLE_MEMBER])]
77
    private string $role = self::ROLE_MEMBER;
78
79
    #[ORM\Column(type: 'enum', options: ['default' => Membership::None])]
80
    private Membership $membership = Membership::None;
81
82
    #[ORM\Column(type: 'enum', nullable: true)]
83
    private ?ProductType $subscriptionType = null;
84
85
    #[ORM\Column(type: 'string', length: 25, options: ['default' => ''])]
86
    private string $phone = '';
87
88
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
89
    private bool $webTemporaryAccess = false;
90
91
    #[ORM\Column(type: 'boolean', options: ['default' => false])]
92
    private bool $isPublicFacilitator = false;
93
94
    #[ORM\Column(type: 'datetime', nullable: true)]
95
    private ?Chronos $firstLogin = null;
96
97
    #[ORM\Column(type: 'datetime', nullable: true)]
98
    private ?Chronos $lastLogin = null;
99
100
    /**
101
     * @var Collection<int, Session>
102
     */
103
    #[ORM\ManyToMany(targetEntity: Session::class, mappedBy: 'facilitators')]
104
    private Collection $sessions;
105
106
    /**
107
     * @var Collection<int, User>
108
     */
109
    #[ORM\OneToMany(targetEntity: self::class, mappedBy: 'owner')]
110
    private Collection $users;
111
112
    /**
113
     * @param string $role role for new user
114
     */
115 14
    public function __construct(string $role = self::ROLE_MEMBER)
116
    {
117 14
        $this->role = $role;
118 14
        $this->sessions = new ArrayCollection();
119 14
        $this->users = new ArrayCollection();
120
    }
121
122
    /**
123
     * Get full name.
124
     */
125 10
    public function getName(): string
126
    {
127 10
        return implode(' ', array_filter([$this->getFirstName(), $this->getLastName()]));
128
    }
129
130
    /**
131
     * Set email.
132
     */
133 3
    #[API\Input(type: EmailType::class)]
134
    public function setEmail(?string $email): void
135
    {
136 3
        $this->email = $email;
137
    }
138
139
    /**
140
     * Get email.
141
     */
142 19
    #[API\Field(type: EmailType::class)]
143
    public function getEmail(): ?string
144
    {
145 19
        return $this->email;
146
    }
147
148
    /**
149
     * Use email as a technical identifier of user.
150
     */
151 10
    #[API\Exclude]
152
    public function getLogin(): ?string
153
    {
154 10
        return $this->getEmail();
155
    }
156
157
    /**
158
     * Get the user role.
159
     */
160 44
    #[API\Field(type: UserRoleType::class)]
161
    public function getRole(): string
162
    {
163 44
        return $this->role;
164
    }
165
166
    /**
167
     * Sets the user role.
168
     */
169 7
    #[API\Input(type: UserRoleType::class)]
170
    public function setRole(string $role): void
171
    {
172 7
        if (!Role::canUpdate(self::getCurrent(), $this->role, $role)) {
173 3
            $currentRole = self::getCurrent() ? self::getCurrent()->getRole() : self::ROLE_ANONYMOUS;
174
175 3
            throw new Exception($currentRole . ' is not allowed to change role from ' . $this->role . ' to ' . $role);
176
        }
177
178 4
        $this->role = $role;
179
    }
180
181 1
    public function initialize(): void
182
    {
183 1
        $this->role = self::ROLE_MEMBER; // Bypass security
184
    }
185
186
    public function getPhone(): string
187
    {
188
        return $this->phone;
189
    }
190
191
    public function setPhone(string $phone): void
192
    {
193
        $this->phone = $phone;
194
    }
195
196
    public function getSessions(): Collection
197
    {
198
        return $this->sessions;
199
    }
200
201
    /**
202
     * Notify the user that it has a new session.
203
     * This should only be called by Session::addFacilitator().
204
     */
205
    public function sessionAdded(Session $session): void
206
    {
207
        $this->sessions->add($session);
208
    }
209
210
    /**
211
     * Notify the user that a session was removed.
212
     * This should only be called by Session::removeFacilitator().
213
     */
214
    public function sessionRemoved(Session $session): void
215
    {
216
        $this->sessions->removeElement($session);
217
    }
218
219 1
    public function getMembership(): Membership
220
    {
221 1
        return $this->membership;
222
    }
223
224
    #[API\Exclude]
225
    public function setMembership(Membership $membership): void
226
    {
227
        $this->membership = $membership;
228
    }
229
230 3
    public function getWebTemporaryAccess(): bool
231
    {
232 3
        return $this->webTemporaryAccess;
233
    }
234
235 2
    #[API\Exclude]
236
    public function setWebTemporaryAccess(bool $webTemporaryAccess): void
237
    {
238 2
        $this->webTemporaryAccess = $webTemporaryAccess;
239
    }
240
241
    public function setIsPublicFacilitator(bool $isPublicFacilitator): void
242
    {
243
        $this->isPublicFacilitator = $isPublicFacilitator;
244
    }
245
246
    public function isPublicFacilitator(): bool
247
    {
248
        return $this->isPublicFacilitator;
249
    }
250
251
    /**
252
     * Get the first login date.
253
     */
254 1
    public function getFirstLogin(): ?Chronos
255
    {
256 1
        return $this->firstLogin;
257
    }
258
259
    /**
260
     * Get the last login date.
261
     */
262 1
    public function getLastLogin(): ?Chronos
263
    {
264 1
        return $this->lastLogin;
265
    }
266
267 3
    public function recordLogin(): void
268
    {
269 3
        _log()->info(LogRepository::LOGIN);
270
271 3
        $now = new Chronos();
272 3
        if (!$this->firstLogin) {
273 3
            $this->firstLogin = $now;
274
        }
275
276 3
        $this->lastLogin = $now;
277
    }
278
279
    /**
280
     * Override parent to prevents users created from administration to be family of the administrator.
281
     *
282
     * The owner must be explicitly set for all users.
283
     */
284 2
    protected function getOwnerForCreation(): ?self
285
    {
286 2
        return null;
287
    }
288
289
    /**
290
     * Set subscription type.
291
     */
292
    #[API\Exclude]
293
    public function setSubscriptionType(?ProductType $subscriptionType): void
294
    {
295
        $this->subscriptionType = $subscriptionType;
296
    }
297
298
    /**
299
     * Get subscription type.
300
     */
301 2
    public function getSubscriptionType(): ?ProductType
302
    {
303 2
        return $this->subscriptionType;
304
    }
305
}
306