Passed
Pull Request — master (#5738)
by
unknown
07:04
created

SessionRepository::getCurrentSessionsOfUserInUrl()   C

Complexity

Conditions 12
Paths 1

Size

Total Lines 50
Code Lines 25

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 12
eloc 25
nc 1
nop 2
dl 0
loc 50
rs 6.9666
c 4
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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