Passed
Push — master ( 736e5d...28a07b )
by
unknown
09:44 queued 15s
created

Session::getStatusList()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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