User::setExtraData()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
cc 1
eloc 1
c 1
b 0
f 1
nc 1
nop 2
dl 0
loc 3
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace ProjetNormandie\UserBundle\Entity;
6
7
use ApiPlatform\Metadata\ApiResource;
8
use ApiPlatform\Metadata\Get;
9
use ApiPlatform\Metadata\GetCollection;
10
use ApiPlatform\Metadata\Post;
11
use ApiPlatform\Metadata\ApiFilter;
12
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
13
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
14
use ApiPlatform\Metadata\Put;
15
use ApiPlatform\OpenApi\Model;
16
use DateTime;
17
use Doctrine\Common\Collections\ArrayCollection;
18
use Doctrine\Common\Collections\Collection;
19
use Doctrine\ORM\Mapping as ORM;
20
use Gedmo\Timestampable\Traits\TimestampableEntity;
21
use Gedmo\Mapping\Annotation as Gedmo;
22
use ProjetNormandie\UserBundle\Controller\User\Autocomplete;
23
use ProjetNormandie\UserBundle\Repository\UserRepository;
24
use Symfony\Bridge\Doctrine\Validator\Constraints as DoctrineAssert;
25
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
26
use Symfony\Component\Security\Core\User\UserInterface;
27
use Symfony\Component\Serializer\Annotation\Groups;
28
use Symfony\Component\Validator\Constraints as Assert;
29
30
#[ORM\Table(name:'pnu_user')]
31
#[ORM\Entity(repositoryClass: UserRepository::class)]
32
#[ORM\EntityListeners(["ProjetNormandie\UserBundle\EventListener\Entity\UserListener"])]
33
#[DoctrineAssert\UniqueEntity(["email"])]
34
#[DoctrineAssert\UniqueEntity(["username"])]
35
#[ApiResource(
36
    operations: [
37
        new GetCollection(),
38
        new GetCollection(
39
            uriTemplate: '/users/autocomplete',
40
            controller: Autocomplete::class,
41
            openapi: new Model\Operation(
42
                responses: [
43
                    '200' => new Model\Response(description: 'Users retrieved successfully')
44
                ],
45
                summary: 'Retrieves users by autocompletion',
46
                description: 'Retrieves users by autocompletion',
47
                parameters: [
48
                    new Model\Parameter(
49
                        name: 'query',
50
                        in: 'query',
51
                        required: true,
52
                        schema: [
53
                            'type' => 'string'
54
                        ]
55
                    )
56
                ],
57
                security: [],
58
            ),
59
            normalizationContext: ['groups' => [
60
                'user:read']
61
            ],
62
        ),
63
        new Post(
64
            denormalizationContext: ['groups' => ['user:create']],
65
            validationContext: ['groups' => ['Default', 'user:create']],
66
        ),
67
        new Put(
68
            denormalizationContext: ['groups' => ['user:update']],
69
            security: 'is_granted("ROLE_USER") and (object == user)',
70
            validationContext: ['groups' => ['Default', 'user:update']]
71
        ),
72
        new Get(),
73
    ],
74
    normalizationContext: ['groups' => ['user:read']]
75
)]
76
#[ApiFilter(SearchFilter::class, properties: ['id' => 'exact', 'username' => 'partial'])]
77
#[ApiFilter(OrderFilter::class, properties: ['id', 'username'], arguments: ['orderParameterName' => 'order'])]
78
class User implements UserInterface, PasswordAuthenticatedUserInterface
79
{
80
    use TimestampableEntity;
81
82
    #[Groups(['user:read', 'user:read:minimal'])]
83
    #[ORM\Id, ORM\Column, ORM\GeneratedValue]
84
    protected ?int $id = null;
85
86
87
    #[Groups(['user:read', 'user:read:minimal', 'user:create', 'user:update'])]
88
    #[ORM\Column(length: 100, unique: true, nullable: false)]
89
    protected string $username = '';
90
91
    #[Groups(['user:read', 'user:create', 'user:update'])]
92
    #[ORM\Column(length: 180, unique: true, nullable: false)]
93
    private string $email = '';
94
95
96
    #[ORM\Column(nullable: false, options: ['default' => true])]
97
    protected bool $enabled = true;
98
99
    /**
100
     * @var array<string>
101
     */
102
    #[ORM\Column(type: 'array', nullable: false)]
103
    private array $roles = [];
104
105
    #[ORM\Column(length: 255)]
106
    private ?string $password;
107
108
    /**
109
     * Plain password. Used for model validation. Must not be persisted.
110
     */
111
    #[Assert\NotBlank(groups: ['user:create'])]
112
    #[Groups(['user:create'])]
113
    protected ?string $plainPassword = null;
114
115
    #[Groups(['user:read'])]
116
    #[ORM\Column(type: 'datetime', nullable: true)]
117
    protected ?DateTime $lastLogin = null;
118
119
    #[ORM\Column(length: 255, unique: true, nullable: true)]
120
    protected ?string $confirmationToken = null;
121
122
    #[ORM\Column(type: 'datetime', nullable: true)]
123
    protected ?DateTime $passwordRequestedAt = null;
124
125
    #[Groups(['user:read'])]
126
    #[ORM\Column(nullable: false, options: ['default' => 0])]
127
    protected int $nbConnexion = 0;
128
129
    /**
130
     * Extra data for extensions and additional bundles.
131
     * @var array<string, mixed>
132
     */
133
    #[Groups(['user:read', 'user:read:minimal'])]
134
    #[ORM\Column(type: 'json', nullable: true)]
135
    protected array $extraData = [];
136
137
    #[ORM\Column(length: 255, nullable: false, options: ['default' => 'default.png'])]
138
    protected string $avatar = 'default.png';
139
140
    #[ORM\Column(length: 1000, nullable: true)]
141
    protected ?string $comment = null;
142
143
    #[Groups(['user:read', 'user:update'])]
144
    #[ORM\Column(length: 2, nullable: false, options: ['default' => 'en'])]
145
    protected string $language = 'en';
146
147
    #[Groups(['user:read', 'user:read:minimal'])]
148
    #[ORM\Column(length: 128)]
149
    #[Gedmo\Slug(fields: ['username'])]
150
    protected string $slug;
151
152
    #[ORM\JoinTable(name: 'pnu_user_group')]
153
    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id')]
154
    #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
155
    #[ORM\ManyToMany(targetEntity: Group::class)]
156
    protected Collection $groups;
157
158
    public function __construct()
159
    {
160
        $this->groups = new ArrayCollection();
161
    }
162
163
    public function getId(): ?int
164
    {
165
        return $this->id;
166
    }
167
168
    public function setId(?int $id): void
169
    {
170
        $this->id = $id;
171
    }
172
173
    public function getUsername(): string
174
    {
175
        return $this->username;
176
    }
177
178
    public function setUsername($username): void
179
    {
180
        $this->username = $username;
181
    }
182
183
    public function getEmail(): ?string
184
    {
185
        return $this->email;
186
    }
187
188
    public function setEmail(string $email): void
189
    {
190
        $this->email = $email;
191
    }
192
193
    public function setEnabled($boolean): void
194
    {
195
        $this->enabled = (bool) $boolean;
196
    }
197
198
    public function isEnabled(): bool
199
    {
200
        return $this->enabled;
201
    }
202
203
    public function getRoles(): array
204
    {
205
        $roles = $this->roles;
206
207
        foreach ($this->getGroups() as $group) {
208
            $roles = array_merge($roles, $group->getRoles());
209
        }
210
211
        // we need to make sure to have at least one role
212
        $roles[] = 'ROLE_USER';
213
214
        return array_values(array_unique($roles));
215
    }
216
217
    public function setRoles(array $roles): void
218
    {
219
        $this->roles = $roles;
220
    }
221
222
    public function getPassword(): ?string
223
    {
224
        return $this->password;
225
    }
226
227
    public function setPassword(string $password): void
228
    {
229
        $this->password = $password;
230
    }
231
232
    /**
233
     * Returning a salt is only needed, if you are not using a modern
234
     * hashing algorithm (e.g. bcrypt or sodium) in your security.yaml.
235
     */
236
    public function getSalt(): ?string
237
    {
238
        return null;
239
    }
240
241
    public function getPlainPassword(): ?string
242
    {
243
        return $this->plainPassword;
244
    }
245
246
    public function hasRole($role): bool
247
    {
248
        return in_array(strtoupper($role), $this->getRoles(), true);
249
    }
250
251
    public function eraseCredentials(): void
252
    {
253
        // If you store any temporary, sensitive data on the user, clear it here
254
        // $this->plainPassword = null;
255
    }
256
257
    public function getLastLogin(): ?DateTime
258
    {
259
        return $this->lastLogin;
260
    }
261
262
    public function setLastLogin(?DateTime $time = null): void
263
    {
264
        if ($time === null) {
265
            $time = new \DateTime();
266
        }
267
268
        $lastLogin = $this->getLastLogin();
269
270
        if ($lastLogin === null || $lastLogin->format('Y-m-d') !== $time->format('Y-m-d')) {
271
            ++$this->nbConnexion;
272
        }
273
274
        $this->lastLogin = $time;
275
    }
276
277
    public function updateLastLoginOnly(?\DateTime $time = null): void
278
    {
279
        if ($time === null) {
280
            $time = new \DateTime();
281
        }
282
283
        $this->lastLogin = $time;
284
    }
285
286
    public function setConfirmationToken($confirmationToken): void
287
    {
288
        $this->confirmationToken = $confirmationToken;
289
    }
290
291
    public function getConfirmationToken(): ?string
292
    {
293
        return $this->confirmationToken;
294
    }
295
296
    public function setPasswordRequestedAt(?DateTime $date = null): void
297
    {
298
        $this->passwordRequestedAt = $date;
299
    }
300
301
    public function getPasswordRequestedAt(): ?DateTime
302
    {
303
        return $this->passwordRequestedAt;
304
    }
305
306
    public function isPasswordRequestExpired($ttl): bool
307
    {
308
        return $this->getPasswordRequestedAt() instanceof DateTime &&
309
               $this->getPasswordRequestedAt()->getTimestamp() + $ttl < time();
310
    }
311
312
    public function getLanguage(): string
313
    {
314
        return $this->language;
315
    }
316
317
    public function setLanguage(string $language): void
318
    {
319
        $this->language = $language;
320
    }
321
322
    public function getSlug(): string
323
    {
324
        return $this->slug;
325
    }
326
327
    public function getNbConnexion(): int
328
    {
329
        return $this->nbConnexion;
330
    }
331
332
    public function setNbConnexion(int $nbConnexion): void
333
    {
334
        $this->nbConnexion = $nbConnexion;
335
    }
336
337
    /**
338
     * Get extra data by key or all extra data if no key provided.
339
     *
340
     * @param string|null $key The key to retrieve
341
     * @return mixed The value or all extraData if no key provided
342
     */
343
    public function getExtraData(?string $key = null): mixed
344
    {
345
        if ($key === null) {
346
            return $this->extraData;
347
        }
348
349
        return $this->extraData[$key] ?? null;
350
    }
351
352
    /**
353
     * Set extra data with a given key.
354
     *
355
     * @param string $key The key to set
356
     * @param mixed $value The value to set
357
     */
358
    public function setExtraData(string $key, mixed $value): void
359
    {
360
        $this->extraData[$key] = $value;
361
    }
362
363
    /**
364
     * Check if extra data with given key exists.
365
     *
366
     * @param string $key The key to check
367
     * @return bool True if the key exists
368
     */
369
    public function hasExtraData(string $key): bool
370
    {
371
        return array_key_exists($key, $this->extraData);
372
    }
373
374
    /**
375
     * Remove extra data with given key.
376
     *
377
     * @param string $key The key to remove
378
     */
379
    public function removeExtraData(string $key): void
380
    {
381
        if ($this->hasExtraData($key)) {
382
            unset($this->extraData[$key]);
383
        }
384
    }
385
386
    public function getAvatar(): string
387
    {
388
        return $this->avatar;
389
    }
390
391
    public function setAvatar(string $avatar): void
392
    {
393
        $this->avatar = $avatar;
394
    }
395
396
    public function getComment(): ?string
397
    {
398
        return $this->comment;
399
    }
400
401
    public function setComment(?string $comment = null): void
402
    {
403
        $this->comment = $comment;
404
    }
405
406
    public function setGroups($groups): void
407
    {
408
        $this->groups = $groups;
409
    }
410
411
    public function getGroups(): Collection
412
    {
413
        return $this->groups;
414
    }
415
416
    public function setPlainPassword($password): void
417
    {
418
        $this->plainPassword = $password;
419
    }
420
421
    public function addGroup($group): void
422
    {
423
        $this->groups[] = $group;
424
    }
425
426
    public function removeGroup(Group $group): void
427
    {
428
        $this->groups->removeElement($group);
429
    }
430
431
    public function __toString()
432
    {
433
        return sprintf('%s [%d]', $this->getUsername(), $this->getId());
434
    }
435
436
    public function addRole($role): void
437
    {
438
        $role = strtoupper($role);
439
        if (!in_array($role, $this->roles, true)) {
440
            $this->roles[] = $role;
441
        }
442
    }
443
444
    public function removeRole($role): void
445
    {
446
        if (false !== $key = array_search(strtoupper($role), $this->roles, true)) {
447
            unset($this->roles[$key]);
448
            $this->roles = array_values($this->roles);
449
        }
450
    }
451
452
    public function getUserIdentifier(): string
453
    {
454
        return $this->email;
455
    }
456
}
457