Passed
Push — master ( 7b2e96...eb2391 )
by Yannick
11:12
created

User::getFullNameWithClasses()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 13
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 7
nc 4
nop 0
dl 0
loc 13
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Entity;
8
9
use ApiPlatform\Doctrine\Orm\Filter\BooleanFilter;
10
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
11
use ApiPlatform\Metadata\ApiFilter;
12
use ApiPlatform\Metadata\ApiProperty;
13
use ApiPlatform\Metadata\ApiResource;
14
use ApiPlatform\Metadata\Delete;
15
use ApiPlatform\Metadata\Get;
16
use ApiPlatform\Metadata\GetCollection;
17
use ApiPlatform\Metadata\Link;
18
use ApiPlatform\Metadata\Post;
19
use ApiPlatform\Metadata\Put;
20
use Chamilo\CoreBundle\Controller\Api\CreateUserOnAccessUrlAction;
21
use Chamilo\CoreBundle\Controller\Api\GetStatsAction;
22
use Chamilo\CoreBundle\Controller\Api\UserSkillsController;
23
use Chamilo\CoreBundle\Dto\CreateUserOnAccessUrlInput;
24
use Chamilo\CoreBundle\Entity\Listener\UserListener;
25
use Chamilo\CoreBundle\Filter\PartialSearchOrFilter;
26
use Chamilo\CoreBundle\Repository\Node\UserRepository;
27
use Chamilo\CoreBundle\Traits\UserCreatorTrait;
28
use Chamilo\CourseBundle\Entity\CGroupRelTutor;
29
use Chamilo\CourseBundle\Entity\CGroupRelUser;
30
use Chamilo\CourseBundle\Entity\CSurveyInvitation;
31
use DateTime;
32
use DateTimeInterface;
33
use Doctrine\Common\Collections\ArrayCollection;
34
use Doctrine\Common\Collections\Collection;
35
use Doctrine\Common\Collections\Criteria;
36
use Doctrine\Common\Collections\ReadableCollection;
37
use Doctrine\ORM\Mapping as ORM;
38
use Gedmo\Timestampable\Traits\TimestampableEntity;
39
use Stringable;
40
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
41
use Symfony\Component\Security\Core\User\EquatableInterface;
42
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
43
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
44
use Symfony\Component\Security\Core\User\UserInterface;
45
use Symfony\Component\Serializer\Annotation\Groups;
46
use Symfony\Component\Uid\Uuid;
47
use Symfony\Component\Validator\Constraints as Assert;
48
use Symfony\Component\Validator\Mapping\ClassMetadata;
49
use UserManager;
50
51
#[ApiResource(
52
    types: ['http://schema.org/Person'],
53
    operations: [
54
        new Get(
55
            openapiContext: [
56
                'description' => 'Get details of one specific user, including name, e-mail and role.',
57
            ],
58
            security: "is_granted('VIEW', object)",
59
        ),
60
        new Get(
61
            uriTemplate: '/users/{id}/courses/{courseId}/stats/{metric}',
62
            requirements: [
63
                'id' => '\d+',
64
                'courseId' => '\d+',
65
                'metric' => 'avg-lp-progress|certificates|gradebook-global',
66
            ],
67
            controller: GetStatsAction::class,
68
            openapiContext: [
69
                'summary' => 'User-course statistics, switch by {metric}',
70
                'parameters' => [
71
                    [
72
                        'name' => 'courseId',
73
                        'in' => 'path',
74
                        'required' => true,
75
                        'schema' => ['type' => 'integer'],
76
                        'description' => 'Course ID',
77
                    ],
78
                    [
79
                        'name' => 'metric',
80
                        'in' => 'path',
81
                        'required' => true,
82
                        'schema' => [
83
                            'type' => 'string',
84
                            'enum' => ['avg-lp-progress', 'certificates', 'gradebook-global'],
85
                        ],
86
                        'description' => 'Metric selector',
87
                    ],
88
                    [
89
                        'name' => 'sessionId',
90
                        'in' => 'query',
91
                        'required' => false,
92
                        'schema' => ['type' => 'integer'],
93
                        'description' => 'Optional Session ID',
94
                    ],
95
                ],
96
            ],
97
            security: "is_granted('ROLE_USER')",
98
            output: false,
99
            read: false,
100
            name: 'stats_user_course_metric'
101
        ),
102
        new Put(security: "is_granted('EDIT', object)"),
103
        new Delete(security: "is_granted('DELETE', object)"),
104
        new GetCollection(security: "is_granted('ROLE_USER')"),
105
        new Post(security: "is_granted('ROLE_ADMIN')"),
106
        new GetCollection(
107
            uriTemplate: '/users/{id}/skills',
108
            controller: UserSkillsController::class,
109
            normalizationContext: ['groups' => ['user_skills:read']],
110
            name: 'get_user_skills'
111
        ),
112
    ],
113
    normalizationContext: ['groups' => ['user:read']],
114
    denormalizationContext: ['groups' => ['user:write']],
115
    security: 'is_granted("ROLE_USER")'
116
)]
117
#[ApiResource(
118
    uriTemplate: '/access_urls/{id}/user',
119
    operations: [
120
        new Post(
121
            controller: CreateUserOnAccessUrlAction::class,
122
        ),
123
    ],
124
    uriVariables: [
125
        'id' => new Link(
126
            description: 'AccessUrl identifier',
127
        ),
128
    ],
129
    denormalizationContext: ['groups' => ['write']],
130
    input: CreateUserOnAccessUrlInput::class,
131
    output: User::class,
132
    security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_SESSION_MANAGER')",
133
)]
134
#[ORM\Table(name: 'user')]
135
#[ORM\Index(columns: ['status'], name: 'status')]
136
#[UniqueEntity('username')]
137
#[ORM\Entity(repositoryClass: UserRepository::class)]
138
#[ORM\EntityListeners([UserListener::class])]
139
#[ApiFilter(
140
    filterClass: SearchFilter::class,
141
    properties: [
142
        'username' => 'partial',
143
        'firstname' => 'partial',
144
        'lastname' => 'partial',
145
    ]
146
)]
147
#[ApiFilter(PartialSearchOrFilter::class, properties: ['username', 'firstname', 'lastname'])]
148
#[ApiFilter(filterClass: BooleanFilter::class, properties: ['isActive'])]
149
class User implements UserInterface, EquatableInterface, ResourceInterface, ResourceIllustrationInterface, PasswordAuthenticatedUserInterface, LegacyPasswordAuthenticatedUserInterface, ExtraFieldItemInterface, Stringable
150
{
151
    use TimestampableEntity;
152
    use UserCreatorTrait;
153
154
    public const USERNAME_MAX_LENGTH = 100;
155
    public const ROLE_DEFAULT = 'ROLE_USER';
156
    public const ANONYMOUS = 6;
157
158
    /**
159
     * Global status for the fallback user.
160
     * This special status is used for a system user that acts as a placeholder
161
     * or fallback for content ownership when regular users are deleted.
162
     * This ensures data integrity and prevents orphaned content within the system.
163
     */
164
    public const ROLE_FALLBACK = 99;
165
166
    // User active field constants
167
    public const ACTIVE = 1;
168
    public const INACTIVE = 0;
169
    public const INACTIVE_AUTOMATIC = -1;
170
    public const SOFT_DELETED = -2;
171
172
    #[Groups(['user_json:read'])]
173
    #[ORM\OneToOne(targetEntity: ResourceNode::class, cascade: ['persist'])]
174
    #[ORM\JoinColumn(name: 'resource_node_id', onDelete: 'CASCADE')]
175
    public ?ResourceNode $resourceNode = null;
176
177
    /**
178
     * Resource illustration URL - Property set by ResourceNormalizer.php.
179
     */
180
    #[ApiProperty(iris: ['http://schema.org/contentUrl'])]
181
    #[Groups([
182
        'user_export',
183
        'user:read',
184
        'resource_node:read',
185
        'document:read',
186
        'media_object_read',
187
        'course:read',
188
        'course_rel_user:read',
189
        'user_json:read',
190
        'message:read',
191
        'user_rel_user:read',
192
        'social_post:read',
193
        'user_subscriptions:sessions',
194
    ])]
195
    public ?string $illustrationUrl = null;
196
197
    #[Groups([
198
        'user:read',
199
        'course:read',
200
        'resource_node:read',
201
        'user_json:read',
202
        'message:read',
203
        'user_rel_user:read',
204
        'session:item:read',
205
    ])]
206
    #[ORM\Column(name: 'id', type: 'integer')]
207
    #[ORM\Id]
208
    #[ORM\GeneratedValue]
209
    protected ?int $id = null;
210
211
    #[Assert\NotBlank]
212
    #[Groups([
213
        'user_export',
214
        'user:read',
215
        'user:write',
216
        'course:read',
217
        'course_rel_user:read',
218
        'resource_node:read',
219
        'user_json:read',
220
        'message:read',
221
        'page:read',
222
        'user_rel_user:read',
223
        'social_post:read',
224
        'track_e_exercise:read',
225
        'user_subscriptions:sessions',
226
        'student_publication_rel_user:read',
227
    ])]
228
    #[ORM\Column(name: 'username', type: 'string', length: 100, unique: true)]
229
    protected string $username;
230
231
    #[ORM\Column(name: 'api_token', type: 'string', unique: true, nullable: true)]
232
    protected ?string $apiToken = null;
233
234
    #[ApiProperty(iris: ['http://schema.org/name'])]
235
    #[Groups(['user:read', 'user:write', 'resource_node:read', 'user_json:read', 'track_e_exercise:read', 'user_rel_user:read', 'user_subscriptions:sessions', 'student_publication_rel_user:read'])]
236
    #[ORM\Column(name: 'firstname', type: 'string', length: 64, nullable: true)]
237
    protected ?string $firstname = null;
238
239
    #[Groups(['user:read', 'user:write', 'resource_node:read', 'user_json:read', 'track_e_exercise:read', 'user_rel_user:read', 'user_subscriptions:sessions', 'student_publication_rel_user:read'])]
240
    #[ORM\Column(name: 'lastname', type: 'string', length: 64, nullable: true)]
241
    protected ?string $lastname = null;
242
243
    #[Groups(['user:read', 'user:write'])]
244
    #[ORM\Column(name: 'website', type: 'string', length: 255, nullable: true)]
245
    protected ?string $website;
246
247
    #[Groups(['user:read', 'user:write'])]
248
    #[ORM\Column(name: 'biography', type: 'text', nullable: true)]
249
    protected ?string $biography;
250
251
    #[Groups(['user:read', 'user:write', 'user_json:read'])]
252
    #[ORM\Column(name: 'locale', type: 'string', length: 10)]
253
    protected string $locale;
254
255
    #[Groups(['user:write'])]
256
    protected ?string $plainPassword = null;
257
258
    #[ORM\Column(name: 'password', type: 'string', length: 255)]
259
    protected string $password = '';
260
261
    #[ORM\Column(name: 'username_canonical', type: 'string', length: 180)]
262
    protected string $usernameCanonical;
263
264
    #[Groups(['user:read', 'user:write', 'user_json:read'])]
265
    #[ORM\Column(name: 'timezone', type: 'string', length: 64)]
266
    protected string $timezone;
267
268
    #[ORM\Column(name: 'email_canonical', type: 'string', length: 100)]
269
    protected string $emailCanonical;
270
271
    #[Groups(['user:read', 'user:write', 'user_json:read'])]
272
    #[Assert\NotBlank]
273
    #[Assert\Email]
274
    #[ORM\Column(name: 'email', type: 'string', length: 100)]
275
    protected string $email;
276
277
    #[ORM\Column(name: 'locked', type: 'boolean')]
278
    protected bool $locked;
279
280
    #[Groups(['user:read', 'user:write'])]
281
    #[ORM\Column(name: 'expired', type: 'boolean')]
282
    protected bool $expired;
283
284
    #[ORM\Column(name: 'credentials_expired', type: 'boolean')]
285
    protected bool $credentialsExpired;
286
287
    #[ORM\Column(name: 'credentials_expire_at', type: 'datetime', nullable: true)]
288
    protected ?DateTime $credentialsExpireAt;
289
290
    #[ORM\Column(name: 'date_of_birth', type: 'datetime', nullable: true)]
291
    protected ?DateTime $dateOfBirth = null;
292
293
    #[Groups(['user:read', 'user:write'])]
294
    #[ORM\Column(name: 'expires_at', type: 'datetime', nullable: true)]
295
    protected ?DateTime $expiresAt;
296
297
    #[Groups(['user:read', 'user:write'])]
298
    #[ORM\Column(name: 'phone', type: 'string', length: 64, nullable: true)]
299
    protected ?string $phone = null;
300
301
    #[Groups(['user:read', 'user:write'])]
302
    #[ORM\Column(name: 'address', type: 'string', length: 250, nullable: true)]
303
    protected ?string $address = null;
304
305
    #[ORM\Column(type: 'string', length: 255)]
306
    protected string $salt;
307
308
    #[ORM\Column(name: 'gender', type: 'string', length: 1, nullable: true)]
309
    protected ?string $gender = null;
310
311
    #[Groups(['user:read'])]
312
    #[ORM\Column(name: 'last_login', type: 'datetime', nullable: true)]
313
    protected ?DateTime $lastLogin = null;
314
315
    /**
316
     * Random string sent to the user email address in order to verify it.
317
     */
318
    #[ORM\Column(name: 'confirmation_token', type: 'string', length: 255, nullable: true)]
319
    protected ?string $confirmationToken = null;
320
321
    #[ORM\Column(name: 'password_requested_at', type: 'datetime', nullable: true)]
322
    protected ?DateTime $passwordRequestedAt;
323
324
    /**
325
     * @var Collection<int, CourseRelUser>
326
     */
327
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: CourseRelUser::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
328
    protected Collection $courses;
329
330
    /**
331
     * @var Collection<int, UsergroupRelUser>
332
     */
333
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: UsergroupRelUser::class)]
334
    protected Collection $classes;
335
336
    /**
337
     * ORM\OneToMany(targetEntity="Chamilo\CourseBundle\Entity\CDropboxPost", mappedBy="user").
338
     */
339
    protected Collection $dropBoxReceivedFiles;
340
341
    /**
342
     * ORM\OneToMany(targetEntity="Chamilo\CourseBundle\Entity\CDropboxFile", mappedBy="userSent").
343
     */
344
    protected Collection $dropBoxSentFiles;
345
346
    /**
347
     * An array of roles. Example: ROLE_USER, ROLE_TEACHER, ROLE_ADMIN.
348
     */
349
    #[Groups(['user:read', 'user:write', 'user_json:read'])]
350
    #[ORM\Column(type: 'array')]
351
    protected array $roles = [];
352
353
    #[ORM\Column(name: 'profile_completed', type: 'boolean', nullable: true)]
354
    protected ?bool $profileCompleted = null;
355
356
    /**
357
     * ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\JuryMembers", mappedBy="user").
358
     */
359
    // protected $jurySubscriptions;
360
361
    /**
362
     * @var Collection<int, Group>
363
     */
364
    #[ORM\JoinTable(name: 'fos_user_user_group')]
365
    #[ORM\JoinColumn(name: 'user_id', referencedColumnName: 'id', onDelete: 'cascade')]
366
    #[ORM\InverseJoinColumn(name: 'group_id', referencedColumnName: 'id')]
367
    #[ORM\ManyToMany(targetEntity: Group::class, inversedBy: 'users')]
368
    protected Collection $groups;
369
370
    /**
371
     * ORM\OneToMany(targetEntity="Chamilo\CoreBundle\Entity\CurriculumItemRelUser", mappedBy="user").
372
     */
373
    protected Collection $curriculumItems;
374
375
    /**
376
     * @var Collection<int, AccessUrlRelUser>
377
     */
378
    #[ORM\OneToMany(
379
        mappedBy: 'user',
380
        targetEntity: AccessUrlRelUser::class,
381
        cascade: ['persist', 'remove'],
382
        orphanRemoval: true
383
    )]
384
    protected Collection $portals;
385
386
    /**
387
     * @var Collection<int, ResourceNode>
388
     */
389
    #[ORM\OneToMany(mappedBy: 'creator', targetEntity: ResourceNode::class, cascade: ['persist', 'remove'])]
390
    protected Collection $resourceNodes;
391
392
    /**
393
     * @var Collection<int, SessionRelCourseRelUser>
394
     */
395
    #[ORM\OneToMany(
396
        mappedBy: 'user',
397
        targetEntity: SessionRelCourseRelUser::class,
398
        cascade: ['persist'],
399
        orphanRemoval: true
400
    )]
401
    protected Collection $sessionRelCourseRelUsers;
402
403
    /**
404
     * @var Collection<int, SessionRelUser>
405
     */
406
    #[ORM\OneToMany(
407
        mappedBy: 'user',
408
        targetEntity: SessionRelUser::class,
409
        cascade: ['persist', 'remove'],
410
        orphanRemoval: true
411
    )]
412
    protected Collection $sessionsRelUser;
413
414
    /**
415
     * @var Collection<int, SkillRelUser>
416
     */
417
    #[ORM\OneToMany(
418
        mappedBy: 'user',
419
        targetEntity: SkillRelUser::class,
420
        cascade: ['persist', 'remove'],
421
        orphanRemoval: true
422
    )]
423
    protected Collection $achievedSkills;
424
425
    /**
426
     * @var Collection<int, SkillRelUserComment>
427
     */
428
    #[ORM\OneToMany(
429
        mappedBy: 'feedbackGiver',
430
        targetEntity: SkillRelUserComment::class,
431
        cascade: ['persist', 'remove'],
432
        orphanRemoval: true
433
    )]
434
    protected Collection $commentedUserSkills;
435
436
    /**
437
     * @var Collection<int, GradebookCategory>
438
     */
439
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: GradebookCategory::class)]
440
    protected Collection $gradeBookCategories;
441
442
    /**
443
     * @var Collection<int, GradebookCertificate>
444
     */
445
    #[ORM\OneToMany(
446
        mappedBy: 'user',
447
        targetEntity: GradebookCertificate::class,
448
        cascade: ['persist', 'remove'],
449
        orphanRemoval: true
450
    )]
451
    protected Collection $gradeBookCertificates;
452
453
    /**
454
     * @var Collection<int, GradebookComment>
455
     */
456
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: GradebookComment::class)]
457
    protected Collection $gradeBookComments;
458
459
    /**
460
     * @var Collection<int, GradebookResult>
461
     */
462
    #[ORM\OneToMany(
463
        mappedBy: 'user',
464
        targetEntity: GradebookResult::class,
465
        cascade: ['persist', 'remove'],
466
        orphanRemoval: true
467
    )]
468
    protected Collection $gradeBookResults;
469
470
    /**
471
     * @var Collection<int, GradebookResultLog>
472
     */
473
    #[ORM\OneToMany(
474
        mappedBy: 'user',
475
        targetEntity: GradebookResultLog::class,
476
        cascade: ['persist', 'remove'],
477
        orphanRemoval: true
478
    )]
479
    protected Collection $gradeBookResultLogs;
480
481
    /**
482
     * @var Collection<int, GradebookScoreLog>
483
     */
484
    #[ORM\OneToMany(
485
        mappedBy: 'user',
486
        targetEntity: GradebookScoreLog::class,
487
        cascade: ['persist', 'remove'],
488
        orphanRemoval: true
489
    )]
490
    protected Collection $gradeBookScoreLogs;
491
492
    /**
493
     * @var Collection<int, UserRelUser>
494
     */
495
    #[ORM\OneToMany(
496
        mappedBy: 'user',
497
        targetEntity: UserRelUser::class,
498
        cascade: ['persist', 'remove'],
499
        fetch: 'EXTRA_LAZY',
500
        orphanRemoval: true
501
    )]
502
    protected Collection $friends;
503
504
    /**
505
     * @var Collection<int, UserRelUser>
506
     */
507
    #[ORM\OneToMany(
508
        mappedBy: 'friend',
509
        targetEntity: UserRelUser::class,
510
        cascade: ['persist', 'remove'],
511
        fetch: 'EXTRA_LAZY',
512
        orphanRemoval: true
513
    )]
514
    protected Collection $friendsWithMe;
515
516
    /**
517
     * @var Collection<int, GradebookLinkevalLog>
518
     */
519
    #[ORM\OneToMany(
520
        mappedBy: 'user',
521
        targetEntity: GradebookLinkevalLog::class,
522
        cascade: ['persist', 'remove'],
523
        orphanRemoval: true
524
    )]
525
    protected Collection $gradeBookLinkEvalLogs;
526
527
    /**
528
     * @var Collection<int, SequenceValue>
529
     */
530
    #[ORM\OneToMany(
531
        mappedBy: 'user',
532
        targetEntity: SequenceValue::class,
533
        cascade: ['persist', 'remove'],
534
        orphanRemoval: true
535
    )]
536
    protected Collection $sequenceValues;
537
538
    /**
539
     * @var Collection<int, TrackEExerciseConfirmation>
540
     */
541
    #[ORM\OneToMany(
542
        mappedBy: 'user',
543
        targetEntity: TrackEExerciseConfirmation::class,
544
        cascade: ['persist', 'remove'],
545
        orphanRemoval: true
546
    )]
547
    protected Collection $trackEExerciseConfirmations;
548
549
    /**
550
     * @var Collection<int, TrackEAttempt>
551
     */
552
    #[ORM\OneToMany(
553
        mappedBy: 'user',
554
        targetEntity: TrackEAccessComplete::class,
555
        cascade: [
556
            'persist',
557
            'remove',
558
        ],
559
        orphanRemoval: true
560
    )]
561
    protected Collection $trackEAccessCompleteList;
562
563
    /**
564
     * @var Collection<int, Templates>
565
     */
566
    #[ORM\OneToMany(
567
        mappedBy: 'user',
568
        targetEntity: Templates::class,
569
        cascade: ['persist', 'remove'],
570
        fetch: 'EXTRA_LAZY',
571
        orphanRemoval: true
572
    )]
573
    protected Collection $templates;
574
575
    /**
576
     * @var Collection<int, TrackEAttempt>
577
     */
578
    #[ORM\OneToMany(
579
        mappedBy: 'user',
580
        targetEntity: TrackEAttempt::class,
581
        cascade: ['persist', 'remove'],
582
        orphanRemoval: true
583
    )]
584
    protected Collection $trackEAttempts;
585
586
    /**
587
     * @var Collection<int, TrackECourseAccess>
588
     */
589
    #[ORM\OneToMany(
590
        mappedBy: 'user',
591
        targetEntity: TrackECourseAccess::class,
592
        cascade: ['persist', 'remove'],
593
        orphanRemoval: true
594
    )]
595
    protected Collection $trackECourseAccess;
596
597
    /**
598
     * @var Collection<int, UserCourseCategory>
599
     */
600
    #[ORM\OneToMany(
601
        mappedBy: 'user',
602
        targetEntity: UserCourseCategory::class,
603
        cascade: ['persist', 'remove'],
604
        orphanRemoval: true
605
    )]
606
    protected Collection $userCourseCategories;
607
608
    /**
609
     * @var Collection<int, UserRelCourseVote>
610
     */
611
    #[ORM\OneToMany(
612
        mappedBy: 'user',
613
        targetEntity: UserRelCourseVote::class,
614
        cascade: ['persist', 'remove'],
615
        orphanRemoval: true
616
    )]
617
    protected Collection $userRelCourseVotes;
618
619
    /**
620
     * @var Collection<int, UserRelTag>
621
     */
622
    #[ORM\OneToMany(
623
        mappedBy: 'user',
624
        targetEntity: UserRelTag::class,
625
        cascade: ['persist', 'remove'],
626
        orphanRemoval: true
627
    )]
628
    protected Collection $userRelTags;
629
630
    /**
631
     * @var Collection<int, CGroupRelUser>
632
     */
633
    #[ORM\OneToMany(
634
        mappedBy: 'user',
635
        targetEntity: CGroupRelUser::class,
636
        cascade: ['persist', 'remove'],
637
        orphanRemoval: true
638
    )]
639
    protected Collection $courseGroupsAsMember;
640
641
    /**
642
     * @var Collection<int, CGroupRelTutor>
643
     */
644
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: CGroupRelTutor::class, orphanRemoval: true)]
645
    protected Collection $courseGroupsAsTutor;
646
647
    #[ORM\Column(name: 'status', type: 'integer')]
648
    protected int $status;
649
650
    #[ORM\Column(name: 'official_code', type: 'string', length: 40, nullable: true)]
651
    protected ?string $officialCode = null;
652
653
    #[ORM\Column(name: 'picture_uri', type: 'string', length: 250, nullable: true)]
654
    protected ?string $pictureUri = null;
655
656
    #[ORM\Column(name: 'creator_id', type: 'integer', unique: false, nullable: true)]
657
    protected ?int $creatorId = null;
658
659
    #[ORM\Column(name: 'competences', type: 'text', unique: false, nullable: true)]
660
    protected ?string $competences = null;
661
662
    #[ORM\Column(name: 'diplomas', type: 'text', unique: false, nullable: true)]
663
    protected ?string $diplomas = null;
664
665
    #[ORM\Column(name: 'openarea', type: 'text', unique: false, nullable: true)]
666
    protected ?string $openarea = null;
667
668
    #[ORM\Column(name: 'teach', type: 'text', unique: false, nullable: true)]
669
    protected ?string $teach = null;
670
671
    #[ORM\Column(name: 'productions', type: 'string', length: 250, unique: false, nullable: true)]
672
    protected ?string $productions = null;
673
674
    #[ORM\Column(name: 'expiration_date', type: 'datetime', unique: false, nullable: true)]
675
    protected ?DateTime $expirationDate = null;
676
677
    #[Groups(['user:read', 'user_json:read'])]
678
    #[ORM\Column(name: 'active', type: 'integer')]
679
    protected int $active;
680
681
    #[ORM\Column(name: 'openid', type: 'string', length: 255, unique: false, nullable: true)]
682
    protected ?string $openid = null;
683
684
    #[ORM\Column(name: 'theme', type: 'string', length: 255, unique: false, nullable: true)]
685
    protected ?string $theme = null;
686
687
    #[ORM\Column(name: 'hr_dept_id', type: 'smallint', unique: false, nullable: true)]
688
    protected ?int $hrDeptId = null;
689
690
    #[Groups(['user:write'])]
691
    protected ?AccessUrl $currentUrl = null;
692
693
    /**
694
     * @var Collection<int, MessageTag>
695
     */
696
    #[ORM\OneToMany(
697
        mappedBy: 'user',
698
        targetEntity: MessageTag::class,
699
        cascade: ['persist', 'remove'],
700
        orphanRemoval: true
701
    )]
702
    protected Collection $messageTags;
703
704
    /**
705
     * @var Collection<int, Message>
706
     */
707
    #[ORM\OneToMany(
708
        mappedBy: 'sender',
709
        targetEntity: Message::class,
710
        cascade: ['persist']
711
    )]
712
    protected Collection $sentMessages;
713
714
    /**
715
     * @var Collection<int, MessageRelUser>
716
     */
717
    #[ORM\OneToMany(mappedBy: 'receiver', targetEntity: MessageRelUser::class, cascade: ['persist', 'remove'])]
718
    protected Collection $receivedMessages;
719
720
    /**
721
     * @var Collection<int, CSurveyInvitation>
722
     */
723
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: CSurveyInvitation::class, cascade: ['persist', 'remove'])]
724
    protected Collection $surveyInvitations;
725
726
    /**
727
     * @var Collection<int, TrackELogin>
728
     */
729
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: TrackELogin::class, cascade: ['persist', 'remove'])]
730
    protected Collection $logins;
731
732
    #[ORM\OneToOne(mappedBy: 'user', targetEntity: Admin::class, cascade: ['persist', 'remove'], orphanRemoval: true)]
733
    protected ?Admin $admin = null;
734
735
    #[ORM\Column(type: 'uuid', unique: true)]
736
    protected Uuid $uuid;
737
738
    // Property used only during installation.
739
    protected bool $skipResourceNode = false;
740
741
    #[Groups([
742
        'user:read',
743
        'user_json:read',
744
        'social_post:read',
745
        'course:read',
746
        'course_rel_user:read',
747
        'message:read',
748
        'user_subscriptions:sessions',
749
        'student_publication_rel_user:read',
750
        'student_publication:read',
751
        'student_publication_comment:read',
752
    ])]
753
    protected string $fullName;
754
755
    #[ORM\OneToMany(mappedBy: 'sender', targetEntity: SocialPost::class, orphanRemoval: true)]
756
    private Collection $sentSocialPosts;
757
758
    #[ORM\OneToMany(mappedBy: 'userReceiver', targetEntity: SocialPost::class)]
759
    private Collection $receivedSocialPosts;
760
761
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: SocialPostFeedback::class, orphanRemoval: true)]
762
    private Collection $socialPostsFeedbacks;
763
764
    #[ORM\Column(name: 'mfa_enabled', type: 'boolean', options: ['default' => false])]
765
    protected bool $mfaEnabled = false;
766
767
    #[ORM\Column(name: 'mfa_service', type: 'string', length: 255, nullable: true)]
768
    protected ?string $mfaService = null;
769
770
    #[ORM\Column(name: 'mfa_secret', type: 'string', length: 255, nullable: true)]
771
    protected ?string $mfaSecret = null;
772
773
    #[ORM\Column(name: 'mfa_backup_codes', type: 'text', nullable: true)]
774
    protected ?string $mfaBackupCodes = null;
775
776
    #[ORM\Column(name: 'mfa_last_used', type: 'datetime', nullable: true)]
777
    protected ?DateTimeInterface $mfaLastUsed = null;
778
779
    /**
780
     * @var Collection<int, UserAuthSource>
781
     */
782
    #[ORM\OneToMany(mappedBy: 'user', targetEntity: UserAuthSource::class, cascade: ['persist'], orphanRemoval: true)]
783
    private Collection $authSources;
784
785
    #[Groups(['user:read', 'user:write'])]
786
    #[ORM\Column(name: 'password_updated_at', type: 'datetime', nullable: true)]
787
    protected ?DateTimeInterface $passwordUpdatedAt = null;
788
789
    public function __construct()
790
    {
791
        $this->skipResourceNode = false;
792
        $this->uuid = Uuid::v4();
793
        $this->apiToken = null;
794
        $this->biography = '';
795
        $this->website = '';
796
        $this->locale = 'en';
797
        $this->timezone = 'Europe/Paris';
798
        $this->status = CourseRelUser::STUDENT;
799
        $this->salt = sha1(uniqid('', true));
800
        $this->active = 1;
801
        $this->locked = false;
802
        $this->expired = false;
803
        $this->courses = new ArrayCollection();
804
        $this->classes = new ArrayCollection();
805
        $this->curriculumItems = new ArrayCollection();
806
        $this->portals = new ArrayCollection();
807
        $this->dropBoxSentFiles = new ArrayCollection();
808
        $this->dropBoxReceivedFiles = new ArrayCollection();
809
        $this->groups = new ArrayCollection();
810
        $this->gradeBookCertificates = new ArrayCollection();
811
        $this->courseGroupsAsMember = new ArrayCollection();
812
        $this->courseGroupsAsTutor = new ArrayCollection();
813
        $this->resourceNodes = new ArrayCollection();
814
        $this->sessionRelCourseRelUsers = new ArrayCollection();
815
        $this->achievedSkills = new ArrayCollection();
816
        $this->commentedUserSkills = new ArrayCollection();
817
        $this->gradeBookCategories = new ArrayCollection();
818
        $this->gradeBookComments = new ArrayCollection();
819
        $this->gradeBookResults = new ArrayCollection();
820
        $this->gradeBookResultLogs = new ArrayCollection();
821
        $this->gradeBookScoreLogs = new ArrayCollection();
822
        $this->friends = new ArrayCollection();
823
        $this->friendsWithMe = new ArrayCollection();
824
        $this->gradeBookLinkEvalLogs = new ArrayCollection();
825
        $this->messageTags = new ArrayCollection();
826
        $this->sequenceValues = new ArrayCollection();
827
        $this->trackEExerciseConfirmations = new ArrayCollection();
828
        $this->trackEAccessCompleteList = new ArrayCollection();
829
        $this->templates = new ArrayCollection();
830
        $this->trackEAttempts = new ArrayCollection();
831
        $this->trackECourseAccess = new ArrayCollection();
832
        $this->userCourseCategories = new ArrayCollection();
833
        $this->userRelCourseVotes = new ArrayCollection();
834
        $this->userRelTags = new ArrayCollection();
835
        $this->sessionsRelUser = new ArrayCollection();
836
        $this->sentMessages = new ArrayCollection();
837
        $this->receivedMessages = new ArrayCollection();
838
        $this->surveyInvitations = new ArrayCollection();
839
        $this->logins = new ArrayCollection();
840
        $this->createdAt = new DateTime();
841
        $this->updatedAt = new DateTime();
842
        $this->roles = [];
843
        $this->credentialsExpired = false;
844
        $this->credentialsExpireAt = new DateTime();
845
        $this->dateOfBirth = null;
846
        $this->expiresAt = new DateTime();
847
        $this->passwordRequestedAt = new DateTime();
848
        $this->sentSocialPosts = new ArrayCollection();
849
        $this->receivedSocialPosts = new ArrayCollection();
850
        $this->socialPostsFeedbacks = new ArrayCollection();
851
        $this->authSources = new ArrayCollection();
852
    }
853
854
    public function __toString(): string
855
    {
856
        return $this->username;
857
    }
858
859
    public static function getPasswordConstraints(): array
860
    {
861
        return [
862
            new Assert\Length(['min' => 5]),
863
            new Assert\Regex(['pattern' => '/^[a-z\-_0-9]+$/i', 'htmlPattern' => '/^[a-z\-_0-9]+$/i']),
864
            new Assert\Regex(['pattern' => '/[0-9]{2}/', 'htmlPattern' => '/[0-9]{2}/']),
865
        ];
866
    }
867
868
    public static function loadValidatorMetadata(ClassMetadata $metadata): void {}
869
870
    public function getUuid(): Uuid
871
    {
872
        return $this->uuid;
873
    }
874
875
    public function setUuid(Uuid $uuid): self
876
    {
877
        $this->uuid = $uuid;
878
879
        return $this;
880
    }
881
882
    public function getResourceNode(): ?ResourceNode
883
    {
884
        return $this->resourceNode;
885
    }
886
887
    public function setResourceNode(ResourceNode $resourceNode): self
888
    {
889
        $this->resourceNode = $resourceNode;
890
891
        return $this;
892
    }
893
894
    public function hasResourceNode(): bool
895
    {
896
        return $this->resourceNode instanceof ResourceNode;
897
    }
898
899
    public function getResourceNodes(): Collection
900
    {
901
        return $this->resourceNodes;
902
    }
903
904
    public function addResourceNode(ResourceNode $resourceNode): static
905
    {
906
        if (!$this->resourceNodes->contains($resourceNode)) {
907
            $this->resourceNodes->add($resourceNode);
908
            $resourceNode->setCreator($this);
909
        }
910
911
        return $this;
912
    }
913
914
    public function getDropBoxSentFiles(): Collection
915
    {
916
        return $this->dropBoxSentFiles;
917
    }
918
919
    public function setDropBoxSentFiles(Collection $value): self
920
    {
921
        $this->dropBoxSentFiles = $value;
922
923
        return $this;
924
    }
925
926
    public function getCourses(): Collection
927
    {
928
        return $this->courses;
929
    }
930
931
    /**
932
     * @param Collection<int, CourseRelUser> $courses
933
     */
934
    public function setCourses(Collection $courses): self
935
    {
936
        $this->courses = $courses;
937
938
        return $this;
939
    }
940
941
    public function setPortal(AccessUrlRelUser $portal): self
942
    {
943
        $this->portals->add($portal);
944
945
        return $this;
946
    }
947
948
    /**
949
     * Get a bool on whether the user is active or not. Active can be "-1" which means pre-deleted, and is returned as false (not active).
950
     *
951
     * @return bool True if active = 1, false in any other case (0 = inactive, -1 = predeleted)
952
     */
953
    public function getIsActive(): bool
954
    {
955
        return 1 === $this->active;
956
    }
957
958
    public function isEnabled(): bool
959
    {
960
        return $this->isActive();
961
    }
962
963
    /**
964
     * Returns the list of classes for the user.
965
     */
966
    public function getFullNameWithClasses(): string
967
    {
968
        $classSubscription = $this->getClasses();
969
        $classList = [];
970
971
        /** @var UsergroupRelUser $subscription */
972
        foreach ($classSubscription as $subscription) {
973
            $class = $subscription->getUsergroup();
974
            $classList[] = $class->getTitle();
975
        }
976
        $classString = empty($classList) ? null : ' ['.implode(', ', $classList).']';
977
978
        return UserManager::formatUserFullName($this).$classString;
979
    }
980
981
    public function getClasses(): Collection
982
    {
983
        return $this->classes;
984
    }
985
986
    /**
987
     * @param Collection<int, UsergroupRelUser> $classes
988
     */
989
    public function setClasses(Collection $classes): self
990
    {
991
        $this->classes = $classes;
992
993
        return $this;
994
    }
995
996
    public function getEmail(): string
997
    {
998
        return $this->email;
999
    }
1000
1001
    public function setEmail(string $email): self
1002
    {
1003
        $this->email = $email;
1004
1005
        return $this;
1006
    }
1007
1008
    public function getOfficialCode(): ?string
1009
    {
1010
        return $this->officialCode;
1011
    }
1012
1013
    public function setOfficialCode(?string $officialCode): self
1014
    {
1015
        $this->officialCode = $officialCode;
1016
1017
        return $this;
1018
    }
1019
1020
    public function getPhone(): ?string
1021
    {
1022
        return $this->phone;
1023
    }
1024
1025
    public function setPhone(?string $phone): self
1026
    {
1027
        $this->phone = $phone;
1028
1029
        return $this;
1030
    }
1031
1032
    public function getAddress(): ?string
1033
    {
1034
        return $this->address;
1035
    }
1036
1037
    public function setAddress(?string $address): self
1038
    {
1039
        $this->address = $address;
1040
1041
        return $this;
1042
    }
1043
1044
    public function getCreatorId(): ?int
1045
    {
1046
        return $this->creatorId;
1047
    }
1048
1049
    public function setCreatorId(int $creatorId): self
1050
    {
1051
        $this->creatorId = $creatorId;
1052
1053
        return $this;
1054
    }
1055
1056
    public function getCompetences(): ?string
1057
    {
1058
        return $this->competences;
1059
    }
1060
1061
    public function setCompetences(?string $competences): self
1062
    {
1063
        $this->competences = $competences;
1064
1065
        return $this;
1066
    }
1067
1068
    public function getDiplomas(): ?string
1069
    {
1070
        return $this->diplomas;
1071
    }
1072
1073
    public function setDiplomas(?string $diplomas): self
1074
    {
1075
        $this->diplomas = $diplomas;
1076
1077
        return $this;
1078
    }
1079
1080
    public function getOpenarea(): ?string
1081
    {
1082
        return $this->openarea;
1083
    }
1084
1085
    public function setOpenarea(?string $openarea): self
1086
    {
1087
        $this->openarea = $openarea;
1088
1089
        return $this;
1090
    }
1091
1092
    public function getTeach(): ?string
1093
    {
1094
        return $this->teach;
1095
    }
1096
1097
    public function setTeach(?string $teach): self
1098
    {
1099
        $this->teach = $teach;
1100
1101
        return $this;
1102
    }
1103
1104
    public function getProductions(): ?string
1105
    {
1106
        return $this->productions;
1107
    }
1108
1109
    public function setProductions(?string $productions): self
1110
    {
1111
        $this->productions = $productions;
1112
1113
        return $this;
1114
    }
1115
1116
    public function getExpirationDate(): ?DateTime
1117
    {
1118
        return $this->expirationDate;
1119
    }
1120
1121
    public function setExpirationDate(?DateTime $expirationDate): self
1122
    {
1123
        $this->expirationDate = $expirationDate;
1124
1125
        return $this;
1126
    }
1127
1128
    public function getActive(): int
1129
    {
1130
        return $this->active;
1131
    }
1132
1133
    public function isActive(): bool
1134
    {
1135
        return $this->getIsActive();
1136
    }
1137
1138
    public function setActive(int $active): self
1139
    {
1140
        $this->active = $active;
1141
1142
        return $this;
1143
    }
1144
1145
    public function getOpenid(): ?string
1146
    {
1147
        return $this->openid;
1148
    }
1149
1150
    public function setOpenid(string $openid): self
1151
    {
1152
        $this->openid = $openid;
1153
1154
        return $this;
1155
    }
1156
1157
    public function getTheme(): ?string
1158
    {
1159
        return $this->theme;
1160
    }
1161
1162
    public function setTheme(string $theme): self
1163
    {
1164
        $this->theme = $theme;
1165
1166
        return $this;
1167
    }
1168
1169
    public function getHrDeptId(): ?int
1170
    {
1171
        return $this->hrDeptId;
1172
    }
1173
1174
    public function setHrDeptId(int $hrDeptId): self
1175
    {
1176
        $this->hrDeptId = $hrDeptId;
1177
1178
        return $this;
1179
    }
1180
1181
    public function isOnline(): bool
1182
    {
1183
        return false;
1184
    }
1185
1186
    public function getIdentifier(): int
1187
    {
1188
        return $this->getId();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->getId() could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
1189
    }
1190
1191
    public function getId(): ?int
1192
    {
1193
        return $this->id;
1194
    }
1195
1196
    public function getIri(): ?string
1197
    {
1198
        if (null === $this->id) {
1199
            return null;
1200
        }
1201
1202
        return '/api/users/'.$this->getId();
1203
    }
1204
1205
    public function getSlug(): string
1206
    {
1207
        return $this->getUsername();
1208
    }
1209
1210
    public function getUsername(): string
1211
    {
1212
        return $this->username;
1213
    }
1214
1215
    public function setUsername(string $username): self
1216
    {
1217
        $this->username = $username;
1218
1219
        return $this;
1220
    }
1221
1222
    public function setSlug(string $slug): self
1223
    {
1224
        return $this->setUsername($slug);
1225
    }
1226
1227
    public function getLastLogin(): ?DateTime
1228
    {
1229
        return $this->lastLogin;
1230
    }
1231
1232
    public function setLastLogin(?DateTime $lastLogin = null): self
1233
    {
1234
        $this->lastLogin = $lastLogin;
1235
1236
        return $this;
1237
    }
1238
1239
    public function getConfirmationToken(): ?string
1240
    {
1241
        return $this->confirmationToken;
1242
    }
1243
1244
    public function setConfirmationToken(string $confirmationToken): self
1245
    {
1246
        $this->confirmationToken = $confirmationToken;
1247
1248
        return $this;
1249
    }
1250
1251
    public function isPasswordRequestNonExpired(int $ttl): bool
1252
    {
1253
        return $this->getPasswordRequestedAt() instanceof DateTime && $this->getPasswordRequestedAt()->getTimestamp(
1254
        ) + $ttl > time();
1255
    }
1256
1257
    public function getPasswordRequestedAt(): ?DateTime
1258
    {
1259
        return $this->passwordRequestedAt;
1260
    }
1261
1262
    public function setPasswordRequestedAt(?DateTime $date = null): self
1263
    {
1264
        $this->passwordRequestedAt = $date;
1265
1266
        return $this;
1267
    }
1268
1269
    public function getPlainPassword(): ?string
1270
    {
1271
        return $this->plainPassword;
1272
    }
1273
1274
    public function setPlainPassword(?string $password): self
1275
    {
1276
        $this->plainPassword = $password;
1277
        // forces the object to look "dirty" to Doctrine. Avoids
1278
        // Doctrine *not* saving this entity, if only plainPassword changes
1279
        $this->password = '';
1280
1281
        return $this;
1282
    }
1283
1284
    /**
1285
     * Returns the expiration date.
1286
     */
1287
    public function getExpiresAt(): ?DateTime
1288
    {
1289
        return $this->expiresAt;
1290
    }
1291
1292
    public function setExpiresAt(DateTime $date): self
1293
    {
1294
        $this->expiresAt = $date;
1295
1296
        return $this;
1297
    }
1298
1299
    /**
1300
     * Returns the credentials expiration date.
1301
     */
1302
    public function getCredentialsExpireAt(): ?DateTime
1303
    {
1304
        return $this->credentialsExpireAt;
1305
    }
1306
1307
    /**
1308
     * Sets the credentials expiration date.
1309
     */
1310
    public function setCredentialsExpireAt(?DateTime $date = null): self
1311
    {
1312
        $this->credentialsExpireAt = $date;
1313
1314
        return $this;
1315
    }
1316
1317
    public function getFullName(): string
1318
    {
1319
        if (empty($this->fullName)) {
1320
            return \sprintf('%s %s', $this->getFirstname(), $this->getLastname());
1321
        }
1322
1323
        return $this->fullName;
1324
    }
1325
1326
    public function setFullName(string $fullName): self
1327
    {
1328
        $this->fullName = $fullName;
1329
1330
        return $this;
1331
    }
1332
1333
    public function getFirstname(): ?string
1334
    {
1335
        return $this->firstname;
1336
    }
1337
1338
    public function setFirstname(?string $firstname): self
1339
    {
1340
        $this->firstname = $firstname;
1341
1342
        return $this;
1343
    }
1344
1345
    public function getLastname(): ?string
1346
    {
1347
        return $this->lastname;
1348
    }
1349
1350
    public function setLastname(?string $lastname): self
1351
    {
1352
        $this->lastname = $lastname;
1353
1354
        return $this;
1355
    }
1356
1357
    public function hasGroup(string $name): bool
1358
    {
1359
        return \in_array($name, $this->getGroupNames(), true);
1360
    }
1361
1362
    public function getGroupNames(): array
1363
    {
1364
        $names = [];
1365
        foreach ($this->getGroups() as $group) {
1366
            $names[] = $group->getTitle();
1367
        }
1368
1369
        return $names;
1370
    }
1371
1372
    public function getGroups(): Collection
1373
    {
1374
        return $this->groups;
1375
    }
1376
1377
    /**
1378
     * Sets the user groups.
1379
     */
1380
    public function setGroups(Collection $groups): self
1381
    {
1382
        foreach ($groups as $group) {
1383
            $this->addGroup($group);
1384
        }
1385
1386
        return $this;
1387
    }
1388
1389
    public function addGroup(Group $group): self
1390
    {
1391
        if (!$this->getGroups()->contains($group)) {
1392
            $this->getGroups()->add($group);
1393
        }
1394
1395
        return $this;
1396
    }
1397
1398
    public function removeGroup(Group $group): self
1399
    {
1400
        if ($this->getGroups()->contains($group)) {
1401
            $this->getGroups()->removeElement($group);
1402
        }
1403
1404
        return $this;
1405
    }
1406
1407
    public function isAccountNonExpired(): bool
1408
    {
1409
        return true;
1410
    }
1411
1412
    public function isAccountNonLocked(): bool
1413
    {
1414
        return true;
1415
    }
1416
1417
    public function isCredentialsNonExpired(): bool
1418
    {
1419
        return true;
1420
    }
1421
1422
    public function getCredentialsExpired(): bool
1423
    {
1424
        return $this->credentialsExpired;
1425
    }
1426
1427
    public function setCredentialsExpired(bool $boolean): self
1428
    {
1429
        $this->credentialsExpired = $boolean;
1430
1431
        return $this;
1432
    }
1433
1434
    public function getExpired(): bool
1435
    {
1436
        return $this->expired;
1437
    }
1438
1439
    /**
1440
     * Sets this user to expired.
1441
     */
1442
    public function setExpired(bool $boolean): self
1443
    {
1444
        $this->expired = $boolean;
1445
1446
        return $this;
1447
    }
1448
1449
    public function getLocked(): bool
1450
    {
1451
        return $this->locked;
1452
    }
1453
1454
    public function setLocked(bool $boolean): self
1455
    {
1456
        $this->locked = $boolean;
1457
1458
        return $this;
1459
    }
1460
1461
    /**
1462
     * Check if the user has the skill.
1463
     *
1464
     * @param Skill $skill The skill
1465
     */
1466
    public function hasSkill(Skill $skill): bool
1467
    {
1468
        $achievedSkills = $this->getAchievedSkills();
1469
        foreach ($achievedSkills as $userSkill) {
1470
            if ($userSkill->getSkill()->getId() !== $skill->getId()) {
1471
                continue;
1472
            }
1473
1474
            return true;
1475
        }
1476
1477
        return false;
1478
    }
1479
1480
    /**
1481
     * @return Collection<int, SkillRelUser>
1482
     */
1483
    public function getAchievedSkills(): Collection
1484
    {
1485
        return $this->achievedSkills;
1486
    }
1487
1488
    /**
1489
     * @param Collection<int, SkillRelUser> $value
1490
     */
1491
    public function setAchievedSkills(Collection $value): self
1492
    {
1493
        $this->achievedSkills = $value;
1494
1495
        return $this;
1496
    }
1497
1498
    public function isProfileCompleted(): ?bool
1499
    {
1500
        return $this->profileCompleted;
1501
    }
1502
1503
    public function setProfileCompleted(?bool $profileCompleted): self
1504
    {
1505
        $this->profileCompleted = $profileCompleted;
1506
1507
        return $this;
1508
    }
1509
1510
    public function getCurrentUrl(): ?AccessUrl
1511
    {
1512
        return $this->currentUrl;
1513
    }
1514
1515
    public function setCurrentUrl(AccessUrl $url): self
1516
    {
1517
        $accessUrlRelUser = (new AccessUrlRelUser())->setUrl($url)->setUser($this);
1518
        $this->getPortals()->add($accessUrlRelUser);
1519
1520
        return $this;
1521
    }
1522
1523
    /**
1524
     * @return Collection<int, AccessUrlRelUser>
1525
     */
1526
    public function getPortals(): Collection
1527
    {
1528
        return $this->portals;
1529
    }
1530
1531
    /**
1532
     * @param Collection<int, AccessUrlRelUser> $value
1533
     */
1534
    public function setPortals(Collection $value): void
1535
    {
1536
        $this->portals = $value;
1537
    }
1538
1539
    public function getSessionsAsGeneralCoach(): array
1540
    {
1541
        return $this->getSessions(Session::GENERAL_COACH);
1542
    }
1543
1544
    /**
1545
     * Retrieves this user's related sessions.
1546
     */
1547
    public function getSessions(int $relationType): array
1548
    {
1549
        $sessions = [];
1550
        foreach ($this->getSessionsRelUser() as $sessionRelUser) {
1551
            if ($sessionRelUser->getRelationType() === $relationType) {
1552
                $sessions[] = $sessionRelUser->getSession();
1553
            }
1554
        }
1555
1556
        return $sessions;
1557
    }
1558
1559
    /**
1560
     * @return Collection<int, SessionRelUser>
1561
     */
1562
    public function getSessionsRelUser(): Collection
1563
    {
1564
        return $this->sessionsRelUser;
1565
    }
1566
1567
    public function getSessionsAsAdmin(): array
1568
    {
1569
        return $this->getSessions(Session::SESSION_ADMIN);
1570
    }
1571
1572
    public function getCommentedUserSkills(): Collection
1573
    {
1574
        return $this->commentedUserSkills;
1575
    }
1576
1577
    /**
1578
     * @param Collection<int, SkillRelUserComment> $commentedUserSkills
1579
     */
1580
    public function setCommentedUserSkills(Collection $commentedUserSkills): self
1581
    {
1582
        $this->commentedUserSkills = $commentedUserSkills;
1583
1584
        return $this;
1585
    }
1586
1587
    public function isEqualTo(UserInterface $user): bool
1588
    {
1589
        if ($this->password !== $user->getPassword()) {
1590
            return false;
1591
        }
1592
        if ($this->salt !== $user->getSalt()) {
1593
            return false;
1594
        }
1595
        if ($this->username !== $user->getUserIdentifier()) {
1596
            return false;
1597
        }
1598
1599
        return true;
1600
    }
1601
1602
    public function getPassword(): ?string
1603
    {
1604
        return $this->password;
1605
    }
1606
1607
    public function setPassword(string $password): self
1608
    {
1609
        $this->password = $password;
1610
1611
        return $this;
1612
    }
1613
1614
    public function getSalt(): ?string
1615
    {
1616
        return $this->salt;
1617
    }
1618
1619
    public function setSalt(string $salt): self
1620
    {
1621
        $this->salt = $salt;
1622
1623
        return $this;
1624
    }
1625
1626
    public function getUserIdentifier(): string
1627
    {
1628
        return $this->username;
1629
    }
1630
1631
    /**
1632
     * @return Collection<int, Message>
1633
     */
1634
    public function getSentMessages(): Collection
1635
    {
1636
        return $this->sentMessages;
1637
    }
1638
1639
    public function getReceivedMessages(): Collection
1640
    {
1641
        return $this->receivedMessages;
1642
    }
1643
1644
    public function getCourseGroupsAsMember(): Collection
1645
    {
1646
        return $this->courseGroupsAsMember;
1647
    }
1648
1649
    public function getCourseGroupsAsTutor(): Collection
1650
    {
1651
        return $this->courseGroupsAsTutor;
1652
    }
1653
1654
    public function getCourseGroupsAsMemberFromCourse(Course $course): Collection
1655
    {
1656
        $criteria = Criteria::create();
1657
        $criteria->where(Criteria::expr()->eq('cId', $course));
1658
1659
        return $this->courseGroupsAsMember->matching($criteria);
1660
    }
1661
1662
    public function eraseCredentials(): void
1663
    {
1664
        $this->plainPassword = null;
1665
    }
1666
1667
    /**
1668
     * Returns whether a user can be admin of all multi-URL portals in the case of a multi-URL install.
1669
     */
1670
    public function isSuperAdmin(): bool
1671
    {
1672
        // Treat "global admin" as super-admin
1673
        return $this->hasRole('ROLE_GLOBAL_ADMIN');
1674
    }
1675
1676
    public function hasRole(string $role): bool
1677
    {
1678
        return \in_array(strtoupper($role), $this->getRoles(), true);
1679
    }
1680
1681
    /**
1682
     * Returns the user roles.
1683
     */
1684
    public function getRoles(): array
1685
    {
1686
        $roles = $this->roles;
1687
        foreach ($this->getGroups() as $group) {
1688
            $roles = array_merge($roles, $group->getRoles());
1689
        }
1690
        // we need to make sure to have at least one role
1691
        $roles[] = 'ROLE_USER';
1692
1693
        return array_unique($roles);
1694
    }
1695
1696
    public function setRoles(array $roles): self
1697
    {
1698
        $this->roles = [];
1699
        foreach ($roles as $role) {
1700
            $this->addRole($role);
1701
        }
1702
1703
        return $this;
1704
    }
1705
1706
    public function setRoleFromStatus(int $status): void
1707
    {
1708
        $role = self::getRoleFromStatus($status);
1709
        $this->addRole($role);
1710
    }
1711
1712
    public static function getRoleFromStatus(int $status): string
1713
    {
1714
        return match ($status) {
1715
            COURSEMANAGER => 'ROLE_TEACHER',
1716
            STUDENT => 'ROLE_STUDENT',
1717
            DRH => 'ROLE_HR',
1718
            SESSIONADMIN => 'ROLE_SESSION_MANAGER',
1719
            STUDENT_BOSS => 'ROLE_STUDENT_BOSS',
1720
            INVITEE => 'ROLE_INVITEE',
1721
            default => 'ROLE_USER',
1722
        };
1723
    }
1724
1725
    public function addRole(string $role): self
1726
    {
1727
        $role = strtoupper($role);
1728
        if ($role === static::ROLE_DEFAULT || empty($role)) {
1729
            return $this;
1730
        }
1731
        if (!\in_array($role, $this->roles, true)) {
1732
            $this->roles[] = $role;
1733
        }
1734
1735
        return $this;
1736
    }
1737
1738
    public function removeRole(string $role): self
1739
    {
1740
        if (false !== ($key = array_search(strtoupper($role), $this->roles, true))) {
1741
            unset($this->roles[$key]);
1742
            $this->roles = array_values($this->roles);
1743
        }
1744
1745
        return $this;
1746
    }
1747
1748
    public function getUsernameCanonical(): string
1749
    {
1750
        return $this->usernameCanonical;
1751
    }
1752
1753
    public function setUsernameCanonical(string $usernameCanonical): self
1754
    {
1755
        $this->usernameCanonical = $usernameCanonical;
1756
1757
        return $this;
1758
    }
1759
1760
    public function getEmailCanonical(): string
1761
    {
1762
        return $this->emailCanonical;
1763
    }
1764
1765
    public function setEmailCanonical(string $emailCanonical): self
1766
    {
1767
        $this->emailCanonical = $emailCanonical;
1768
1769
        return $this;
1770
    }
1771
1772
    public function getTimezone(): string
1773
    {
1774
        return $this->timezone;
1775
    }
1776
1777
    public function setTimezone(string $timezone): self
1778
    {
1779
        $this->timezone = $timezone;
1780
1781
        return $this;
1782
    }
1783
1784
    public function getLocale(): string
1785
    {
1786
        return $this->locale;
1787
    }
1788
1789
    public function setLocale(string $locale): self
1790
    {
1791
        $this->locale = $locale;
1792
1793
        return $this;
1794
    }
1795
1796
    public function getApiToken(): ?string
1797
    {
1798
        return $this->apiToken;
1799
    }
1800
1801
    public function setApiToken(string $apiToken): self
1802
    {
1803
        $this->apiToken = $apiToken;
1804
1805
        return $this;
1806
    }
1807
1808
    public function getWebsite(): ?string
1809
    {
1810
        return $this->website;
1811
    }
1812
1813
    public function setWebsite(string $website): self
1814
    {
1815
        $this->website = $website;
1816
1817
        return $this;
1818
    }
1819
1820
    public function getBiography(): ?string
1821
    {
1822
        return $this->biography;
1823
    }
1824
1825
    public function setBiography(string $biography): self
1826
    {
1827
        $this->biography = $biography;
1828
1829
        return $this;
1830
    }
1831
1832
    public function getDateOfBirth(): ?DateTime
1833
    {
1834
        return $this->dateOfBirth;
1835
    }
1836
1837
    public function setDateOfBirth(?DateTime $dateOfBirth = null): self
1838
    {
1839
        $this->dateOfBirth = $dateOfBirth;
1840
1841
        return $this;
1842
    }
1843
1844
    public function getProfileUrl(): string
1845
    {
1846
        return '/main/social/profile.php?u='.$this->id;
1847
    }
1848
1849
    public function getIconStatus(): string
1850
    {
1851
        $hasCertificates = $this->getGradeBookCertificates()->count() > 0;
1852
        $urlImg = '/img/';
1853
        if ($this->isStudent()) {
1854
            $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1855
            if ($hasCertificates) {
1856
                $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1857
            }
1858
1859
            return $iconStatus;
1860
        }
1861
        if ($this->isTeacher()) {
1862
            $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1863
            if ($this->isAdmin()) {
1864
                $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1865
            }
1866
1867
            return $iconStatus;
1868
        }
1869
        if ($this->isStudentBoss()) {
1870
            return $urlImg.'icons/svg/identifier_teacher.svg';
1871
        }
1872
1873
        return '';
1874
    }
1875
1876
    public function getGradeBookCertificates(): Collection
1877
    {
1878
        return $this->gradeBookCertificates;
1879
    }
1880
1881
    /**
1882
     * @param Collection<int, GradebookCertificate> $gradeBookCertificates
1883
     */
1884
    public function setGradeBookCertificates(Collection $gradeBookCertificates): self
1885
    {
1886
        $this->gradeBookCertificates = $gradeBookCertificates;
1887
1888
        return $this;
1889
    }
1890
1891
    public function isStudent(): bool
1892
    {
1893
        return $this->hasRole('ROLE_STUDENT');
1894
    }
1895
1896
    public function isTeacher(): bool
1897
    {
1898
        return $this->hasRole('ROLE_TEACHER');
1899
    }
1900
1901
    public function isAdmin(): bool
1902
    {
1903
        return $this->hasRole('ROLE_ADMIN');
1904
    }
1905
1906
    public function isStudentBoss(): bool
1907
    {
1908
        return $this->hasRole('ROLE_STUDENT_BOSS');
1909
    }
1910
1911
    public function isSessionAdmin(): bool
1912
    {
1913
        return $this->hasRole('ROLE_SESSION_MANAGER');
1914
    }
1915
1916
    public function isInvitee(): bool
1917
    {
1918
        return $this->hasRole('ROLE_INVITEE');
1919
    }
1920
1921
    public function isHRM(): bool
1922
    {
1923
        return $this->hasRole('ROLE_HR');
1924
    }
1925
1926
    public function getStatus(): int
1927
    {
1928
        return $this->status;
1929
    }
1930
1931
    public function setStatus(int $status): self
1932
    {
1933
        $this->status = $status;
1934
1935
        return $this;
1936
    }
1937
1938
    public function getPictureUri(): ?string
1939
    {
1940
        return $this->pictureUri;
1941
    }
1942
1943
    /**
1944
     * @return Collection<int, GradebookCategory>
1945
     */
1946
    public function getGradeBookCategories(): Collection
1947
    {
1948
        return $this->gradeBookCategories;
1949
    }
1950
1951
    /**
1952
     * @return Collection<int, GradebookComment>
1953
     */
1954
    public function getGradeBookComments(): Collection
1955
    {
1956
        return $this->gradeBookComments;
1957
    }
1958
1959
    /**
1960
     * @return Collection<int, GradebookResult>
1961
     */
1962
    public function getGradeBookResults(): Collection
1963
    {
1964
        return $this->gradeBookResults;
1965
    }
1966
1967
    /**
1968
     * @return Collection<int, GradebookResultLog>
1969
     */
1970
    public function getGradeBookResultLogs(): Collection
1971
    {
1972
        return $this->gradeBookResultLogs;
1973
    }
1974
1975
    /**
1976
     * @return Collection<int, GradebookScoreLog>
1977
     */
1978
    public function getGradeBookScoreLogs(): Collection
1979
    {
1980
        return $this->gradeBookScoreLogs;
1981
    }
1982
1983
    /**
1984
     * @return Collection<int, GradebookLinkevalLog>
1985
     */
1986
    public function getGradeBookLinkEvalLogs(): Collection
1987
    {
1988
        return $this->gradeBookLinkEvalLogs;
1989
    }
1990
1991
    /**
1992
     * @return Collection<int, UserRelCourseVote>
1993
     */
1994
    public function getUserRelCourseVotes(): Collection
1995
    {
1996
        return $this->userRelCourseVotes;
1997
    }
1998
1999
    /**
2000
     * @return Collection<int, UserRelTag>
2001
     */
2002
    public function getUserRelTags(): Collection
2003
    {
2004
        return $this->userRelTags;
2005
    }
2006
2007
    public function getCurriculumItems(): Collection
2008
    {
2009
        return $this->curriculumItems;
2010
    }
2011
2012
    /**
2013
     * @return Collection<int, UserRelUser>
2014
     */
2015
    public function getFriends(): Collection
2016
    {
2017
        return $this->friends;
2018
    }
2019
2020
    /**
2021
     * @return Collection<int, UserRelUser>
2022
     */
2023
    public function getFriendsWithMe(): Collection
2024
    {
2025
        return $this->friendsWithMe;
2026
    }
2027
2028
    public function addFriend(self $friend): self
2029
    {
2030
        return $this->addUserRelUser($friend, UserRelUser::USER_RELATION_TYPE_FRIEND);
2031
    }
2032
2033
    public function addUserRelUser(self $friend, int $relationType): self
2034
    {
2035
        $userRelUser = (new UserRelUser())->setUser($this)->setFriend($friend)->setRelationType($relationType);
2036
        $this->friends->add($userRelUser);
2037
2038
        return $this;
2039
    }
2040
2041
    /**
2042
     * @return Collection<int, Templates>
2043
     */
2044
    public function getTemplates(): Collection
2045
    {
2046
        return $this->templates;
2047
    }
2048
2049
    public function getDropBoxReceivedFiles(): Collection
2050
    {
2051
        return $this->dropBoxReceivedFiles;
2052
    }
2053
2054
    /**
2055
     * @return Collection<int, SequenceValue>
2056
     */
2057
    public function getSequenceValues(): Collection
2058
    {
2059
        return $this->sequenceValues;
2060
    }
2061
2062
    /**
2063
     * @return Collection<int, TrackEExerciseConfirmation>
2064
     */
2065
    public function getTrackEExerciseConfirmations(): Collection
2066
    {
2067
        return $this->trackEExerciseConfirmations;
2068
    }
2069
2070
    /**
2071
     * @return Collection<int, TrackEAttempt>
2072
     */
2073
    public function getTrackEAccessCompleteList(): Collection
2074
    {
2075
        return $this->trackEAccessCompleteList;
2076
    }
2077
2078
    /**
2079
     * @return Collection<int, TrackEAttempt>
2080
     */
2081
    public function getTrackEAttempts(): Collection
2082
    {
2083
        return $this->trackEAttempts;
2084
    }
2085
2086
    /**
2087
     * @return Collection<int, TrackECourseAccess>
2088
     */
2089
    public function getTrackECourseAccess(): Collection
2090
    {
2091
        return $this->trackECourseAccess;
2092
    }
2093
2094
    /**
2095
     * @return Collection<int, UserCourseCategory>
2096
     */
2097
    public function getUserCourseCategories(): Collection
2098
    {
2099
        return $this->userCourseCategories;
2100
    }
2101
2102
    public function getCourseGroupsAsTutorFromCourse(Course $course): Collection
2103
    {
2104
        $criteria = Criteria::create();
2105
        $criteria->where(Criteria::expr()->eq('cId', $course->getId()));
2106
2107
        return $this->courseGroupsAsTutor->matching($criteria);
2108
    }
2109
2110
    /**
2111
     * Retrieves this user's related student sessions.
2112
     *
2113
     * @return Session[]
2114
     */
2115
    public function getSessionsAsStudent(): array
2116
    {
2117
        return $this->getSessions(Session::STUDENT);
2118
    }
2119
2120
    public function addSessionRelUser(SessionRelUser $sessionSubscription): static
2121
    {
2122
        $this->sessionsRelUser->add($sessionSubscription);
2123
2124
        return $this;
2125
    }
2126
2127
    public function isSkipResourceNode(): bool
2128
    {
2129
        return $this->skipResourceNode;
2130
    }
2131
2132
    public function setSkipResourceNode(bool $skipResourceNode): self
2133
    {
2134
        $this->skipResourceNode = $skipResourceNode;
2135
2136
        return $this;
2137
    }
2138
2139
    /**
2140
     * Retrieves this user's related DRH sessions.
2141
     *
2142
     * @return Session[]
2143
     */
2144
    public function getDRHSessions(): array
2145
    {
2146
        return $this->getSessions(Session::DRH);
2147
    }
2148
2149
    /**
2150
     * Get this user's related accessible sessions of a type, student by default.
2151
     *
2152
     * @return Session[]
2153
     */
2154
    public function getCurrentlyAccessibleSessions(int $relationType = Session::STUDENT): array
2155
    {
2156
        $sessions = [];
2157
        foreach ($this->getSessions($relationType) as $session) {
2158
            if ($session->isCurrentlyAccessible()) {
2159
                $sessions[] = $session;
2160
            }
2161
        }
2162
2163
        return $sessions;
2164
    }
2165
2166
    public function getResourceIdentifier(): int
2167
    {
2168
        return $this->id;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->id could return the type null which is incompatible with the type-hinted return integer. Consider adding an additional type-check to rule them out.
Loading history...
2169
    }
2170
2171
    public function getResourceName(): string
2172
    {
2173
        return $this->getUsername();
2174
    }
2175
2176
    public function setResourceName(string $name): void
2177
    {
2178
        $this->setUsername($name);
2179
    }
2180
2181
    public function setParent(AbstractResource $parent): void {}
2182
2183
    public function getDefaultIllustration(int $size): string
2184
    {
2185
        $size = empty($size) ? 32 : $size;
2186
2187
        return \sprintf('/img/icons/%s/unknown.png', $size);
2188
    }
2189
2190
    public function getAdmin(): ?Admin
2191
    {
2192
        return $this->admin;
2193
    }
2194
2195
    public function setAdmin(?Admin $admin): self
2196
    {
2197
        $this->admin = $admin;
2198
2199
        return $this;
2200
    }
2201
2202
    public function addUserAsAdmin(): self
2203
    {
2204
        if (null === $this->admin) {
2205
            $admin = new Admin();
2206
            $admin->setUser($this);
2207
            $this->setAdmin($admin);
2208
            $this->addRole('ROLE_ADMIN');
2209
        }
2210
2211
        return $this;
2212
    }
2213
2214
    public function removeUserAsAdmin(): self
2215
    {
2216
        $this->admin->setUser(null);
0 ignored issues
show
Bug introduced by
The method setUser() does not exist on null. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

2216
        $this->admin->/** @scrutinizer ignore-call */ 
2217
                      setUser(null);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
2217
        $this->admin = null;
2218
        $this->removeRole('ROLE_ADMIN');
2219
2220
        return $this;
2221
    }
2222
2223
    public function getSessionsByStatusInCourseSubscription(int $status): ReadableCollection
2224
    {
2225
        $criteria = Criteria::create()->where(Criteria::expr()->eq('status', $status));
2226
2227
        /** @var ArrayCollection $subscriptions */
2228
        $subscriptions = $this->getSessionRelCourseRelUsers();
2229
2230
        return $subscriptions->matching($criteria)->map(
2231
            fn (SessionRelCourseRelUser $sessionRelCourseRelUser) => $sessionRelCourseRelUser->getSession()
2232
        );
2233
    }
2234
2235
    /**
2236
     * @return Collection<int, SessionRelCourseRelUser>
2237
     */
2238
    public function getSessionRelCourseRelUsers(): Collection
2239
    {
2240
        return $this->sessionRelCourseRelUsers;
2241
    }
2242
2243
    /**
2244
     * @param Collection<int, SessionRelCourseRelUser> $sessionRelCourseRelUsers
2245
     */
2246
    public function setSessionRelCourseRelUsers(Collection $sessionRelCourseRelUsers): self
2247
    {
2248
        $this->sessionRelCourseRelUsers = $sessionRelCourseRelUsers;
2249
2250
        return $this;
2251
    }
2252
2253
    public function getGender(): ?string
2254
    {
2255
        return $this->gender;
2256
    }
2257
2258
    public function setGender(?string $gender): self
2259
    {
2260
        $this->gender = $gender;
2261
2262
        return $this;
2263
    }
2264
2265
    /**
2266
     * @return Collection<int, CSurveyInvitation>
2267
     */
2268
    public function getSurveyInvitations(): Collection
2269
    {
2270
        return $this->surveyInvitations;
2271
    }
2272
2273
    public function setSurveyInvitations(Collection $surveyInvitations): self
2274
    {
2275
        $this->surveyInvitations = $surveyInvitations;
2276
2277
        return $this;
2278
    }
2279
2280
    public function getLogin(): string
2281
    {
2282
        return $this->username;
2283
    }
2284
2285
    public function setLogin(string $login): self
2286
    {
2287
        $this->username = $login;
2288
2289
        return $this;
2290
    }
2291
2292
    /**
2293
     * @return Collection<int, TrackELogin>
2294
     */
2295
    public function getLogins(): Collection
2296
    {
2297
        return $this->logins;
2298
    }
2299
2300
    public function setLogins(Collection $logins): self
2301
    {
2302
        $this->logins = $logins;
2303
2304
        return $this;
2305
    }
2306
2307
    /**
2308
     * @return Collection<int, MessageTag>
2309
     */
2310
    public function getMessageTags(): Collection
2311
    {
2312
        return $this->messageTags;
2313
    }
2314
2315
    /**
2316
     * @param Collection<int, MessageTag> $messageTags
2317
     */
2318
    public function setMessageTags(Collection $messageTags): self
2319
    {
2320
        $this->messageTags = $messageTags;
2321
2322
        return $this;
2323
    }
2324
2325
    /**
2326
     * @param null|UserCourseCategory $userCourseCategory the user_course_category
2327
     *
2328
     * @todo move in a repo
2329
     * Find the largest sort value in a given UserCourseCategory
2330
     * This method is used when we are moving a course to a different category
2331
     * and also when a user subscribes to courses (the new course is added at the end of the main category).
2332
     *
2333
     * Used to be implemented in global function \api_max_sort_value.
2334
     * Reimplemented using the ORM cache.
2335
     */
2336
    public function getMaxSortValue(?UserCourseCategory $userCourseCategory = null): int
2337
    {
2338
        $categoryCourses = $this->courses->matching(
2339
            Criteria::create()->where(Criteria::expr()->neq('relationType', COURSE_RELATION_TYPE_RRHH))->andWhere(
2340
                Criteria::expr()->eq('userCourseCat', $userCourseCategory)
2341
            )
2342
        );
2343
2344
        return $categoryCourses->isEmpty() ? 0 : max(
2345
            $categoryCourses->map(fn ($courseRelUser) => $courseRelUser->getSort())->toArray()
2346
        );
2347
    }
2348
2349
    public function hasFriendWithRelationType(self $friend, int $relationType): bool
2350
    {
2351
        $friends = $this->getFriendsByRelationType($relationType);
2352
2353
        return $friends->exists(fn (int $index, UserRelUser $userRelUser) => $userRelUser->getFriend() === $friend);
2354
    }
2355
2356
    public function isFriendWithMeByRelationType(self $friend, int $relationType): bool
2357
    {
2358
        return $this
2359
            ->getFriendsWithMeByRelationType($relationType)
2360
            ->exists(fn (int $index, UserRelUser $userRelUser) => $userRelUser->getUser() === $friend)
2361
        ;
2362
    }
2363
2364
    /**
2365
     * @param int $relationType Example: UserRelUser::USER_RELATION_TYPE_BOSS
2366
     *
2367
     * @return Collection<int, UserRelUser>
2368
     */
2369
    public function getFriendsByRelationType(int $relationType): Collection
2370
    {
2371
        $criteria = Criteria::create();
2372
        $criteria->where(Criteria::expr()->eq('relationType', $relationType));
2373
2374
        return $this->friends->matching($criteria);
2375
    }
2376
2377
    public function getFriendsWithMeByRelationType(int $relationType): Collection
2378
    {
2379
        $criteria = Criteria::create();
2380
        $criteria->where(Criteria::expr()->eq('relationType', $relationType));
2381
2382
        return $this->friendsWithMe->matching($criteria);
2383
    }
2384
2385
    public function getFriendsOfFriends(): array
2386
    {
2387
        $friendsOfFriends = [];
2388
        foreach ($this->getFriends() as $friendRelation) {
2389
            foreach ($friendRelation->getFriend()->getFriends() as $friendOfFriendRelation) {
2390
                $friendsOfFriends[] = $friendOfFriendRelation->getFriend();
2391
            }
2392
        }
2393
2394
        return $friendsOfFriends;
2395
    }
2396
2397
    /**
2398
     * @return Collection<int, SocialPost>
2399
     */
2400
    public function getSentSocialPosts(): Collection
2401
    {
2402
        return $this->sentSocialPosts;
2403
    }
2404
2405
    public function addSentSocialPost(SocialPost $sentSocialPost): self
2406
    {
2407
        if (!$this->sentSocialPosts->contains($sentSocialPost)) {
2408
            $this->sentSocialPosts[] = $sentSocialPost;
2409
            $sentSocialPost->setSender($this);
2410
        }
2411
2412
        return $this;
2413
    }
2414
2415
    /**
2416
     * @return Collection<int, SocialPost>
2417
     */
2418
    public function getReceivedSocialPosts(): Collection
2419
    {
2420
        return $this->receivedSocialPosts;
2421
    }
2422
2423
    public function addReceivedSocialPost(SocialPost $receivedSocialPost): self
2424
    {
2425
        if (!$this->receivedSocialPosts->contains($receivedSocialPost)) {
2426
            $this->receivedSocialPosts[] = $receivedSocialPost;
2427
            $receivedSocialPost->setUserReceiver($this);
2428
        }
2429
2430
        return $this;
2431
    }
2432
2433
    public function getSocialPostFeedbackBySocialPost(SocialPost $post): ?SocialPostFeedback
2434
    {
2435
        $filtered = $this->getSocialPostsFeedbacks()->filter(
2436
            fn (SocialPostFeedback $postFeedback) => $postFeedback->getSocialPost() === $post
2437
        );
2438
        if ($filtered->count() > 0) {
2439
            return $filtered->first();
2440
        }
2441
2442
        return null;
2443
    }
2444
2445
    /**
2446
     * @return Collection<int, SocialPostFeedback>
2447
     */
2448
    public function getSocialPostsFeedbacks(): Collection
2449
    {
2450
        return $this->socialPostsFeedbacks;
2451
    }
2452
2453
    public function addSocialPostFeedback(SocialPostFeedback $socialPostFeedback): self
2454
    {
2455
        if (!$this->socialPostsFeedbacks->contains($socialPostFeedback)) {
2456
            $this->socialPostsFeedbacks[] = $socialPostFeedback;
2457
            $socialPostFeedback->setUser($this);
2458
        }
2459
2460
        return $this;
2461
    }
2462
2463
    public function getSubscriptionToSession(Session $session): ?SessionRelUser
2464
    {
2465
        $criteria = Criteria::create();
2466
        $criteria->where(
2467
            Criteria::expr()->eq('session', $session)
2468
        );
2469
2470
        $match = $this->sessionsRelUser->matching($criteria);
2471
2472
        if ($match->count() > 0) {
2473
            return $match->first();
2474
        }
2475
2476
        return null;
2477
    }
2478
2479
    public function getFirstAccessToSession(Session $session): ?TrackECourseAccess
2480
    {
2481
        $criteria = Criteria::create()
2482
            ->where(
2483
                Criteria::expr()->eq('sessionId', $session->getId())
2484
            )
2485
        ;
2486
2487
        $match = $this->trackECourseAccess->matching($criteria);
2488
2489
        return $match->count() > 0 ? $match->first() : null;
2490
    }
2491
2492
    public function isCourseTutor(?Course $course = null, ?Session $session = null): bool
2493
    {
2494
        return $session?->hasCoachInCourseList($this) || $course?->getSubscriptionByUser($this)?->isTutor();
2495
    }
2496
2497
    /**
2498
     * @return Collection<int, UserAuthSource>
2499
     */
2500
    public function getAuthSources(): Collection
2501
    {
2502
        return $this->authSources;
2503
    }
2504
2505
    /**
2506
     * @return Collection<int, UserAuthSource>
2507
     */
2508
    public function getAuthSourcesByUrl(AccessUrl $url): Collection
2509
    {
2510
        $criteria = Criteria::create();
2511
        $criteria->where(
2512
            Criteria::expr()->eq('url', $url)
2513
        );
2514
2515
        return $this->authSources->matching($criteria);
2516
    }
2517
2518
    /**
2519
     * @return array<int, string>
2520
     */
2521
    public function getAuthSourcesAuthentications(?AccessUrl $url = null): array
2522
    {
2523
        $authSources = $url ? $this->getAuthSourcesByUrl($url) : $this->getAuthSources();
2524
2525
        return $authSources->map(fn (UserAuthSource $authSource) => $authSource->getAuthentication())->toArray();
2526
    }
2527
2528
    public function addAuthSource(UserAuthSource $authSource): static
2529
    {
2530
        if (!$this->authSources->contains($authSource)) {
2531
            $this->authSources->add($authSource);
2532
            $authSource->setUser($this);
2533
        }
2534
2535
        return $this;
2536
    }
2537
2538
    public function addAuthSourceByAuthentication(string $authentication, AccessUrl $url): static
2539
    {
2540
        $authSource = (new UserAuthSource())
2541
            ->setAuthentication($authentication)
2542
            ->setUrl($url)
2543
        ;
2544
2545
        $this->addAuthSource($authSource);
2546
2547
        return $this;
2548
    }
2549
2550
    public function hasAuthSourceByAuthentication(string $authentication): bool
2551
    {
2552
        return $this->authSources->exists(
2553
            fn ($key, $authSource) => $authSource instanceof UserAuthSource
2554
                && $authSource->getAuthentication() === $authentication
2555
        );
2556
    }
2557
2558
    public function getAuthSourceByAuthentication(string $authentication): UserAuthSource
2559
    {
2560
        return $this->authSources->findFirst(
2561
            fn (UserAuthSource $authSource) => $authSource->getAuthentication() === $authentication
2562
        );
2563
    }
2564
2565
    public function removeAuthSources(): static
2566
    {
2567
        foreach ($this->authSources as $authSource) {
2568
            $authSource->setUser(null);
2569
        }
2570
2571
        $this->authSources = new ArrayCollection();
2572
2573
        return $this;
2574
    }
2575
2576
    public function removeAuthSource(UserAuthSource $authSource): static
2577
    {
2578
        if ($this->authSources->removeElement($authSource)) {
2579
            // set the owning side to null (unless already changed)
2580
            if ($authSource->getUser() === $this) {
2581
                $authSource->setUser(null);
2582
            }
2583
        }
2584
2585
        return $this;
2586
    }
2587
2588
    public function getMfaEnabled(): bool
2589
    {
2590
        return $this->mfaEnabled;
2591
    }
2592
2593
    public function setMfaEnabled(bool $mfaEnabled): self
2594
    {
2595
        $this->mfaEnabled = $mfaEnabled;
2596
2597
        return $this;
2598
    }
2599
2600
    public function getMfaService(): ?string
2601
    {
2602
        return $this->mfaService;
2603
    }
2604
2605
    public function setMfaService(?string $mfaService): self
2606
    {
2607
        $this->mfaService = $mfaService;
2608
2609
        return $this;
2610
    }
2611
2612
    public function getMfaSecret(): ?string
2613
    {
2614
        return $this->mfaSecret;
2615
    }
2616
2617
    public function setMfaSecret(?string $mfaSecret): self
2618
    {
2619
        $this->mfaSecret = $mfaSecret;
2620
2621
        return $this;
2622
    }
2623
2624
    public function getMfaBackupCodes(): ?string
2625
    {
2626
        return $this->mfaBackupCodes;
2627
    }
2628
2629
    public function setMfaBackupCodes(?string $mfaBackupCodes): self
2630
    {
2631
        $this->mfaBackupCodes = $mfaBackupCodes;
2632
2633
        return $this;
2634
    }
2635
2636
    public function getMfaLastUsed(): ?DateTimeInterface
2637
    {
2638
        return $this->mfaLastUsed;
2639
    }
2640
2641
    public function setMfaLastUsed(?DateTimeInterface $mfaLastUsed): self
2642
    {
2643
        $this->mfaLastUsed = $mfaLastUsed;
2644
2645
        return $this;
2646
    }
2647
2648
    public function getPasswordUpdatedAt(): ?DateTimeInterface
2649
    {
2650
        return $this->passwordUpdatedAt;
2651
    }
2652
2653
    /**
2654
     * @return $this
2655
     */
2656
    public function setPasswordUpdatedAt(?DateTimeInterface $date): self
2657
    {
2658
        $this->passwordUpdatedAt = $date;
2659
2660
        return $this;
2661
    }
2662
2663
    public function getFullNameWithUsername(): string
2664
    {
2665
        return $this->getFullName().' ('.$this->getUsername().')';
2666
    }
2667
}
2668