Passed
Push — master ( 47d014...744a9d )
by Angel Fernando Quiroz
09:11
created

Session::removeUserSubscription()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

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