Passed
Push — master ( 10e205...526a26 )
by
unknown
10:25 queued 14s
created

Session::setSessionRelCourseRelUsers()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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