Passed
Push — dependabot/npm_and_yarn/microm... ( f2f212...f35bf2 )
by
unknown
13:36 queued 05:58
created

SessionRepository::getUsersByAccessUrl()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 8
nc 3
nop 3
dl 0
loc 16
rs 10
c 0
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/* For licensing terms, see /license.txt */
6
7
namespace Chamilo\CoreBundle\Repository;
8
9
use Chamilo\CoreBundle\Entity\AccessUrl;
10
use Chamilo\CoreBundle\Entity\Course;
11
use Chamilo\CoreBundle\Entity\Session;
12
use Chamilo\CoreBundle\Entity\SessionRelCourse;
13
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
14
use Chamilo\CoreBundle\Entity\SessionRelUser;
15
use Chamilo\CoreBundle\Entity\User;
16
use Chamilo\CoreBundle\Settings\SettingsManager;
17
use DateTime;
18
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
19
use Doctrine\Common\Collections\ArrayCollection;
20
use Doctrine\ORM\Query\Expr\Join;
21
use Doctrine\ORM\QueryBuilder;
22
use Doctrine\Persistence\ManagerRegistry;
23
use Exception;
24
25
/**
26
 * @author Julio Montoya <[email protected]>
27
 */
28
class SessionRepository extends ServiceEntityRepository
29
{
30
    public function __construct(
31
        ManagerRegistry $registry,
32
        private readonly SettingsManager $settingsManager,
33
    ) {
34
        parent::__construct($registry, Session::class);
35
    }
36
37
    public function create(): ?Session
38
    {
39
        return new Session();
40
    }
41
42
    public function update(Session $session): void
43
    {
44
        $this->getEntityManager()->persist($session);
45
        $this->getEntityManager()->flush();
46
    }
47
48
    /**
49
     * @return array<SessionRelUser>
50
     */
51
    public function getUsersByAccessUrl(Session $session, AccessUrl $url, array $relationTypeList = []): array
52
    {
53
        if (0 === $session->getUsers()->count()) {
54
            return [];
55
        }
56
57
        $qb = $this->addSessionRelUserFilterByUrl($session, $url);
58
        $qb->orderBy('sru.relationType');
59
60
        if ($relationTypeList) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $relationTypeList of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
61
            $qb->andWhere(
62
                $qb->expr()->in('sru.relationType', $relationTypeList)
63
            );
64
        }
65
66
        return $qb->getQuery()->getResult();
67
    }
68
69
    public function getSessionsByUser(User $user, AccessUrl $url): QueryBuilder
70
    {
71
        $qb = $this->createQueryBuilder('s');
72
        $qb
73
            ->innerJoin('s.users', 'sru')
74
            ->leftJoin('s.urls', 'urls')
75
            ->where($qb->expr()->eq('sru.user', ':user'))
76
            ->andWhere($qb->expr()->eq('urls.url', ':url'))
77
            ->setParameters([
78
                'user' => $user,
79
                'url' => $url,
80
            ])
81
        ;
82
83
        return $qb;
84
    }
85
86
    /**
87
     * @return array<int, Session>
88
     *
89
     * @throws Exception
90
     */
91
    public function getPastSessionsOfUserInUrl(User $user, AccessUrl $url): array
92
    {
93
        $sessions = $this->getSubscribedSessionsOfUserInUrl($user, $url);
94
95
        $filterPastSessions = function (Session $session) use ($user) {
96
            $now = new DateTime();
97
            // Determine if the user is a coach
98
            $userIsCoach = $session->hasCoach($user);
99
100
            // Check if the session has a duration
101
            if ($session->getDuration() > 0) {
102
                $daysLeft = $session->getDaysLeftByUser($user);
103
                $session->setTitle($session->getTitle().'<-'.$daysLeft);
104
105
                return $daysLeft < 0 && !$userIsCoach;
106
            }
107
108
            // Get the appropriate end date based on whether the user is a coach
109
            $sessionEndDate = $userIsCoach && $session->getCoachAccessEndDate()
110
                ? $session->getCoachAccessEndDate()
111
                : $session->getAccessEndDate();
112
113
            // If there's no end date, the session is not considered past
114
            if (!$sessionEndDate) {
115
                return false;
116
            }
117
118
            // Check if the current date is after the end date
119
            return $now > $sessionEndDate;
120
        };
121
122
        return array_filter($sessions, $filterPastSessions);
123
    }
124
125
    /**
126
     * @return array<int, Session>
127
     *
128
     * @throws Exception
129
     */
130
    public function getCurrentSessionsOfUserInUrl(User $user, AccessUrl $url): array
131
    {
132
        $sessions = $this->getSubscribedSessionsOfUserInUrl($user, $url);
133
134
        $filterCurrentSessions = function (Session $session) use ($user, $url) {
135
            $userIsGeneralCoach = $session->hasUserAsGeneralCoach($user);
136
            if (!$userIsGeneralCoach) {
137
                $coursesAsCoach = $this->getSessionCoursesByStatusInCourseSubscription($user, $session, Session::COURSE_COACH, $url);
138
                $coursesAsStudent = $this->getSessionCoursesByStatusInCourseSubscription($user, $session, Session::STUDENT, $url);
139
                $validCourses = array_merge($coursesAsCoach, $coursesAsStudent);
140
141
                if (empty($validCourses)) {
142
                    return false;
143
                }
144
                $session->setCourses(new ArrayCollection($validCourses));
145
            }
146
147
            $userIsCoach = $session->hasCoach($user);
148
149
            // Check if session has a duration
150
            if ($session->getDuration() > 0) {
151
                $daysLeft = $session->getDaysLeftByUser($user);
152
153
                return $daysLeft >= 0 || $userIsCoach;
154
            }
155
156
            // Determine the start date based on whether the user is a coach
157
            $sessionStartDate = $userIsCoach && $session->getCoachAccessStartDate()
158
                ? $session->getCoachAccessStartDate()
159
                : $session->getAccessStartDate();
160
161
            // If there is no start date, consider the session current
162
            if (!$sessionStartDate) {
163
                return true;
164
            }
165
166
            // Get the current date and time
167
            $now = new DateTime();
168
169
            // Determine the end date based on whether the user is a coach
170
            $sessionEndDate = $userIsCoach && $session->getCoachAccessEndDate()
171
                ? $session->getCoachAccessEndDate()
172
                : $session->getAccessEndDate();
173
174
            // Check if the current date is within the start and end dates
175
            return $now >= $sessionStartDate && (!$sessionEndDate || $now <= $sessionEndDate);
176
        };
177
178
        return array_filter($sessions, $filterCurrentSessions);
179
    }
180
181
    /**
182
     * @return array<int, Session>
183
     *
184
     * @throws Exception
185
     */
186
    public function getUpcomingSessionsOfUserInUrl(User $user, AccessUrl $url): array
187
    {
188
        $sessions = $this->getSubscribedSessionsOfUserInUrl($user, $url);
189
190
        $filterUpcomingSessions = function (Session $session) use ($user) {
191
            $now = new DateTime();
192
193
            // All session with access by duration call be either current or past
194
            if ($session->getDuration() > 0) {
195
                return false;
196
            }
197
198
            // Determine if the user is a coach
199
            $userIsCoach = $session->hasCoach($user);
200
201
            // Get the appropriate start date based on whether the user is a coach
202
            $sessionStartDate = $userIsCoach && $session->getCoachAccessStartDate()
203
                ? $session->getCoachAccessStartDate()
204
                : $session->getAccessStartDate();
205
206
            // If there's no start date, the session is not considered future
207
            if (!$sessionStartDate) {
208
                return false;
209
            }
210
211
            // Check if the current date is before the start date
212
            return $now < $sessionStartDate;
213
        };
214
215
        return array_filter($sessions, $filterUpcomingSessions);
216
    }
217
218
    public function addUserInCourse(int $relationType, User $user, Course $course, Session $session): void
219
    {
220
        if (!$user->isActive()) {
221
            throw new Exception('User not active');
222
        }
223
224
        if (!$session->hasCourse($course)) {
225
            $msg = \sprintf('Course %s is not subscribed to the session %s', $course->getTitle(), $session->getTitle());
226
227
            throw new Exception($msg);
228
        }
229
230
        if (!\in_array($relationType, Session::getRelationTypeList(), true)) {
231
            throw new Exception(\sprintf('Cannot handle relationType %s', $relationType));
232
        }
233
234
        $entityManager = $this->getEntityManager();
235
        $existingRecord = $entityManager->getRepository(SessionRelUser::class)->findOneBy([
236
            'session' => $session,
237
            'user' => $user,
238
            'relationType' => $relationType,
239
        ]);
240
241
        if ($existingRecord) {
242
            $entityManager->remove($existingRecord);
243
            $entityManager->flush();
244
        }
245
246
        switch ($relationType) {
247
            case Session::DRH:
248
                if ($user->hasRole('ROLE_HR')) {
249
                    $session->addUserInSession(Session::DRH, $user);
250
                }
251
252
                break;
253
254
            case Session::STUDENT:
255
                $session
256
                    ->addUserInSession(Session::STUDENT, $user)
257
                    ->addUserInCourse(Session::STUDENT, $user, $course)
258
                ;
259
260
                break;
261
262
            case Session::COURSE_COACH:
263
                if ($user->hasRole('ROLE_TEACHER')) {
264
                    $session
265
                        ->addUserInSession(Session::COURSE_COACH, $user)
266
                        ->addUserInCourse(
267
                            Session::COURSE_COACH,
268
                            $user,
269
                            $course
270
                        )
271
                    ;
272
                }
273
274
                break;
275
        }
276
277
        $entityManager->persist($session);
278
        $entityManager->flush();
279
    }
280
281
    /**
282
     * @return array<SessionRelCourse>
283
     */
284
    public function getSessionCoursesByStatusInUserSubscription(User $user, Session $session, int $relationType, ?AccessUrl $url = null): array
285
    {
286
        $qb = $this->getEntityManager()->createQueryBuilder();
287
288
        $qb->select('src')
289
            ->from(SessionRelCourse::class, 'src')
290
            ->innerJoin(
291
                SessionRelUser::class,
292
                'sru',
293
                Join::WITH,
294
                'src.session = sru.session'
295
            )
296
            ->innerJoin('src.session', 'session')
297
            ->where(
298
                $qb->expr()->eq('session', ':session')
299
            )
300
            ->andWhere(
301
                $qb->expr()->eq('sru.user', ':user')
302
            )
303
            ->andWhere(
304
                $qb->expr()->eq('sru.relationType', ':relation_type')
305
            )
306
        ;
307
308
        $parameters = [
309
            'session' => $session,
310
            'user' => $user,
311
            'relation_type' => $relationType,
312
        ];
313
314
        if ($url) {
315
            $qb->innerJoin('session.urls', 'urls')
316
                ->andWhere(
317
                    $qb->expr()->eq('urls.url', ':url')
318
                )
319
            ;
320
321
            $parameters['url'] = $url;
322
        }
323
324
        $qb->setParameters($parameters);
325
326
        return $qb->getQuery()->getResult();
327
    }
328
329
    /**
330
     * @return array<SessionRelCourse>
331
     */
332
    public function getSessionCoursesByStatusInCourseSubscription(User $user, Session $session, int $status, ?AccessUrl $url = null): array
333
    {
334
        $qb = $this->getEntityManager()->createQueryBuilder();
335
336
        $qb->select('src')
337
            ->from(SessionRelCourse::class, 'src')
338
            ->innerJoin(
339
                SessionRelCourseRelUser::class,
340
                'srcru',
341
                Join::WITH,
342
                'src.session = srcru.session AND src.course = srcru.course'
343
            )
344
            ->innerJoin('srcru.session', 'session')
345
            ->where(
346
                $qb->expr()->eq('session', ':session')
347
            )
348
            ->andWhere(
349
                $qb->expr()->eq('srcru.user', ':user')
350
            )
351
            ->andWhere(
352
                $qb->expr()->eq('srcru.status', ':status')
353
            )
354
        ;
355
356
        $parameters = [
357
            'session' => $session,
358
            'user' => $user,
359
            'status' => $status,
360
        ];
361
362
        if ($url) {
363
            $qb->innerJoin('session.urls', 'urls')
364
                ->andWhere(
365
                    $qb->expr()->eq('urls.url', ':url')
366
                )
367
            ;
368
369
            $parameters['url'] = $url;
370
        }
371
372
        $qb->setParameters($parameters);
373
374
        return $qb->getQuery()->getResult();
375
    }
376
377
    private function addSessionRelUserFilterByUrl(Session $session, AccessUrl $url): QueryBuilder
378
    {
379
        $qb = $this->getEntityManager()->createQueryBuilder();
380
        $qb
381
            ->select('sru')
382
            ->from(SessionRelUser::class, 'sru')
383
            ->innerJoin('sru.user', 'u')
384
            ->innerJoin('u.portals', 'p')
385
            ->andWhere('sru.session = :session AND p.url = :url')
386
            ->setParameters([
387
                'session' => $session,
388
                'url' => $url,
389
            ])
390
        ;
391
392
        return $qb;
393
    }
394
395
    public function getUserFollowedSessionsInAccessUrl(User $user, AccessUrl $url): QueryBuilder
396
    {
397
        $callback = fn (Session $session) => $session->getId();
398
399
        if ($user->isHRM()) {
400
            $idList = array_map($callback, $user->getDRHSessions());
401
        } elseif ($user->isTeacher() || COURSEMANAGER === $user->getStatus()) {
402
            $idListAsCoach = $user
403
                ->getSessionsByStatusInCourseSubscription(Session::COURSE_COACH)
404
                ->map($callback)
405
                ->getValues()
406
            ;
407
            $idListAsGeneralCoach = array_map($callback, $user->getSessionsAsGeneralCoach());
408
            $idList = array_merge($idListAsCoach, $idListAsGeneralCoach);
409
        } elseif ($user->isSessionAdmin()) {
410
            $idList = array_map($callback, $user->getSessionsAsAdmin());
411
        } else {
412
            $idList = array_map($callback, $user->getSessionsAsStudent());
413
        }
414
415
        $qb = $this->createQueryBuilder('s');
416
        $qb
417
            ->innerJoin('s.urls', 'u')
418
            ->where($qb->expr()->eq('u.url', $url->getId()))
419
            ->andWhere($qb->expr()->in('s.id', ':id_list'))
420
            ->setParameter('id_list', $idList)
421
        ;
422
423
        return $qb;
424
    }
425
426
    /**
427
     * @return array<int, Session>
428
     *
429
     * @throws Exception
430
     */
431
    public function getSubscribedSessionsOfUserInUrl(
432
        User $user,
433
        AccessUrl $url,
434
        bool $ignoreVisibilityForAdmins = false,
435
    ): array {
436
        $sessions = $this->getSessionsByUser($user, $url)->getQuery()->getResult();
437
438
        $filterSessions = function (Session $session) use ($user, $ignoreVisibilityForAdmins) {
439
            $visibility = $session->setAccessVisibilityByUser($user, $ignoreVisibilityForAdmins);
440
441
            if (Session::VISIBLE !== $visibility) {
442
                $closedOrHiddenCourses = $session->getClosedOrHiddenCourses();
443
444
                if ($closedOrHiddenCourses->count() === $session->getCourses()->count()) {
445
                    $visibility = Session::INVISIBLE;
446
                }
447
            }
448
449
            switch ($visibility) {
450
                case Session::READ_ONLY:
451
                case Session::VISIBLE:
452
                case Session::AVAILABLE:
453
                    break;
454
455
                case Session::INVISIBLE:
456
                    if (!$ignoreVisibilityForAdmins) {
457
                        return false;
458
                    }
459
            }
460
461
            return true;
462
        };
463
464
        return array_filter($sessions, $filterSessions);
465
    }
466
467
    public function countUsersBySession(int $sessionId): int
468
    {
469
        $qb = $this->createQueryBuilder('s');
470
        $qb->select('COUNT(sru.id)')
471
            ->innerJoin('s.users', 'sru')
472
            ->where('s.id = :sessionId')
473
            ->setParameter('sessionId', $sessionId);
474
475
        return (int) $qb->getQuery()->getSingleScalarResult();
476
    }
477
}
478