Passed
Pull Request — master (#5738)
by
unknown
15:54 queued 08:46
created

SessionRepository::getSessionsByUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
nc 1
nop 2
dl 0
loc 15
rs 9.9332
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
            $coursesAsCoach = $this->getSessionCoursesByStatusInCourseSubscription($user, $session, Session::COURSE_COACH, $url);
136
            $coursesAsStudent = $this->getSessionCoursesByStatusInCourseSubscription($user, $session, Session::STUDENT, $url);
137
            $validCourses = array_merge($coursesAsCoach, $coursesAsStudent);
138
139
            if (empty($validCourses)) {
140
                return false;
141
            }
142
143
            $session->setCourses(new ArrayCollection($validCourses));
144
145
            // Check if session has a duration
146
            if ($session->getDuration() > 0) {
147
                $daysLeft = $session->getDaysLeftByUser($user);
148
149
                return $daysLeft >= 0;
150
            }
151
152
            $now = new DateTime();
153
            $sessionStartDate = $session->getAccessStartDate();
154
            $sessionEndDate = $session->getAccessEndDate();
155
156
            $isWithinDateRange = $now >= $sessionStartDate && (!$sessionEndDate || $now <= $sessionEndDate);
157
158
            return $isWithinDateRange;
159
        };
160
161
        $filteredSessions = array_filter($sessions, $filterCurrentSessions);
162
163
        return $filteredSessions;
164
    }
165
166
    /**
167
     * @return array<int, Session>
168
     *
169
     * @throws Exception
170
     */
171
    public function getUpcomingSessionsOfUserInUrl(User $user, AccessUrl $url): array
172
    {
173
        $sessions = $this->getSubscribedSessionsOfUserInUrl($user, $url);
174
175
        $filterUpcomingSessions = function (Session $session) use ($user) {
176
            $now = new DateTime();
177
178
            // All session with access by duration call be either current or past
179
            if ($session->getDuration() > 0) {
180
                return false;
181
            }
182
183
            // Determine if the user is a coach
184
            $userIsCoach = $session->hasCoach($user);
185
186
            // Get the appropriate start date based on whether the user is a coach
187
            $sessionStartDate = $userIsCoach && $session->getCoachAccessStartDate()
188
                ? $session->getCoachAccessStartDate()
189
                : $session->getAccessStartDate();
190
191
            // If there's no start date, the session is not considered future
192
            if (!$sessionStartDate) {
193
                return false;
194
            }
195
196
            // Check if the current date is before the start date
197
            return $now < $sessionStartDate;
198
        };
199
200
        return array_filter($sessions, $filterUpcomingSessions);
201
    }
202
203
    public function addUserInCourse(int $relationType, User $user, Course $course, Session $session): void
204
    {
205
        if (!$user->isActive()) {
206
            throw new Exception('User not active');
207
        }
208
209
        if (!$session->hasCourse($course)) {
210
            $msg = sprintf('Course %s is not subscribed to the session %s', $course->getTitle(), $session->getTitle());
211
212
            throw new Exception($msg);
213
        }
214
215
        if (!\in_array($relationType, Session::getRelationTypeList(), true)) {
216
            throw new Exception(sprintf('Cannot handle relationType %s', $relationType));
217
        }
218
219
        $entityManager = $this->getEntityManager();
220
        $existingRecord = $entityManager->getRepository(SessionRelUser::class)->findOneBy([
221
            'session' => $session,
222
            'user' => $user,
223
            'relationType' => $relationType,
224
        ]);
225
226
        if ($existingRecord) {
227
            $entityManager->remove($existingRecord);
228
            $entityManager->flush();
229
        }
230
231
        switch ($relationType) {
232
            case Session::DRH:
233
                if ($user->hasRole('ROLE_HR')) {
234
                    $session->addUserInSession(Session::DRH, $user);
235
                }
236
237
                break;
238
239
            case Session::STUDENT:
240
                $session
241
                    ->addUserInSession(Session::STUDENT, $user)
242
                    ->addUserInCourse(Session::STUDENT, $user, $course)
243
                ;
244
245
                break;
246
247
            case Session::COURSE_COACH:
248
                if ($user->hasRole('ROLE_TEACHER')) {
249
                    $session
250
                        ->addUserInSession(Session::COURSE_COACH, $user)
251
                        ->addUserInCourse(
252
                            Session::COURSE_COACH,
253
                            $user,
254
                            $course
255
                        )
256
                    ;
257
                }
258
259
                break;
260
        }
261
262
        $entityManager->persist($session);
263
        $entityManager->flush();
264
    }
265
266
    /**
267
     * @return array<SessionRelCourse>
268
     */
269
    public function getSessionCoursesByStatusInUserSubscription(User $user, Session $session, int $relationType, ?AccessUrl $url = null): array
270
    {
271
        $qb = $this->getEntityManager()->createQueryBuilder();
272
273
        $qb->select('src')
274
            ->from(SessionRelCourse::class, 'src')
275
            ->innerJoin(
276
                SessionRelUser::class,
277
                'sru',
278
                Join::WITH,
279
                'src.session = sru.session'
280
            )
281
            ->innerJoin('src.session', 'session')
282
            ->where(
283
                $qb->expr()->eq('session', ':session')
284
            )
285
            ->andWhere(
286
                $qb->expr()->eq('sru.user', ':user')
287
            )
288
            ->andWhere(
289
                $qb->expr()->eq('sru.relationType', ':relation_type')
290
            )
291
        ;
292
293
        $parameters = [
294
            'session' => $session,
295
            'user' => $user,
296
            'relation_type' => $relationType,
297
        ];
298
299
        if ($url) {
300
            $qb->innerJoin('session.urls', 'urls')
301
                ->andWhere(
302
                    $qb->expr()->eq('urls.url', ':url')
303
                )
304
            ;
305
306
            $parameters['url'] = $url;
307
        }
308
309
        $qb->setParameters($parameters);
310
311
        return $qb->getQuery()->getResult();
312
    }
313
314
    /**
315
     * @return array<SessionRelCourse>
316
     */
317
    public function getSessionCoursesByStatusInCourseSubscription(User $user, Session $session, int $status, ?AccessUrl $url = null): array
318
    {
319
        $qb = $this->getEntityManager()->createQueryBuilder();
320
321
        $qb->select('src')
322
            ->from(SessionRelCourse::class, 'src')
323
            ->innerJoin(
324
                SessionRelCourseRelUser::class,
325
                'srcru',
326
                Join::WITH,
327
                'src.session = srcru.session AND src.course = srcru.course'
328
            )
329
            ->innerJoin('srcru.session', 'session')
330
            ->where(
331
                $qb->expr()->eq('session', ':session')
332
            )
333
            ->andWhere(
334
                $qb->expr()->eq('srcru.user', ':user')
335
            )
336
            ->andWhere(
337
                $qb->expr()->eq('srcru.status', ':status')
338
            )
339
        ;
340
341
        $parameters = [
342
            'session' => $session,
343
            'user' => $user,
344
            'status' => $status,
345
        ];
346
347
        if ($url) {
348
            $qb->innerJoin('session.urls', 'urls')
349
                ->andWhere(
350
                    $qb->expr()->eq('urls.url', ':url')
351
                )
352
            ;
353
354
            $parameters['url'] = $url;
355
        }
356
357
        $qb->setParameters($parameters);
358
359
        return $qb->getQuery()->getResult();
360
    }
361
362
    private function addSessionRelUserFilterByUrl(Session $session, AccessUrl $url): QueryBuilder
363
    {
364
        $qb = $this->getEntityManager()->createQueryBuilder();
365
        $qb
366
            ->select('sru')
367
            ->from(SessionRelUser::class, 'sru')
368
            ->innerJoin('sru.user', 'u')
369
            ->innerJoin('u.portals', 'p')
370
            ->andWhere('sru.session = :session AND p.url = :url')
371
            ->setParameters([
372
                'session' => $session,
373
                'url' => $url,
374
            ])
375
        ;
376
377
        return $qb;
378
    }
379
380
    public function getUserFollowedSessionsInAccessUrl(User $user, AccessUrl $url): QueryBuilder
381
    {
382
        $callback = fn (Session $session) => $session->getId();
383
384
        if ($user->isHRM()) {
385
            $idList = array_map($callback, $user->getDRHSessions());
386
        } elseif ($user->isTeacher() || COURSEMANAGER === $user->getStatus()) {
387
            $idListAsCoach = $user
388
                ->getSessionsByStatusInCourseSubscription(Session::COURSE_COACH)
389
                ->map($callback)
390
                ->getValues()
391
            ;
392
            $idListAsGeneralCoach = array_map($callback, $user->getSessionsAsGeneralCoach());
393
            $idList = array_merge($idListAsCoach, $idListAsGeneralCoach);
394
        } elseif ($user->isSessionAdmin()) {
395
            $idList = array_map($callback, $user->getSessionsAsAdmin());
396
        } else {
397
            $idList = array_map($callback, $user->getSessionsAsStudent());
398
        }
399
400
        $qb = $this->createQueryBuilder('s');
401
        $qb
402
            ->innerJoin('s.urls', 'u')
403
            ->where($qb->expr()->eq('u.url', $url->getId()))
404
            ->andWhere($qb->expr()->in('s.id', ':id_list'))
405
            ->setParameter('id_list', $idList)
406
        ;
407
408
        return $qb;
409
    }
410
411
    /**
412
     * @return array<int, Session>
413
     *
414
     * @throws Exception
415
     */
416
    public function getSubscribedSessionsOfUserInUrl(
417
        User $user,
418
        AccessUrl $url,
419
        bool $ignoreVisibilityForAdmins = false,
420
    ): array {
421
        $sessions = $this->getSessionsByUser($user, $url)->getQuery()->getResult();
422
423
        $filterSessions = function (Session $session) use ($user, $ignoreVisibilityForAdmins) {
424
            $visibility = $session->setAccessVisibilityByUser($user, $ignoreVisibilityForAdmins);
425
426
            if (Session::VISIBLE !== $visibility) {
427
                $closedOrHiddenCourses = $session->getClosedOrHiddenCourses();
428
429
                if ($closedOrHiddenCourses->count() === $session->getCourses()->count()) {
430
                    $visibility = Session::INVISIBLE;
431
                }
432
            }
433
434
            switch ($visibility) {
435
                case Session::READ_ONLY:
436
                case Session::VISIBLE:
437
                case Session::AVAILABLE:
438
                    break;
439
440
                case Session::INVISIBLE:
441
                    if (!$ignoreVisibilityForAdmins) {
442
                        return false;
443
                    }
444
            }
445
446
            return true;
447
        };
448
449
        return array_filter($sessions, $filterSessions);
450
    }
451
}
452