Passed
Push — master ( 02d96b...11f250 )
by Angel Fernando Quiroz
08:17
created

User::getFullName()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 3
nc 2
nop 0
dl 0
loc 7
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\Post;
18
use ApiPlatform\Metadata\Put;
19
use Chamilo\CoreBundle\Controller\Api\CreateUserOnAccessUrlAction;
20
use Chamilo\CoreBundle\Controller\Api\GetStatsAction;
21
use Chamilo\CoreBundle\Controller\Api\UserSkillsController;
22
use Chamilo\CoreBundle\Dto\CreateUserOnAccessUrlInput;
23
use Chamilo\CoreBundle\Entity\Listener\UserListener;
24
use Chamilo\CoreBundle\Filter\PartialSearchOrFilter;
25
use Chamilo\CoreBundle\Repository\Node\UserRepository;
26
use Chamilo\CoreBundle\Traits\UserCreatorTrait;
27
use Chamilo\CourseBundle\Entity\CGroupRelTutor;
28
use Chamilo\CourseBundle\Entity\CGroupRelUser;
29
use Chamilo\CourseBundle\Entity\CSurveyInvitation;
30
use DateTime;
31
use DateTimeInterface;
32
use Doctrine\Common\Collections\ArrayCollection;
33
use Doctrine\Common\Collections\Collection;
34
use Doctrine\Common\Collections\Criteria;
35
use Doctrine\Common\Collections\ReadableCollection;
36
use Doctrine\ORM\Mapping as ORM;
37
use Gedmo\Timestampable\Traits\TimestampableEntity;
38
use Stringable;
39
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
40
use Symfony\Component\Security\Core\User\EquatableInterface;
41
use Symfony\Component\Security\Core\User\LegacyPasswordAuthenticatedUserInterface;
42
use Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface;
43
use Symfony\Component\Security\Core\User\UserInterface;
44
use Symfony\Component\Serializer\Annotation\Groups;
45
use Symfony\Component\Uid\Uuid;
46
use Symfony\Component\Validator\Constraints as Assert;
47
use Symfony\Component\Validator\Mapping\ClassMetadata;
48
use UserManager;
49
50
#[ApiResource(
51
    types: ['http://schema.org/Person'],
52
    operations: [
53
        new Get(
54
            openapiContext: [
55
                'description' => 'Get details of one specific user, including name, e-mail and role.',
56
            ],
57
            security: "is_granted('VIEW', object)",
58
        ),
59
        new Get(
60
            uriTemplate: '/users/{id}/courses/{courseId}/stats/{metric}',
61
            requirements: [
62
                'id' => '\d+',
63
                'courseId' => '\d+',
64
                'metric' => 'avg-lp-progress|certificates|gradebook-global',
65
            ],
66
            controller: GetStatsAction::class,
67
            openapiContext: [
68
                'summary' => 'User-course statistics, switch by {metric}',
69
                'parameters' => [
70
                    [
71
                        'name' => 'courseId',
72
                        'in' => 'path',
73
                        'required' => true,
74
                        'schema' => ['type' => 'integer'],
75
                        'description' => 'Course ID',
76
                    ],
77
                    [
78
                        'name' => 'metric',
79
                        'in' => 'path',
80
                        'required' => true,
81
                        'schema' => [
82
                            'type' => 'string',
83
                            'enum' => ['avg-lp-progress', 'certificates', 'gradebook-global'],
84
                        ],
85
                        'description' => 'Metric selector',
86
                    ],
87
                    [
88
                        'name' => 'sessionId',
89
                        'in' => 'query',
90
                        'required' => false,
91
                        'schema' => ['type' => 'integer'],
92
                        'description' => 'Optional Session ID',
93
                    ],
94
                ],
95
            ],
96
            security: "is_granted('ROLE_USER')",
97
            output: false,
98
            read: false,
99
            name: 'stats_user_course_metric'
100
        ),
101
        new Put(security: "is_granted('EDIT', object)"),
102
        new Delete(security: "is_granted('DELETE', object)"),
103
        new GetCollection(security: "is_granted('ROLE_USER')"),
104
        new Post(security: "is_granted('ROLE_ADMIN')"),
105
        new GetCollection(
106
            uriTemplate: '/users/{id}/skills',
107
            controller: UserSkillsController::class,
108
            normalizationContext: ['groups' => ['user_skills:read']],
109
            name: 'get_user_skills'
110
        ),
111
        new Post(
112
            uriTemplate: '/advanced/create-user-on-access-url',
113
            controller: CreateUserOnAccessUrlAction::class,
114
            denormalizationContext: ['groups' => ['write']],
115
            security: "is_granted('ROLE_ADMIN') or is_granted('ROLE_SESSION_MANAGER')",
116
            input: CreateUserOnAccessUrlInput::class,
117
            output: User::class,
118
            deserialize: true,
119
            name: 'create_user_on_access_url'
120
        ),
121
    ],
122
    normalizationContext: ['groups' => ['user:read']],
123
    denormalizationContext: ['groups' => ['user:write']],
124
    security: 'is_granted("ROLE_USER")'
125
)]
126
#[ORM\Table(name: 'user')]
127
#[ORM\Index(columns: ['status'], name: 'status')]
128
#[UniqueEntity('username')]
129
#[ORM\Entity(repositoryClass: UserRepository::class)]
130
#[ORM\EntityListeners([UserListener::class])]
131
#[ApiFilter(
132
    filterClass: SearchFilter::class,
133
    properties: [
134
        'username' => 'partial',
135
        'firstname' => 'partial',
136
        'lastname' => 'partial',
137
    ]
138
)]
139
#[ApiFilter(PartialSearchOrFilter::class, properties: ['username', 'firstname', 'lastname'])]
140
#[ApiFilter(filterClass: BooleanFilter::class, properties: ['isActive'])]
141
class User implements UserInterface, EquatableInterface, ResourceInterface, ResourceIllustrationInterface, PasswordAuthenticatedUserInterface, LegacyPasswordAuthenticatedUserInterface, ExtraFieldItemInterface, Stringable
142
{
143
    use TimestampableEntity;
144
    use UserCreatorTrait;
145
146
    public const USERNAME_MAX_LENGTH = 100;
147
    public const ROLE_DEFAULT = 'ROLE_USER';
148
    public const ANONYMOUS = 6;
149
150
    /**
151
     * Global status for the fallback user.
152
     * This special status is used for a system user that acts as a placeholder
153
     * or fallback for content ownership when regular users are deleted.
154
     * This ensures data integrity and prevents orphaned content within the system.
155
     */
156
    public const ROLE_FALLBACK = 99;
157
158
    /*public const COURSE_MANAGER = 1;
159
      public const TEACHER = 1;
160
      public const SESSION_ADMIN = 3;
161
      public const DRH = 4;
162
      public const STUDENT = 5;
163
      public const ANONYMOUS = 6;*/
164
165
    // User active field constants
166
    public const ACTIVE = 1;
167
    public const INACTIVE = 0;
168
    public const INACTIVE_AUTOMATIC = -1;
169
    public const SOFT_DELETED = -2;
170
171
    #[Groups(['user_json:read'])]
172
    #[ORM\OneToOne(targetEntity: ResourceNode::class, cascade: ['persist'])]
173
    #[ORM\JoinColumn(name: 'resource_node_id', onDelete: 'CASCADE')]
174
    public ?ResourceNode $resourceNode = null;
175
176
    /**
177
     * Resource illustration URL - Property set by ResourceNormalizer.php.
178
     */
179
    #[ApiProperty(iris: ['http://schema.org/contentUrl'])]
180
    #[Groups([
181
        'user_export',
182
        'user:read',
183
        'resource_node:read',
184
        'document:read',
185
        'media_object_read',
186
        'course:read',
187
        'course_rel_user:read',
188
        'user_json:read',
189
        'message:read',
190
        'user_rel_user:read',
191
        'social_post:read',
192
        'user_subscriptions:sessions',
193
    ])]
194
    public ?string $illustrationUrl = null;
195
196
    #[Groups([
197
        'user:read',
198
        'course:read',
199
        'resource_node:read',
200
        'user_json:read',
201
        'message:read',
202
        'user_rel_user:read',
203
        'session:item:read',
204
    ])]
205
    #[ORM\Column(name: 'id', type: 'integer')]
206
    #[ORM\Id]
207
    #[ORM\GeneratedValue]
208
    protected ?int $id = null;
209
210
    #[Assert\NotBlank]
211
    #[Groups([
212
        'user_export',
213
        'user:read',
214
        'user:write',
215
        'course:read',
216
        'course_rel_user:read',
217
        'resource_node:read',
218
        'user_json:read',
219
        'message:read',
220
        'page:read',
221
        'user_rel_user:read',
222
        'social_post:read',
223
        'track_e_exercise:read',
224
        'user_subscriptions:sessions',
225
        'student_publication_rel_user:read',
226
    ])]
227
    #[ORM\Column(name: 'username', type: 'string', length: 100, unique: true)]
228
    protected string $username;
229
230
    #[ORM\Column(name: 'api_token', type: 'string', unique: true, nullable: true)]
231
    protected ?string $apiToken = null;
232
233
    #[ApiProperty(iris: ['http://schema.org/name'])]
234
    #[Assert\NotBlank]
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;
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 = new DateTime();
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 getCompleteNameWithClasses(): 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
        return $this->hasRole('ROLE_SUPER_ADMIN');
1673
    }
1674
1675
    public function hasRole(string $role): bool
1676
    {
1677
        return \in_array(strtoupper($role), $this->getRoles(), true);
1678
    }
1679
1680
    /**
1681
     * Returns the user roles.
1682
     */
1683
    public function getRoles(): array
1684
    {
1685
        $roles = $this->roles;
1686
        foreach ($this->getGroups() as $group) {
1687
            $roles = array_merge($roles, $group->getRoles());
1688
        }
1689
        // we need to make sure to have at least one role
1690
        $roles[] = 'ROLE_USER';
1691
1692
        return array_unique($roles);
1693
    }
1694
1695
    public function setRoles(array $roles): self
1696
    {
1697
        $this->roles = [];
1698
        foreach ($roles as $role) {
1699
            $this->addRole($role);
1700
        }
1701
1702
        return $this;
1703
    }
1704
1705
    public function setRoleFromStatus(int $status): void
1706
    {
1707
        $role = self::getRoleFromStatus($status);
1708
        $this->addRole($role);
1709
    }
1710
1711
    public static function getRoleFromStatus(int $status): string
1712
    {
1713
        return match ($status) {
1714
            COURSEMANAGER => 'ROLE_TEACHER',
1715
            STUDENT => 'ROLE_STUDENT',
1716
            DRH => 'ROLE_HR',
1717
            SESSIONADMIN => 'ROLE_SESSION_MANAGER',
1718
            STUDENT_BOSS => 'ROLE_STUDENT_BOSS',
1719
            INVITEE => 'ROLE_INVITEE',
1720
            default => 'ROLE_USER',
1721
        };
1722
    }
1723
1724
    public function addRole(string $role): self
1725
    {
1726
        $role = strtoupper($role);
1727
        if ($role === static::ROLE_DEFAULT || empty($role)) {
1728
            return $this;
1729
        }
1730
        if (!\in_array($role, $this->roles, true)) {
1731
            $this->roles[] = $role;
1732
        }
1733
1734
        return $this;
1735
    }
1736
1737
    public function removeRole(string $role): self
1738
    {
1739
        if (false !== ($key = array_search(strtoupper($role), $this->roles, true))) {
1740
            unset($this->roles[$key]);
1741
            $this->roles = array_values($this->roles);
1742
        }
1743
1744
        return $this;
1745
    }
1746
1747
    public function getUsernameCanonical(): string
1748
    {
1749
        return $this->usernameCanonical;
1750
    }
1751
1752
    public function setUsernameCanonical(string $usernameCanonical): self
1753
    {
1754
        $this->usernameCanonical = $usernameCanonical;
1755
1756
        return $this;
1757
    }
1758
1759
    public function getEmailCanonical(): string
1760
    {
1761
        return $this->emailCanonical;
1762
    }
1763
1764
    public function setEmailCanonical(string $emailCanonical): self
1765
    {
1766
        $this->emailCanonical = $emailCanonical;
1767
1768
        return $this;
1769
    }
1770
1771
    public function getTimezone(): string
1772
    {
1773
        return $this->timezone;
1774
    }
1775
1776
    public function setTimezone(string $timezone): self
1777
    {
1778
        $this->timezone = $timezone;
1779
1780
        return $this;
1781
    }
1782
1783
    public function getLocale(): string
1784
    {
1785
        return $this->locale;
1786
    }
1787
1788
    public function setLocale(string $locale): self
1789
    {
1790
        $this->locale = $locale;
1791
1792
        return $this;
1793
    }
1794
1795
    public function getApiToken(): ?string
1796
    {
1797
        return $this->apiToken;
1798
    }
1799
1800
    public function setApiToken(string $apiToken): self
1801
    {
1802
        $this->apiToken = $apiToken;
1803
1804
        return $this;
1805
    }
1806
1807
    public function getWebsite(): ?string
1808
    {
1809
        return $this->website;
1810
    }
1811
1812
    public function setWebsite(string $website): self
1813
    {
1814
        $this->website = $website;
1815
1816
        return $this;
1817
    }
1818
1819
    public function getBiography(): ?string
1820
    {
1821
        return $this->biography;
1822
    }
1823
1824
    public function setBiography(string $biography): self
1825
    {
1826
        $this->biography = $biography;
1827
1828
        return $this;
1829
    }
1830
1831
    public function getDateOfBirth(): ?DateTime
1832
    {
1833
        return $this->dateOfBirth;
1834
    }
1835
1836
    public function setDateOfBirth(?DateTime $dateOfBirth = null): self
1837
    {
1838
        $this->dateOfBirth = $dateOfBirth;
1839
1840
        return $this;
1841
    }
1842
1843
    public function getProfileUrl(): string
1844
    {
1845
        return '/main/social/profile.php?u='.$this->id;
1846
    }
1847
1848
    public function getIconStatus(): string
1849
    {
1850
        $hasCertificates = $this->getGradeBookCertificates()->count() > 0;
1851
        $urlImg = '/img/';
1852
        if ($this->isStudent()) {
1853
            $iconStatus = $urlImg.'icons/svg/identifier_student.svg';
1854
            if ($hasCertificates) {
1855
                $iconStatus = $urlImg.'icons/svg/identifier_graduated.svg';
1856
            }
1857
1858
            return $iconStatus;
1859
        }
1860
        if ($this->isTeacher()) {
1861
            $iconStatus = $urlImg.'icons/svg/identifier_teacher.svg';
1862
            if ($this->isAdmin()) {
1863
                $iconStatus = $urlImg.'icons/svg/identifier_admin.svg';
1864
            }
1865
1866
            return $iconStatus;
1867
        }
1868
        if ($this->isStudentBoss()) {
1869
            return $urlImg.'icons/svg/identifier_teacher.svg';
1870
        }
1871
1872
        return '';
1873
    }
1874
1875
    public function getGradeBookCertificates(): Collection
1876
    {
1877
        return $this->gradeBookCertificates;
1878
    }
1879
1880
    /**
1881
     * @param Collection<int, GradebookCertificate> $gradeBookCertificates
1882
     */
1883
    public function setGradeBookCertificates(Collection $gradeBookCertificates): self
1884
    {
1885
        $this->gradeBookCertificates = $gradeBookCertificates;
1886
1887
        return $this;
1888
    }
1889
1890
    public function isStudent(): bool
1891
    {
1892
        return $this->hasRole('ROLE_STUDENT');
1893
    }
1894
1895
    public function isTeacher(): bool
1896
    {
1897
        return $this->hasRole('ROLE_TEACHER');
1898
    }
1899
1900
    public function isAdmin(): bool
1901
    {
1902
        return $this->hasRole('ROLE_ADMIN');
1903
    }
1904
1905
    public function isStudentBoss(): bool
1906
    {
1907
        return $this->hasRole('ROLE_STUDENT_BOSS');
1908
    }
1909
1910
    public function isSessionAdmin(): bool
1911
    {
1912
        return $this->hasRole('ROLE_SESSION_MANAGER');
1913
    }
1914
1915
    public function isInvitee(): bool
1916
    {
1917
        return $this->hasRole('ROLE_INVITEE');
1918
    }
1919
1920
    public function isHRM(): bool
1921
    {
1922
        return $this->hasRole('ROLE_HR');
1923
    }
1924
1925
    public function getStatus(): int
1926
    {
1927
        return $this->status;
1928
    }
1929
1930
    public function setStatus(int $status): self
1931
    {
1932
        $this->status = $status;
1933
1934
        return $this;
1935
    }
1936
1937
    public function getPictureUri(): ?string
1938
    {
1939
        return $this->pictureUri;
1940
    }
1941
1942
    /**
1943
     * @return Collection<int, GradebookCategory>
1944
     */
1945
    public function getGradeBookCategories(): Collection
1946
    {
1947
        return $this->gradeBookCategories;
1948
    }
1949
1950
    /**
1951
     * @return Collection<int, GradebookComment>
1952
     */
1953
    public function getGradeBookComments(): Collection
1954
    {
1955
        return $this->gradeBookComments;
1956
    }
1957
1958
    /**
1959
     * @return Collection<int, GradebookResult>
1960
     */
1961
    public function getGradeBookResults(): Collection
1962
    {
1963
        return $this->gradeBookResults;
1964
    }
1965
1966
    /**
1967
     * @return Collection<int, GradebookResultLog>
1968
     */
1969
    public function getGradeBookResultLogs(): Collection
1970
    {
1971
        return $this->gradeBookResultLogs;
1972
    }
1973
1974
    /**
1975
     * @return Collection<int, GradebookScoreLog>
1976
     */
1977
    public function getGradeBookScoreLogs(): Collection
1978
    {
1979
        return $this->gradeBookScoreLogs;
1980
    }
1981
1982
    /**
1983
     * @return Collection<int, GradebookLinkevalLog>
1984
     */
1985
    public function getGradeBookLinkEvalLogs(): Collection
1986
    {
1987
        return $this->gradeBookLinkEvalLogs;
1988
    }
1989
1990
    /**
1991
     * @return Collection<int, UserRelCourseVote>
1992
     */
1993
    public function getUserRelCourseVotes(): Collection
1994
    {
1995
        return $this->userRelCourseVotes;
1996
    }
1997
1998
    /**
1999
     * @return Collection<int, UserRelTag>
2000
     */
2001
    public function getUserRelTags(): Collection
2002
    {
2003
        return $this->userRelTags;
2004
    }
2005
2006
    public function getCurriculumItems(): Collection
2007
    {
2008
        return $this->curriculumItems;
2009
    }
2010
2011
    /**
2012
     * @return Collection<int, UserRelUser>
2013
     */
2014
    public function getFriends(): Collection
2015
    {
2016
        return $this->friends;
2017
    }
2018
2019
    /**
2020
     * @return Collection<int, UserRelUser>
2021
     */
2022
    public function getFriendsWithMe(): Collection
2023
    {
2024
        return $this->friendsWithMe;
2025
    }
2026
2027
    public function addFriend(self $friend): self
2028
    {
2029
        return $this->addUserRelUser($friend, UserRelUser::USER_RELATION_TYPE_FRIEND);
2030
    }
2031
2032
    public function addUserRelUser(self $friend, int $relationType): self
2033
    {
2034
        $userRelUser = (new UserRelUser())->setUser($this)->setFriend($friend)->setRelationType($relationType);
2035
        $this->friends->add($userRelUser);
2036
2037
        return $this;
2038
    }
2039
2040
    /**
2041
     * @return Collection<int, Templates>
2042
     */
2043
    public function getTemplates(): Collection
2044
    {
2045
        return $this->templates;
2046
    }
2047
2048
    public function getDropBoxReceivedFiles(): Collection
2049
    {
2050
        return $this->dropBoxReceivedFiles;
2051
    }
2052
2053
    /**
2054
     * @return Collection<int, SequenceValue>
2055
     */
2056
    public function getSequenceValues(): Collection
2057
    {
2058
        return $this->sequenceValues;
2059
    }
2060
2061
    /**
2062
     * @return Collection<int, TrackEExerciseConfirmation>
2063
     */
2064
    public function getTrackEExerciseConfirmations(): Collection
2065
    {
2066
        return $this->trackEExerciseConfirmations;
2067
    }
2068
2069
    /**
2070
     * @return Collection<int, TrackEAttempt>
2071
     */
2072
    public function getTrackEAccessCompleteList(): Collection
2073
    {
2074
        return $this->trackEAccessCompleteList;
2075
    }
2076
2077
    /**
2078
     * @return Collection<int, TrackEAttempt>
2079
     */
2080
    public function getTrackEAttempts(): Collection
2081
    {
2082
        return $this->trackEAttempts;
2083
    }
2084
2085
    /**
2086
     * @return Collection<int, TrackECourseAccess>
2087
     */
2088
    public function getTrackECourseAccess(): Collection
2089
    {
2090
        return $this->trackECourseAccess;
2091
    }
2092
2093
    /**
2094
     * @return Collection<int, UserCourseCategory>
2095
     */
2096
    public function getUserCourseCategories(): Collection
2097
    {
2098
        return $this->userCourseCategories;
2099
    }
2100
2101
    public function getCourseGroupsAsTutorFromCourse(Course $course): Collection
2102
    {
2103
        $criteria = Criteria::create();
2104
        $criteria->where(Criteria::expr()->eq('cId', $course->getId()));
2105
2106
        return $this->courseGroupsAsTutor->matching($criteria);
2107
    }
2108
2109
    /**
2110
     * Retrieves this user's related student sessions.
2111
     *
2112
     * @return Session[]
2113
     */
2114
    public function getSessionsAsStudent(): array
2115
    {
2116
        return $this->getSessions(Session::STUDENT);
2117
    }
2118
2119
    public function addSessionRelUser(SessionRelUser $sessionSubscription): static
2120
    {
2121
        $this->sessionsRelUser->add($sessionSubscription);
2122
2123
        return $this;
2124
    }
2125
2126
    public function isSkipResourceNode(): bool
2127
    {
2128
        return $this->skipResourceNode;
2129
    }
2130
2131
    public function setSkipResourceNode(bool $skipResourceNode): self
2132
    {
2133
        $this->skipResourceNode = $skipResourceNode;
2134
2135
        return $this;
2136
    }
2137
2138
    /**
2139
     * Retrieves this user's related DRH sessions.
2140
     *
2141
     * @return Session[]
2142
     */
2143
    public function getDRHSessions(): array
2144
    {
2145
        return $this->getSessions(Session::DRH);
2146
    }
2147
2148
    /**
2149
     * Get this user's related accessible sessions of a type, student by default.
2150
     *
2151
     * @return Session[]
2152
     */
2153
    public function getCurrentlyAccessibleSessions(int $relationType = Session::STUDENT): array
2154
    {
2155
        $sessions = [];
2156
        foreach ($this->getSessions($relationType) as $session) {
2157
            if ($session->isCurrentlyAccessible()) {
2158
                $sessions[] = $session;
2159
            }
2160
        }
2161
2162
        return $sessions;
2163
    }
2164
2165
    public function getResourceIdentifier(): int
2166
    {
2167
        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...
2168
    }
2169
2170
    public function getResourceName(): string
2171
    {
2172
        return $this->getUsername();
2173
    }
2174
2175
    public function setResourceName(string $name): void
2176
    {
2177
        $this->setUsername($name);
2178
    }
2179
2180
    public function setParent(AbstractResource $parent): void {}
2181
2182
    public function getDefaultIllustration(int $size): string
2183
    {
2184
        $size = empty($size) ? 32 : $size;
2185
2186
        return \sprintf('/img/icons/%s/unknown.png', $size);
2187
    }
2188
2189
    public function getAdmin(): ?Admin
2190
    {
2191
        return $this->admin;
2192
    }
2193
2194
    public function setAdmin(?Admin $admin): self
2195
    {
2196
        $this->admin = $admin;
2197
2198
        return $this;
2199
    }
2200
2201
    public function addUserAsAdmin(): self
2202
    {
2203
        if (null === $this->admin) {
2204
            $admin = new Admin();
2205
            $admin->setUser($this);
2206
            $this->setAdmin($admin);
2207
            $this->addRole('ROLE_ADMIN');
2208
        }
2209
2210
        return $this;
2211
    }
2212
2213
    public function removeUserAsAdmin(): self
2214
    {
2215
        $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

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