Passed
Push — master ( 1476c0...3c442d )
by Angel Fernando Quiroz
07:06
created

Session::setImage()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
declare(strict_types=1);
6
7
namespace Chamilo\CoreBundle\Entity;
8
9
use ApiPlatform\Doctrine\Orm\Filter\OrderFilter;
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 ApiPlatform\Serializer\Filter\PropertyFilter;
21
use Chamilo\CoreBundle\Entity\Listener\SessionListener;
22
use Chamilo\CoreBundle\Repository\SessionRepository;
23
use Chamilo\CoreBundle\State\UserSessionSubscriptionsStateProvider;
24
use DateTime;
25
use Doctrine\Common\Collections\ArrayCollection;
26
use Doctrine\Common\Collections\Collection;
27
use Doctrine\Common\Collections\Criteria;
28
use Doctrine\Common\Collections\ReadableCollection;
29
use Doctrine\ORM\Mapping as ORM;
30
use Stringable;
31
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
32
use Symfony\Component\Serializer\Annotation\Groups;
33
use Symfony\Component\Validator\Constraints as Assert;
34
35
#[ApiResource(
36
    operations: [
37
        new Get(
38
            normalizationContext: [
39
                'groups' => ['session:read', 'session:item:read'],
40
            ],
41
            security: "is_granted('ROLE_ADMIN') or is_granted('VIEW', object)"
42
        ),
43
        new Put(security: "is_granted('ROLE_ADMIN')"),
44
        new GetCollection(security: "is_granted('ROLE_ADMIN')"),
45
        new GetCollection(
46
            uriTemplate: '/users/{id}/session_subscriptions/past.{_format}',
47
            uriVariables: [
48
                'id' => new Link(
49
                    fromClass: User::class,
50
                ),
51
            ],
52
            paginationEnabled: false,
53
            normalizationContext: [
54
                'groups' => [
55
                    'user_subscriptions:sessions',
56
                ],
57
            ],
58
            security: "is_granted('ROLE_USER')",
59
            name: 'user_session_subscriptions_past',
60
            provider: UserSessionSubscriptionsStateProvider::class,
61
        ),
62
        new GetCollection(
63
            uriTemplate: '/users/{id}/session_subscriptions/current.{_format}',
64
            uriVariables: [
65
                'id' => new Link(
66
                    fromClass: User::class,
67
                ),
68
            ],
69
            paginationEnabled: false,
70
            normalizationContext: [
71
                'groups' => [
72
                    'user_subscriptions:sessions',
73
                ],
74
            ],
75
            security: "is_granted('ROLE_USER')",
76
            name: 'user_session_subscriptions_current',
77
            provider: UserSessionSubscriptionsStateProvider::class,
78
        ),
79
        new GetCollection(
80
            uriTemplate: '/users/{id}/session_subscriptions/upcoming.{_format}',
81
            uriVariables: [
82
                'id' => new Link(
83
                    fromClass: User::class,
84
                ),
85
            ],
86
            paginationEnabled: false,
87
            normalizationContext: [
88
                'groups' => [
89
                    'user_subscriptions:sessions',
90
                ],
91
            ],
92
            security: "is_granted('ROLE_USER')",
93
            name: 'user_session_subscriptions_upcoming',
94
            provider: UserSessionSubscriptionsStateProvider::class,
95
        ),
96
        new Post(security: "is_granted('ROLE_ADMIN')"),
97
        new Delete(security: "is_granted('DELETE', object)"),
98
    ],
99
    normalizationContext: ['groups' => ['session:read']],
100
    denormalizationContext: ['groups' => ['session:write']],
101
    security: "is_granted('ROLE_ADMIN')"
102
)]
103
#[ORM\Table(name: 'session')]
104
#[ORM\UniqueConstraint(name: 'title', columns: ['title'])]
105
#[ORM\EntityListeners([SessionListener::class])]
106
#[ORM\Entity(repositoryClass: SessionRepository::class)]
107
#[UniqueEntity('title')]
108
#[ApiFilter(filterClass: SearchFilter::class, properties: ['title' => 'partial'])]
109
#[ApiFilter(filterClass: PropertyFilter::class)]
110
#[ApiFilter(filterClass: OrderFilter::class, properties: ['id', 'title'])]
111
class Session implements ResourceWithAccessUrlInterface, Stringable
112
{
113
    public const READ_ONLY = 1;
114
    public const VISIBLE = 2;
115
    public const INVISIBLE = 3;
116
    public const AVAILABLE = 4;
117
118
    public const STUDENT = 0;
119
    public const DRH = 1;
120
    public const COURSE_COACH = 2;
121
    public const GENERAL_COACH = 3;
122
    public const SESSION_ADMIN = 4;
123
124
    #[Groups([
125
        'session:read',
126
        'session_rel_user:read',
127
        'session_rel_course_rel_user:read',
128
        'course:read',
129
        'track_e_exercise:read',
130
        'user_subscriptions:sessions',
131
    ])]
132
    #[ORM\Column(name: 'id', type: 'integer')]
133
    #[ORM\Id]
134
    #[ORM\GeneratedValue]
135
    protected ?int $id = null;
136
137
    /**
138
     * @var Collection<int, SessionRelCourse>
139
     */
140
    #[Groups([
141
        'session:read',
142
        'session_rel_user:read',
143
        'session_rel_course_rel_user:read',
144
        'user_subscriptions:sessions',
145
    ])]
146
    #[ORM\OrderBy(['position' => 'ASC'])]
147
    #[ORM\OneToMany(
148
        mappedBy: 'session',
149
        targetEntity: SessionRelCourse::class,
150
        cascade: ['persist'],
151
        orphanRemoval: true
152
    )]
153
    protected Collection $courses;
154
155
    /**
156
     * @var Collection<int, SessionRelUser>
157
     */
158
    #[Groups([
159
        'session:read',
160
    ])]
161
    #[ORM\OneToMany(
162
        mappedBy: 'session',
163
        targetEntity: SessionRelUser::class,
164
        cascade: ['persist', 'remove'],
165
        orphanRemoval: true
166
    )]
167
    protected Collection $users;
168
169
    /**
170
     * @var Collection<int, SessionRelCourseRelUser>
171
     */
172
    #[Groups([
173
        'session:read',
174
        'session_rel_course_rel_user:read',
175
    ])]
176
    #[ORM\OneToMany(
177
        mappedBy: 'session',
178
        targetEntity: SessionRelCourseRelUser::class,
179
        cascade: ['persist'],
180
        orphanRemoval: true
181
    )]
182
    protected Collection $sessionRelCourseRelUsers;
183
184
    /**
185
     * @var Collection<int, SkillRelCourse>
186
     */
187
    #[ORM\OneToMany(
188
        mappedBy: 'session',
189
        targetEntity: SkillRelCourse::class,
190
        cascade: ['persist', 'remove']
191
    )]
192
    protected Collection $skills;
193
194
    /**
195
     * @var Collection<int, SkillRelUser>
196
     */
197
    #[ORM\OneToMany(mappedBy: 'session', targetEntity: SkillRelUser::class, cascade: ['persist'])]
198
    protected Collection $issuedSkills;
199
200
    /**
201
     * @var Collection<int, EntityAccessUrlInterface>
202
     */
203
    #[ORM\OneToMany(
204
        mappedBy: 'session',
205
        targetEntity: AccessUrlRelSession::class,
206
        cascade: ['persist'],
207
        orphanRemoval: true
208
    )]
209
    protected Collection $urls;
210
211
    /**
212
     * @var Collection<int, ResourceLink>
213
     */
214
    #[ORM\OneToMany(mappedBy: 'session', targetEntity: ResourceLink::class, cascade: ['remove'], orphanRemoval: true)]
215
    protected Collection $resourceLinks;
216
217
    protected AccessUrl $currentUrl;
218
219
    protected ?Course $currentCourse = null;
220
221
    #[Assert\NotBlank]
222
    #[Groups([
223
        'session:read',
224
        'session:write',
225
        'session_rel_course_rel_user:read',
226
        'document:read',
227
        'session_rel_user:read',
228
        'course:read',
229
        'track_e_exercise:read',
230
        'calendar_event:read',
231
        'user_subscriptions:sessions',
232
    ])]
233
    #[ORM\Column(name: 'title', type: 'string', length: 150)]
234
    protected string $title;
235
236
    #[Groups([
237
        'session:read',
238
        'session:write',
239
    ])]
240
    #[ORM\Column(name: 'description', type: 'text', unique: false, nullable: true)]
241
    protected ?string $description;
242
243
    #[Groups([
244
        'session:read',
245
        'session:write',
246
    ])]
247
    #[ORM\Column(name: 'show_description', type: 'boolean', nullable: true)]
248
    protected ?bool $showDescription;
249
250
    #[Groups(['session:read', 'session:write', 'user_subscriptions:sessions'])]
251
    #[ORM\Column(name: 'duration', type: 'integer', nullable: true)]
252
    protected ?int $duration = null;
253
254
    #[Groups(['session:read'])]
255
    #[ORM\Column(name: 'nbr_courses', type: 'integer', unique: false, nullable: false)]
256
    protected int $nbrCourses;
257
258
    #[Groups(['session:read'])]
259
    #[ORM\Column(name: 'nbr_users', type: 'integer', unique: false, nullable: false)]
260
    protected int $nbrUsers;
261
262
    #[Groups(['session:read'])]
263
    #[ORM\Column(name: 'nbr_classes', type: 'integer', unique: false, nullable: false)]
264
    protected int $nbrClasses;
265
266
    #[Groups([
267
        'session:read',
268
        'session:write',
269
    ])]
270
    #[ORM\Column(name: 'visibility', type: 'integer')]
271
    protected int $visibility;
272
273
    #[ORM\ManyToOne(targetEntity: Promotion::class, cascade: ['persist'], inversedBy: 'sessions')]
274
    #[ORM\JoinColumn(name: 'promotion_id', referencedColumnName: 'id', onDelete: 'CASCADE')]
275
    protected ?Promotion $promotion = null;
276
277
    #[Groups([
278
        'session:read',
279
        'session:write',
280
        'session_rel_user:read',
281
        'session_rel_course_rel_user:read',
282
        'user_subscriptions:sessions',
283
    ])]
284
    #[ORM\Column(name: 'display_start_date', type: 'datetime', unique: false, nullable: true)]
285
    protected ?DateTime $displayStartDate;
286
287
    #[Groups([
288
        'session:read',
289
        'session:write',
290
        'session_rel_user:read',
291
        'session_rel_course_rel_user:read',
292
        'user_subscriptions:sessions',
293
    ])]
294
    #[ORM\Column(name: 'display_end_date', type: 'datetime', unique: false, nullable: true)]
295
    protected ?DateTime $displayEndDate;
296
297
    #[Groups([
298
        'session:read',
299
        'session:write',
300
        'session_rel_user:read',
301
        'session_rel_course_rel_user:read',
302
    ])]
303
    #[ORM\Column(name: 'access_start_date', type: 'datetime', unique: false, nullable: true)]
304
    protected ?DateTime $accessStartDate;
305
306
    #[Groups([
307
        'session:read',
308
        'session:write',
309
        'session_rel_user:read',
310
        'session_rel_course_rel_user:read',
311
    ])]
312
    #[ORM\Column(name: 'access_end_date', type: 'datetime', unique: false, nullable: true)]
313
    protected ?DateTime $accessEndDate;
314
315
    #[Groups([
316
        'session:read',
317
        'session:write',
318
        'session_rel_user:read',
319
        'session_rel_course_rel_user:read',
320
    ])]
321
    #[ORM\Column(name: 'coach_access_start_date', type: 'datetime', unique: false, nullable: true)]
322
    protected ?DateTime $coachAccessStartDate;
323
324
    #[Groups([
325
        'session:read',
326
        'session:write',
327
        'session_rel_user:read',
328
        'session_rel_course_rel_user:read',
329
    ])]
330
    #[ORM\Column(name: 'coach_access_end_date', type: 'datetime', unique: false, nullable: true)]
331
    protected ?DateTime $coachAccessEndDate;
332
333
    #[ORM\Column(name: 'position', type: 'integer', nullable: false, options: ['default' => 0])]
334
    protected int $position;
335
336
    #[Groups(['session:read'])]
337
    #[ORM\Column(name: 'status', type: 'integer', nullable: false)]
338
    protected int $status;
339
340
    #[Groups(['session:read', 'session:write', 'session_rel_user:read', 'user_subscriptions:sessions'])]
341
    #[ORM\ManyToOne(targetEntity: SessionCategory::class, inversedBy: 'sessions')]
342
    #[ORM\JoinColumn(name: 'session_category_id', referencedColumnName: 'id')]
343
    protected ?SessionCategory $category = null;
344
345
    #[ORM\Column(
346
        name: 'send_subscription_notification',
347
        type: 'boolean',
348
        nullable: false,
349
        options: ['default' => false]
350
    )]
351
    protected bool $sendSubscriptionNotification;
352
353
    /**
354
     * Image illustrating the session (was extra field 'image' in 1.11).
355
     */
356
    #[Groups(['user_subscriptions:sessions'])]
357
    #[ORM\ManyToOne(targetEntity: Asset::class, cascade: ['remove'])]
358
    #[ORM\JoinColumn(name: 'image_id', referencedColumnName: 'id', onDelete: 'SET NULL')]
359
    protected ?Asset $image = null;
360
361
    #[ApiProperty(writable: false)]
362
    #[Groups(['user_subscriptions:sessions'])]
363
    private int $accessVisibility;
364
365
    public function __construct()
366
    {
367
        $this->skills = new ArrayCollection();
368
        $this->issuedSkills = new ArrayCollection();
369
        $this->resourceLinks = new ArrayCollection();
370
        $this->courses = new ArrayCollection();
371
        $this->users = new ArrayCollection();
372
        $this->sessionRelCourseRelUsers = new ArrayCollection();
373
        $this->urls = new ArrayCollection();
374
        $this->duration = 0;
375
        $this->description = '';
376
        $this->nbrClasses = 0;
377
        $this->nbrUsers = 0;
378
        $this->nbrCourses = 0;
379
        $this->sendSubscriptionNotification = false;
380
        $now = new DateTime();
381
        $this->displayStartDate = $now;
382
        $this->displayEndDate = $now;
383
        $this->accessStartDate = $now;
384
        $this->accessEndDate = $now;
385
        $this->coachAccessStartDate = $now;
386
        $this->coachAccessEndDate = $now;
387
        $this->visibility = 1;
388
        $this->showDescription = false;
389
        $this->category = null;
390
        $this->status = 0;
391
        $this->position = 0;
392
    }
393
394
    public function __toString(): string
395
    {
396
        return $this->getTitle();
397
    }
398
399
    public static function getRelationTypeList(): array
400
    {
401
        return [self::STUDENT, self::DRH, self::COURSE_COACH, self::GENERAL_COACH, self::SESSION_ADMIN];
402
    }
403
404
    public static function getStatusList(): array
405
    {
406
        return [
407
            self::READ_ONLY => 'status_read_only',
408
            self::VISIBLE => 'status_visible',
409
            self::INVISIBLE => 'status_invisible',
410
            self::AVAILABLE => 'status_available',
411
        ];
412
    }
413
414
    public function getDuration(): ?int
415
    {
416
        return $this->duration;
417
    }
418
419
    public function setDuration(int $duration): self
420
    {
421
        $this->duration = $duration;
422
423
        return $this;
424
    }
425
426
    public function getShowDescription(): bool
427
    {
428
        return $this->showDescription;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->showDescription could return the type null which is incompatible with the type-hinted return boolean. Consider adding an additional type-check to rule them out.
Loading history...
429
    }
430
431
    public function setShowDescription(bool $showDescription): self
432
    {
433
        $this->showDescription = $showDescription;
434
435
        return $this;
436
    }
437
438
    /**
439
     * @return Collection<int, SessionRelUser>
440
     */
441
    public function getUsers(): Collection
442
    {
443
        return $this->users;
444
    }
445
446
    public function setUsers(Collection $users): self
447
    {
448
        $this->users = new ArrayCollection();
449
        foreach ($users as $user) {
450
            $this->addUserSubscription($user);
451
        }
452
453
        return $this;
454
    }
455
456
    public function addUserSubscription(SessionRelUser $subscription): void
457
    {
458
        $subscription->setSession($this);
459
        if (!$this->hasUser($subscription)) {
460
            $this->users->add($subscription);
461
            $this->nbrUsers++;
462
        }
463
    }
464
465
    public function hasUser(SessionRelUser $subscription): bool
466
    {
467
        if (0 !== $this->getUsers()->count()) {
468
            $criteria = Criteria::create()
469
                ->where(
470
                    Criteria::expr()->eq('user', $subscription->getUser())
471
                )
472
                ->andWhere(
473
                    Criteria::expr()->eq('session', $subscription->getSession())
474
                )
475
                ->andWhere(
476
                    Criteria::expr()->eq('relationType', $subscription->getRelationType())
477
                )
478
            ;
479
            $relation = $this->getUsers()->matching($criteria);
480
481
            return $relation->count() > 0;
482
        }
483
484
        return false;
485
    }
486
487
    public function hasCourse(Course $course): bool
488
    {
489
        if (0 !== $this->getCourses()->count()) {
490
            $criteria = Criteria::create()->where(Criteria::expr()->eq('course', $course));
491
            $relation = $this->getCourses()->matching($criteria);
492
493
            return $relation->count() > 0;
494
        }
495
496
        return false;
497
    }
498
499
    /**
500
     * @return Collection<int, SessionRelCourse>
501
     */
502
    public function getCourses(): Collection
503
    {
504
        return $this->courses;
505
    }
506
507
    public function setCourses(ArrayCollection $courses): void
508
    {
509
        $this->courses = new ArrayCollection();
510
        foreach ($courses as $course) {
511
            $this->addCourses($course);
512
        }
513
    }
514
515
    public function addCourses(SessionRelCourse $course): void
516
    {
517
        $course->setSession($this);
518
        $this->courses->add($course);
519
    }
520
521
    public function removeCourses(SessionRelCourse $course): void
522
    {
523
        foreach ($this->courses as $key => $value) {
524
            if ($value->getId() === $course->getId()) {
525
                unset($this->courses[$key]);
526
            }
527
        }
528
    }
529
530
    public function getId(): ?int
531
    {
532
        return $this->id;
533
    }
534
535
    /**
536
     * Remove course subscription for a user.
537
     * If user status in session is student, then decrease number of course users.
538
     */
539
    public function removeUserCourseSubscription(User $user, Course $course): void
540
    {
541
        foreach ($this->sessionRelCourseRelUsers as $i => $sessionRelUser) {
542
            if ($sessionRelUser->getCourse()->getId() === $course->getId()
543
                && $sessionRelUser->getUser()->getId() === $user->getId()
544
            ) {
545
                if (self::STUDENT === $this->sessionRelCourseRelUsers[$i]->getStatus()) {
546
                    $sessionCourse = $this->getCourseSubscription($course);
547
                    $sessionCourse->setNbrUsers($sessionCourse->getNbrUsers() - 1);
548
                }
549
550
                unset($this->sessionRelCourseRelUsers[$i]);
551
            }
552
        }
553
    }
554
555
    public function getStatus(): int
556
    {
557
        return $this->status;
558
    }
559
560
    public function setStatus(int $status): self
561
    {
562
        $this->status = $status;
563
564
        return $this;
565
    }
566
567
    public function setTitle(string $title): self
568
    {
569
        $this->title = $title;
570
571
        return $this;
572
    }
573
574
    public function getCourseSubscription(Course $course): ?SessionRelCourse
575
    {
576
        $criteria = Criteria::create()->where(Criteria::expr()->eq('course', $course));
577
578
        return $this->courses->matching($criteria)->current();
579
    }
580
581
    public function getTitle(): string
582
    {
583
        return $this->title;
584
    }
585
586
    public function getNbrUsers(): int
587
    {
588
        return $this->nbrUsers;
589
    }
590
591
    public function setNbrUsers(int $nbrUsers): self
592
    {
593
        $this->nbrUsers = $nbrUsers;
594
595
        return $this;
596
    }
597
598
    /**
599
     * @return Collection<int, SessionRelCourseRelUser>
600
     */
601
    public function getAllUsersFromCourse(int $status): Collection
602
    {
603
        $criteria = Criteria::create()->where(Criteria::expr()->eq('status', $status));
604
605
        return $this->getSessionRelCourseRelUsers()->matching($criteria);
606
    }
607
608
    public function getSessionRelCourseRelUsers(): Collection
609
    {
610
        return $this->sessionRelCourseRelUsers;
611
    }
612
613
    public function setSessionRelCourseRelUsers(Collection $sessionRelCourseRelUsers): self
614
    {
615
        $this->sessionRelCourseRelUsers = new ArrayCollection();
616
        foreach ($sessionRelCourseRelUsers as $item) {
617
            $this->addSessionRelCourseRelUser($item);
618
        }
619
620
        return $this;
621
    }
622
623
    public function addSessionRelCourseRelUser(SessionRelCourseRelUser $sessionRelCourseRelUser): void
624
    {
625
        $sessionRelCourseRelUser->setSession($this);
626
        if (!$this->hasUserCourseSubscription($sessionRelCourseRelUser)) {
627
            $this->sessionRelCourseRelUsers->add($sessionRelCourseRelUser);
628
        }
629
    }
630
631
    public function hasUserCourseSubscription(SessionRelCourseRelUser $subscription): bool
632
    {
633
        if (0 !== $this->getSessionRelCourseRelUsers()->count()) {
634
            $criteria = Criteria::create()
635
                ->where(
636
                    Criteria::expr()->eq('user', $subscription->getUser())
637
                )
638
                ->andWhere(
639
                    Criteria::expr()->eq('course', $subscription->getCourse())
640
                )
641
                ->andWhere(
642
                    Criteria::expr()->eq('session', $subscription->getSession())
643
                )
644
            ;
645
            $relation = $this->getSessionRelCourseRelUsers()->matching($criteria);
646
647
            return $relation->count() > 0;
648
        }
649
650
        return false;
651
    }
652
653
    /**
654
     * @return Collection<int, SessionRelCourseRelUser>
655
     */
656
    public function getSessionRelCourseByUser(User $user, ?int $status = null): Collection
657
    {
658
        $criteria = Criteria::create()->where(Criteria::expr()->eq('user', $user));
659
        if (null !== $status) {
660
            $criteria->andWhere(Criteria::expr()->eq('status', $status));
661
        }
662
663
        return $this->sessionRelCourseRelUsers->matching($criteria);
664
    }
665
666
    public function getDescription(): ?string
667
    {
668
        return $this->description;
669
    }
670
671
    public function setDescription(string $description): self
672
    {
673
        $this->description = $description;
674
675
        return $this;
676
    }
677
678
    public function getNbrCourses(): int
679
    {
680
        return $this->nbrCourses;
681
    }
682
683
    public function setNbrCourses(int $nbrCourses): self
684
    {
685
        $this->nbrCourses = $nbrCourses;
686
687
        return $this;
688
    }
689
690
    public function getNbrClasses(): int
691
    {
692
        return $this->nbrClasses;
693
    }
694
695
    public function setNbrClasses(int $nbrClasses): self
696
    {
697
        $this->nbrClasses = $nbrClasses;
698
699
        return $this;
700
    }
701
702
    public function getVisibility(): int
703
    {
704
        return $this->visibility;
705
    }
706
707
    public function setVisibility(int $visibility): self
708
    {
709
        $this->visibility = $visibility;
710
711
        return $this;
712
    }
713
714
    public function getPromotion(): ?Promotion
715
    {
716
        return $this->promotion;
717
    }
718
719
    public function setPromotion(?Promotion $promotion): self
720
    {
721
        $this->promotion = $promotion;
722
723
        return $this;
724
    }
725
726
    public function getDisplayStartDate(): ?DateTime
727
    {
728
        return $this->displayStartDate;
729
    }
730
731
    public function setDisplayStartDate(?DateTime $displayStartDate): self
732
    {
733
        $this->displayStartDate = $displayStartDate;
734
735
        return $this;
736
    }
737
738
    public function getDisplayEndDate(): ?DateTime
739
    {
740
        return $this->displayEndDate;
741
    }
742
743
    public function setDisplayEndDate(?DateTime $displayEndDate): self
744
    {
745
        $this->displayEndDate = $displayEndDate;
746
747
        return $this;
748
    }
749
750
    public function getGeneralCoaches(): ReadableCollection
751
    {
752
        return $this->getGeneralCoachesSubscriptions()
753
            ->map(fn (SessionRelUser $subscription) => $subscription->getUser())
754
        ;
755
    }
756
757
    #[Groups(['user_subscriptions:sessions'])]
758
    public function getGeneralCoachesSubscriptions(): Collection
759
    {
760
        $criteria = Criteria::create()->where(Criteria::expr()->eq('relationType', self::GENERAL_COACH));
761
762
        return $this->users->matching($criteria);
763
    }
764
765
    public function hasUserAsGeneralCoach(User $user): bool
766
    {
767
        $criteria = Criteria::create()
768
            ->where(
769
                Criteria::expr()->eq('relationType', self::GENERAL_COACH)
770
            )
771
            ->andWhere(
772
                Criteria::expr()->eq('user', $user)
773
            )
774
        ;
775
776
        return $this->users->matching($criteria)->count() > 0;
777
    }
778
779
    public function addGeneralCoach(User $coach): self
780
    {
781
        return $this->addUserInSession(self::GENERAL_COACH, $coach);
782
    }
783
784
    public function addUserInSession(int $relationType, User $user): self
785
    {
786
        $sessionRelUser = (new SessionRelUser())->setUser($user)->setRelationType($relationType);
787
        $this->addUserSubscription($sessionRelUser);
788
789
        return $this;
790
    }
791
792
    public function removeGeneralCoach(User $user): self
793
    {
794
        $this->removeUserInSession(self::GENERAL_COACH, $user);
795
796
        return $this;
797
    }
798
799
    public function removeUserInSession(int $relationType, User $user): self
800
    {
801
        $criteria = Criteria::create()
802
            ->where(
803
                Criteria::expr()->eq('relationType', $relationType)
804
            )
805
            ->andWhere(
806
                Criteria::expr()->eq('user', $user)
807
            )
808
        ;
809
        $subscriptions = $this->users->matching($criteria);
810
811
        foreach ($subscriptions as $subscription) {
812
            $this->removeUserSubscription($subscription);
813
        }
814
815
        return $this;
816
    }
817
818
    public function removeUserSubscription(SessionRelUser $subscription): self
819
    {
820
        if ($this->hasUser($subscription)) {
821
            $subscription->setSession(null);
822
            $this->users->removeElement($subscription);
823
            $this->nbrUsers--;
824
        }
825
826
        return $this;
827
    }
828
829
    public function getCategory(): ?SessionCategory
830
    {
831
        return $this->category;
832
    }
833
834
    public function setCategory(?SessionCategory $category): self
835
    {
836
        $this->category = $category;
837
838
        return $this;
839
    }
840
841
    /**
842
     * Check if session is visible.
843
     */
844
    public function isActive(): bool
845
    {
846
        $now = new DateTime('now');
847
848
        return $now > $this->getAccessStartDate();
849
    }
850
851
    public function getAccessStartDate(): ?DateTime
852
    {
853
        return $this->accessStartDate;
854
    }
855
856
    public function setAccessStartDate(?DateTime $accessStartDate): self
857
    {
858
        $this->accessStartDate = $accessStartDate;
859
860
        return $this;
861
    }
862
863
    public function isActiveForStudent(): bool
864
    {
865
        $start = $this->getAccessStartDate();
866
        $end = $this->getAccessEndDate();
867
868
        return $this->compareDates($start, $end);
869
    }
870
871
    public function getAccessEndDate(): ?DateTime
872
    {
873
        return $this->accessEndDate;
874
    }
875
876
    public function setAccessEndDate(?DateTime $accessEndDate): self
877
    {
878
        $this->accessEndDate = $accessEndDate;
879
880
        return $this;
881
    }
882
883
    public function isActiveForCoach(): bool
884
    {
885
        $start = $this->getCoachAccessStartDate();
886
        $end = $this->getCoachAccessEndDate();
887
888
        return $this->compareDates($start, $end);
889
    }
890
891
    public function getCoachAccessStartDate(): ?DateTime
892
    {
893
        return $this->coachAccessStartDate;
894
    }
895
896
    public function setCoachAccessStartDate(?DateTime $coachAccessStartDate): self
897
    {
898
        $this->coachAccessStartDate = $coachAccessStartDate;
899
900
        return $this;
901
    }
902
903
    public function getCoachAccessEndDate(): ?DateTime
904
    {
905
        return $this->coachAccessEndDate;
906
    }
907
908
    public function setCoachAccessEndDate(?DateTime $coachAccessEndDate): self
909
    {
910
        $this->coachAccessEndDate = $coachAccessEndDate;
911
912
        return $this;
913
    }
914
915
    /**
916
     * Compare the current date with start and end access dates.
917
     * Either missing date is interpreted as no limit.
918
     *
919
     * @return bool whether now is between the session access start and end dates
920
     */
921
    public function isCurrentlyAccessible(): bool
922
    {
923
        $now = new DateTime();
924
925
        return (!$this->accessStartDate || $now >= $this->accessStartDate) && (!$this->accessEndDate || $now <= $this->accessEndDate);
926
    }
927
928
    public function addCourse(Course $course): self
929
    {
930
        $sessionRelCourse = (new SessionRelCourse())->setCourse($course);
931
        $this->addCourses($sessionRelCourse);
932
933
        return $this;
934
    }
935
936
    /**
937
     * Removes a course from this session.
938
     *
939
     * @param Course $course the course to remove from this session
940
     *
941
     * @return bool whether the course was actually found in this session and removed from it
942
     */
943
    public function removeCourse(Course $course): bool
944
    {
945
        $relCourse = $this->getCourseSubscription($course);
946
        if (null !== $relCourse) {
947
            $this->courses->removeElement($relCourse);
948
            $this->setNbrCourses(\count($this->courses));
949
950
            return true;
951
        }
952
953
        return false;
954
    }
955
956
    /**
957
     * Add a user course subscription.
958
     * If user status in session is student, then increase number of course users.
959
     * Status example: Session::STUDENT.
960
     */
961
    public function addUserInCourse(int $status, User $user, Course $course): SessionRelCourseRelUser
962
    {
963
        $userRelCourseRelSession = (new SessionRelCourseRelUser())
964
            ->setCourse($course)
965
            ->setUser($user)
966
            ->setSession($this)
967
            ->setStatus($status)
968
        ;
969
970
        $this->addSessionRelCourseRelUser($userRelCourseRelSession);
971
972
        if (self::STUDENT === $status) {
973
            $sessionCourse = $this->getCourseSubscription($course);
974
            $sessionCourse->setNbrUsers($sessionCourse->getNbrUsers() + 1);
975
        }
976
977
        return $userRelCourseRelSession;
978
    }
979
980
    /**
981
     * currentCourse is set in CidReqListener.
982
     */
983
    public function getCurrentCourse(): ?Course
984
    {
985
        return $this->currentCourse;
986
    }
987
988
    /**
989
     * currentCourse is set in CidReqListener.
990
     */
991
    public function setCurrentCourse(Course $course): self
992
    {
993
        // If the session is registered in the course session list.
994
        $exists = $this->getCourses()
995
            ->exists(
996
                fn ($key, $element) => $course->getId() === $element->getCourse()->getId()
997
            )
998
        ;
999
1000
        if ($exists) {
1001
            $this->currentCourse = $course;
1002
        }
1003
1004
        return $this;
1005
    }
1006
1007
    public function getSendSubscriptionNotification(): bool
1008
    {
1009
        return $this->sendSubscriptionNotification;
1010
    }
1011
1012
    public function setSendSubscriptionNotification(bool $sendNotification): self
1013
    {
1014
        $this->sendSubscriptionNotification = $sendNotification;
1015
1016
        return $this;
1017
    }
1018
1019
    /**
1020
     * Get user from course by status.
1021
     */
1022
    public function getSessionRelCourseRelUsersByStatus(Course $course, int $status): Collection
1023
    {
1024
        $criteria = Criteria::create()
1025
            ->where(
1026
                Criteria::expr()->eq('course', $course)
1027
            )
1028
            ->andWhere(
1029
                Criteria::expr()->eq('status', $status)
1030
            )
1031
        ;
1032
1033
        return $this->sessionRelCourseRelUsers->matching($criteria);
1034
    }
1035
1036
    public function getSessionRelCourseRelUserInCourse(Course $course): Collection
1037
    {
1038
        $criteria = Criteria::create()
1039
            ->where(
1040
                Criteria::expr()->eq('course', $course)
1041
            )
1042
        ;
1043
1044
        return $this->sessionRelCourseRelUsers->matching($criteria);
1045
    }
1046
1047
    public function getIssuedSkills(): Collection
1048
    {
1049
        return $this->issuedSkills;
1050
    }
1051
1052
    public function getCurrentUrl(): AccessUrl
1053
    {
1054
        return $this->currentUrl;
1055
    }
1056
1057
    public function setCurrentUrl(AccessUrl $url): self
1058
    {
1059
        $urlList = $this->getUrls();
1060
        foreach ($urlList as $item) {
1061
            if ($item->getUrl()->getId() === $url->getId()) {
1062
                $this->currentUrl = $url;
1063
1064
                break;
1065
            }
1066
        }
1067
1068
        return $this;
1069
    }
1070
1071
    /**
1072
     * @return Collection<int, EntityAccessUrlInterface>
1073
     */
1074
    public function getUrls(): Collection
1075
    {
1076
        return $this->urls;
1077
    }
1078
1079
    public function setUrls(Collection $urls): self
1080
    {
1081
        $this->urls = new ArrayCollection();
1082
        foreach ($urls as $url) {
1083
            $this->addUrls($url);
1084
        }
1085
1086
        return $this;
1087
    }
1088
1089
    public function addUrls(AccessUrlRelSession $url): self
1090
    {
1091
        $url->setSession($this);
1092
        $this->urls->add($url);
1093
1094
        return $this;
1095
    }
1096
1097
    public function addAccessUrl(?AccessUrl $url): self
1098
    {
1099
        $accessUrlRelSession = new AccessUrlRelSession();
1100
        $accessUrlRelSession->setUrl($url);
1101
        $accessUrlRelSession->setSession($this);
1102
        $this->addUrls($accessUrlRelSession);
1103
1104
        return $this;
1105
    }
1106
1107
    public function getPosition(): int
1108
    {
1109
        return $this->position;
1110
    }
1111
1112
    public function setPosition(int $position): self
1113
    {
1114
        $this->position = $position;
1115
1116
        return $this;
1117
    }
1118
1119
    public function getSessionAdmins(): ReadableCollection
1120
    {
1121
        return $this->getGeneralAdminsSubscriptions()
1122
            ->map(fn (SessionRelUser $subscription) => $subscription->getUser())
1123
        ;
1124
    }
1125
1126
    public function getGeneralAdminsSubscriptions(): Collection
1127
    {
1128
        $criteria = Criteria::create()->where(Criteria::expr()->eq('relationType', self::SESSION_ADMIN));
1129
1130
        return $this->users->matching($criteria);
1131
    }
1132
1133
    public function hasUserAsSessionAdmin(User $user): bool
1134
    {
1135
        $criteria = Criteria::create()
1136
            ->where(
1137
                Criteria::expr()->eq('relationType', self::SESSION_ADMIN)
1138
            )
1139
            ->andWhere(
1140
                Criteria::expr()->eq('user', $user)
1141
            )
1142
        ;
1143
1144
        return $this->users->matching($criteria)->count() > 0;
1145
    }
1146
1147
    public function addSessionAdmin(User $sessionAdmin): self
1148
    {
1149
        return $this->addUserInSession(self::SESSION_ADMIN, $sessionAdmin);
1150
    }
1151
1152
    public function getSkills(): Collection
1153
    {
1154
        return $this->skills;
1155
    }
1156
1157
    public function getResourceLinks(): Collection
1158
    {
1159
        return $this->resourceLinks;
1160
    }
1161
1162
    public function getImage(): ?Asset
1163
    {
1164
        return $this->image;
1165
    }
1166
1167
    public function setImage(?Asset $asset): self
1168
    {
1169
        $this->image = $asset;
1170
1171
        return $this;
1172
    }
1173
1174
    public function hasImage(): bool
1175
    {
1176
        return null !== $this->image;
1177
    }
1178
1179
    /**
1180
     * Check if $user is course coach in any course.
1181
     */
1182
    public function hasCoachInCourseList(User $user): bool
1183
    {
1184
        foreach ($this->courses as $sessionCourse) {
1185
            if ($this->hasCourseCoachInCourse($user, $sessionCourse->getCourse())) {
1186
                return true;
1187
            }
1188
        }
1189
1190
        return false;
1191
    }
1192
1193
    public function hasCourseCoachInCourse(User $user, ?Course $course = null): bool
1194
    {
1195
        if (null === $course) {
1196
            return false;
1197
        }
1198
1199
        return $this->hasUserInCourse($user, $course, self::COURSE_COACH);
1200
    }
1201
1202
    /**
1203
     * @param int $status if not set it will check if the user is registered
1204
     *                    with any status
1205
     */
1206
    public function hasUserInCourse(User $user, Course $course, ?int $status = null): bool
1207
    {
1208
        $relation = $this->getUserInCourse($user, $course, $status);
1209
1210
        return $relation->count() > 0;
1211
    }
1212
1213
    public function getUserInCourse(User $user, Course $course, ?int $status = null): Collection
1214
    {
1215
        $criteria = Criteria::create()
1216
            ->where(
1217
                Criteria::expr()->eq('course', $course)
1218
            )
1219
            ->andWhere(
1220
                Criteria::expr()->eq('user', $user)
1221
            )
1222
        ;
1223
1224
        if (null !== $status) {
1225
            $criteria->andWhere(Criteria::expr()->eq('status', $status));
1226
        }
1227
1228
        return $this->getSessionRelCourseRelUsers()->matching($criteria);
1229
    }
1230
1231
    /**
1232
     * Check if $user is student in any course.
1233
     */
1234
    public function hasStudentInCourseList(User $user): bool
1235
    {
1236
        foreach ($this->courses as $sessionCourse) {
1237
            if ($this->hasStudentInCourse($user, $sessionCourse->getCourse())) {
1238
                return true;
1239
            }
1240
        }
1241
1242
        return false;
1243
    }
1244
1245
    public function hasStudentInCourse(User $user, Course $course): bool
1246
    {
1247
        return $this->hasUserInCourse($user, $course, self::STUDENT);
1248
    }
1249
1250
    protected function compareDates(?DateTime $start, ?DateTime $end = null): bool
1251
    {
1252
        $now = new DateTime('now');
1253
1254
        if (!empty($start) && !empty($end)) {
1255
            return $now >= $start && $now <= $end;
1256
        }
1257
1258
        if (!empty($start)) {
1259
            return $now >= $start;
1260
        }
1261
1262
        return !empty($end) && $now <= $end;
1263
    }
1264
1265
    /**
1266
     * @return Collection<int, SessionRelCourseRelUser>
1267
     */
1268
    #[Groups(['user_subscriptions:sessions'])]
1269
    public function getCourseCoachesSubscriptions(): Collection
1270
    {
1271
        return $this->getAllUsersFromCourse(self::COURSE_COACH);
1272
    }
1273
1274
    public function isAvailableByDurationForUser(User $user): bool
1275
    {
1276
        $duration = $this->duration * 24 * 60 * 60;
1277
1278
        if (0 === $user->getTrackECourseAccess()->count()) {
1279
            return true;
1280
        }
1281
1282
        $trackECourseAccess = $user->getFirstAccessToSession($this);
1283
1284
        $firstAccess = $trackECourseAccess
1285
            ? $trackECourseAccess->getLoginCourseDate()->getTimestamp()
1286
            : 0;
1287
1288
        $userDurationData = $user->getSubscriptionToSession($this);
1289
1290
        $userDuration = $userDurationData
1291
            ? ($userDurationData->getDuration() * 24 * 60 * 60)
1292
            : 0;
1293
1294
        $totalDuration = $firstAccess + $duration + $userDuration;
1295
        $currentTime = time();
1296
1297
        return $totalDuration > $currentTime;
1298
    }
1299
1300
    private function getAccessVisibilityByDuration(User $user): int
1301
    {
1302
        // Session duration per student.
1303
        if ($this->getDuration() > 0) {
1304
            $duration = $this->getDuration() * 24 * 60 * 60;
1305
            $courseAccess = $user->getFirstAccessToSession($this);
1306
1307
            // If there is a session duration but there is no previous
1308
            // access by the user, then the session is still available
1309
            if (!$courseAccess) {
1310
                return self::AVAILABLE;
1311
            }
1312
1313
            $currentTime = time();
1314
            $firstAccess = $courseAccess->getLoginCourseDate()->getTimestamp();
1315
            $userSessionSubscription = $user->getSubscriptionToSession($this);
1316
            $userDuration = $userSessionSubscription
1317
                ? $userSessionSubscription->getDuration() * 24 * 60 * 60
1318
                : 0;
1319
1320
            $totalDuration = $firstAccess + $duration + $userDuration;
1321
1322
            return $totalDuration > $currentTime ? self::AVAILABLE : self::READ_ONLY;
1323
        }
1324
1325
        return self::AVAILABLE;
1326
    }
1327
1328
    /**
1329
     * Checks whether the user is a course or session coach.
1330
     */
1331
    public function hasCoach(User $user): bool
1332
    {
1333
        return $this->hasUserAsGeneralCoach($user) || $this->hasCoachInCourseList($user);
1334
    }
1335
1336
    private function getAcessVisibilityByDates(User $user): int
1337
    {
1338
        $now = new DateTime();
1339
        $visibility = $this->getVisibility();
1340
1341
        // If start date was set.
1342
        if ($this->getAccessStartDate()) {
1343
            $visibility = $now > $this->getAccessStartDate() ? self::AVAILABLE : self::INVISIBLE;
1344
        }
1345
1346
        // If the end date was set.
1347
        if ($this->getAccessEndDate()) {
1348
            // Only if date_start said that it was ok
1349
            if (self::AVAILABLE === $visibility) {
1350
                $visibility = $now < $this->getAccessEndDate()
1351
                    ? self::AVAILABLE // Date still available
1352
                    : $this->getVisibility(); // Session ends
1353
            }
1354
        }
1355
1356
        // If I'm a coach the visibility can change in my favor depending in the coach dates.
1357
        $isCoach = $this->hasCoach($user);
1358
1359
        if ($isCoach) {
1360
            // Test start date.
1361
            if ($this->getCoachAccessStartDate()) {
1362
                $visibility = $this->getCoachAccessStartDate() < $now ? self::AVAILABLE : self::INVISIBLE;
1363
            }
1364
1365
            // Test end date.
1366
            if ($this->getCoachAccessEndDate()) {
1367
                if (self::AVAILABLE === $visibility) {
1368
                    $visibility = $this->getCoachAccessEndDate() >= $now ? self::AVAILABLE : $this->getVisibility();
1369
                }
1370
            }
1371
        }
1372
1373
        return $visibility;
1374
    }
1375
1376
    public function checkAccessVisibilityByUser(User $user): int
1377
    {
1378
        if ($user->isAdmin() || $user->isSuperAdmin()) {
1379
            $this->accessVisibility = self::AVAILABLE;
1380
        } elseif (null === $this->getAccessStartDate() && null === $this->getAccessEndDate()) {
1381
            // I don't care the session visibility.
1382
            $this->accessVisibility = $this->getAccessVisibilityByDuration($user);
1383
        } else {
1384
            $this->accessVisibility = $this->getAcessVisibilityByDates($user);
1385
        }
1386
1387
        return $this->accessVisibility;
1388
    }
1389
1390
    public function getAccessVisibility(): int
1391
    {
1392
        return $this->accessVisibility;
1393
    }
1394
}
1395