Passed
Pull Request — master (#5576)
by Angel Fernando Quiroz
09:01
created

SessionRepository::addUserInCourse()   B

Complexity

Conditions 9
Paths 9

Size

Total Lines 45
Code Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 26
nc 9
nop 4
dl 0
loc 45
rs 8.0555
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\ORM\Query\Expr\Join;
20
use Doctrine\ORM\QueryBuilder;
21
use Doctrine\Persistence\ManagerRegistry;
22
use Exception;
23
24
/**
25
 * @author Julio Montoya <[email protected]>
26
 */
27
class SessionRepository extends ServiceEntityRepository
28
{
29
    public function __construct(
30
        ManagerRegistry $registry,
31
        private readonly SettingsManager $settingsManager,
32
    ) {
33
        parent::__construct($registry, Session::class);
34
    }
35
36
    public function create(): ?Session
37
    {
38
        return new Session();
39
    }
40
41
    public function update(Session $session): void
42
    {
43
        $this->getEntityManager()->persist($session);
44
        $this->getEntityManager()->flush();
45
    }
46
47
    /**
48
     * @return array<SessionRelUser>
49
     */
50
    public function getUsersByAccessUrl(Session $session, AccessUrl $url, array $relationTypeList = []): array
51
    {
52
        if (0 === $session->getUsers()->count()) {
53
            return [];
54
        }
55
56
        $qb = $this->addSessionRelUserFilterByUrl($session, $url);
57
        $qb->orderBy('sru.relationType');
58
59
        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...
60
            $qb->andWhere(
61
                $qb->expr()->in('sru.relationType', $relationTypeList)
62
            );
63
        }
64
65
        return $qb->getQuery()->getResult();
66
    }
67
68
    public function getSessionsByUser(User $user, AccessUrl $url): QueryBuilder
69
    {
70
        $qb = $this->createQueryBuilder('s');
71
        $qb
72
            ->innerJoin('s.users', 'sru')
73
            ->leftJoin('s.urls', 'urls')
74
            ->where($qb->expr()->eq('sru.user', ':user'))
75
            ->andWhere($qb->expr()->eq('urls.url', ':url'))
76
            ->setParameters([
77
                'user' => $user,
78
                'url' => $url,
79
            ])
80
        ;
81
82
        return $qb;
83
    }
84
85
    /**
86
     * @return array<int, Session>
87
     *
88
     * @throws Exception
89
     */
90
    public function getPastSessionsOfUserInUrl(User $user, AccessUrl $url): array
91
    {
92
        $sessions = $this->getSubscribedSessionOfUserInUrl($user, $url);
93
94
        $filterPastSessions = function (Session $session) use ($user) {
95
            $now = new DateTime();
96
97
            // Check if the session has a duration
98
            if ($session->getDuration() > 0) {
99
                $daysLeft = $session->getDaysLeftByUser($user);
100
101
                return $daysLeft < 0;
102
            }
103
104
            // Get the appropriate end date based on whether the user is a coach
105
            $sessionEndDate = $session->hasCoach($user) && $session->getCoachAccessEndDate()
106
                ? $session->getCoachAccessEndDate()
107
                : $session->getAccessEndDate();
108
109
            // If there's no end date, the session is not considered past
110
            if (!$sessionEndDate) {
111
                return false;
112
            }
113
114
            // Check if the current date is after the end date
115
            return $now > $sessionEndDate;
116
        };
117
118
        return array_filter($sessions, $filterPastSessions);
119
    }
120
121
    /**
122
     * @return array<int, Session>
123
     *
124
     * @throws Exception
125
     */
126
    public function getCurrentSessionsOfUserInUrl(User $user, AccessUrl $url): array
127
    {
128
        $sessions = $this->getSubscribedSessionOfUserInUrl($user, $url);
129
130
        $filterCurrentSessions = function (Session $session) use ($user) {
131
            // Check if session has a duration
132
            if ($session->getDuration() > 0) {
133
                $daysLeft = $session->getDaysLeftByUser($user);
134
135
                return $daysLeft >= 0 && $daysLeft < $session->getDuration();
136
            }
137
138
            // Determine if the user is a coach
139
            $userIsCoach = $session->hasCoach($user);
140
141
            // Determine the start date based on whether the user is a coach
142
            $sessionStartDate = $userIsCoach && $session->getCoachAccessStartDate()
143
                ? $session->getCoachAccessStartDate()
144
                : $session->getAccessStartDate();
145
146
            // If there is no start date, consider the session current
147
            if (!$sessionStartDate) {
148
                return true;
149
            }
150
151
            // Get the current date and time
152
            $now = new DateTime();
153
154
            // Determine the end date based on whether the user is a coach
155
            $sessionEndDate = $userIsCoach && $session->getCoachAccessEndDate()
156
                ? $session->getCoachAccessEndDate()
157
                : $session->getAccessEndDate();
158
159
            // Check if the current date is within the start and end dates
160
            return $now >= $sessionStartDate && (!$sessionEndDate || $now <= $sessionEndDate);
161
        };
162
163
        return array_filter($sessions, $filterCurrentSessions);
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->getSubscribedSessionOfUserInUrl($user, $url);
174
175
        $filterUpcomingSessions = function (Session $session) use ($user) {
176
            $now = new DateTime();
177
178
            // Check if the session has a duration
179
            if ($session->getDuration() > 0) {
180
                $daysLeft = $session->getDaysLeftByUser($user);
181
182
                return $daysLeft >= $session->getDuration();
183
            }
184
185
            // Determine if the user is a coach
186
            $userIsCoach = $session->hasCoach($user);
187
188
            // Get the appropriate start date based on whether the user is a coach
189
            $sessionStartDate = $userIsCoach && $session->getCoachAccessStartDate()
190
                ? $session->getCoachAccessStartDate()
191
                : $session->getAccessStartDate();
192
193
            // If there's no start date, the session is not considered future
194
            if (!$sessionStartDate) {
195
                return false;
196
            }
197
198
            // Check if the current date is before the start date
199
            return $now < $sessionStartDate;
200
        };
201
202
        return array_filter($sessions, $filterUpcomingSessions);
203
    }
204
205
    public function addUserInCourse(int $relationType, User $user, Course $course, Session $session): void
206
    {
207
        if (!$user->isActive()) {
208
            throw new Exception('User not active');
209
        }
210
211
        if (!$session->hasCourse($course)) {
212
            $msg = sprintf('Course %s is not subscribed to the session %s', $course->getTitle(), $session->getTitle());
213
214
            throw new Exception($msg);
215
        }
216
217
        if (!\in_array($relationType, Session::getRelationTypeList(), true)) {
218
            throw new Exception(sprintf('Cannot handle relationType %s', $relationType));
219
        }
220
221
        switch ($relationType) {
222
            case Session::DRH:
223
                if ($user->hasRole('ROLE_RRHH')) {
224
                    $session->addUserInSession(Session::DRH, $user);
225
                }
226
227
                break;
228
229
            case Session::STUDENT:
230
                $session
231
                    ->addUserInSession(Session::STUDENT, $user)
232
                    ->addUserInCourse(Session::STUDENT, $user, $course)
233
                ;
234
235
                break;
236
237
            case Session::COURSE_COACH:
238
                if ($user->hasRole('ROLE_TEACHER')) {
239
                    $session
240
                        ->addUserInSession(Session::COURSE_COACH, $user)
241
                        ->addUserInCourse(
242
                            Session::COURSE_COACH,
243
                            $user,
244
                            $course
245
                        )
246
                    ;
247
                }
248
249
                break;
250
        }
251
    }
252
253
    /**
254
     * @return array<SessionRelCourse>
255
     */
256
    public function getSessionCoursesByStatusInUserSubscription(User $user, Session $session, int $relationType, ?AccessUrl $url = null): array
257
    {
258
        $qb = $this->getEntityManager()->createQueryBuilder();
259
260
        $qb->select('src')
261
            ->from(SessionRelCourse::class, 'src')
262
            ->innerJoin(
263
                SessionRelUser::class,
264
                'sru',
265
                Join::WITH,
266
                'src.session = sru.session'
267
            )
268
            ->innerJoin('src.session', 'session')
269
            ->where(
270
                $qb->expr()->eq('session', ':session')
271
            )
272
            ->andWhere(
273
                $qb->expr()->eq('sru.user', ':user')
274
            )
275
            ->andWhere(
276
                $qb->expr()->eq('sru.relationType', ':relation_type')
277
            )
278
        ;
279
280
        $parameters = [
281
            'session' => $session,
282
            'user' => $user,
283
            'relation_type' => $relationType,
284
        ];
285
286
        if ($url) {
287
            $qb->innerJoin('session.urls', 'urls')
288
                ->andWhere(
289
                    $qb->expr()->eq('urls.url', ':url')
290
                )
291
            ;
292
293
            $parameters['url'] = $url;
294
        }
295
296
        $qb->setParameters($parameters);
297
298
        return $qb->getQuery()->getResult();
299
    }
300
301
    /**
302
     * @return array<SessionRelCourse>
303
     */
304
    public function getSessionCoursesByStatusInCourseSubscription(User $user, Session $session, int $status, ?AccessUrl $url = null): array
305
    {
306
        $qb = $this->getEntityManager()->createQueryBuilder();
307
308
        $qb->select('src')
309
            ->from(SessionRelCourse::class, 'src')
310
            ->innerJoin(
311
                SessionRelCourseRelUser::class,
312
                'srcru',
313
                Join::WITH,
314
                'src.session = srcru.session AND src.course = srcru.course'
315
            )
316
            ->innerJoin('srcru.session', 'session')
317
            ->where(
318
                $qb->expr()->eq('session', ':session')
319
            )
320
            ->andWhere(
321
                $qb->expr()->eq('srcru.user', ':user')
322
            )
323
            ->andWhere(
324
                $qb->expr()->eq('srcru.status', ':status')
325
            )
326
        ;
327
328
        $parameters = [
329
            'session' => $session,
330
            'user' => $user,
331
            'status' => $status,
332
        ];
333
334
        if ($url) {
335
            $qb->innerJoin('session.urls', 'urls')
336
                ->andWhere(
337
                    $qb->expr()->eq('urls.url', ':url')
338
                )
339
            ;
340
341
            $parameters['url'] = $url;
342
        }
343
344
        $qb->setParameters($parameters);
345
346
        return $qb->getQuery()->getResult();
347
    }
348
349
    private function addSessionRelUserFilterByUrl(Session $session, AccessUrl $url): QueryBuilder
350
    {
351
        $qb = $this->getEntityManager()->createQueryBuilder();
352
        $qb
353
            ->select('sru')
354
            ->from(SessionRelUser::class, 'sru')
355
            ->innerJoin('sru.user', 'u')
356
            ->innerJoin('u.portals', 'p')
357
            ->andWhere('sru.session = :session AND p.url = :url')
358
            ->setParameters([
359
                'session' => $session,
360
                'url' => $url,
361
            ])
362
        ;
363
364
        return $qb;
365
    }
366
367
    public function getUserFollowedSessionsInAccessUrl(User $user, AccessUrl $url): QueryBuilder
368
    {
369
        $callback = fn (Session $session) => $session->getId();
370
371
        if ($user->isHRM()) {
372
            $idList = array_map($callback, $user->getDRHSessions());
373
        } elseif ($user->isTeacher() || COURSEMANAGER === $user->getStatus()) {
374
            $idListAsCoach = $user
375
                ->getSessionsByStatusInCourseSubscription(Session::COURSE_COACH)
376
                ->map($callback)
377
                ->getValues()
378
            ;
379
            $idListAsGeneralCoach = array_map($callback, $user->getSessionsAsGeneralCoach());
380
            $idList = array_merge($idListAsCoach, $idListAsGeneralCoach);
381
        } elseif ($user->isSessionAdmin()) {
382
            $idList = array_map($callback, $user->getSessionsAsAdmin());
383
        } else {
384
            $idList = array_map($callback, $user->getSessionsAsStudent());
385
        }
386
387
        $qb = $this->createQueryBuilder('s');
388
        $qb
389
            ->innerJoin('s.urls', 'u')
390
            ->where($qb->expr()->eq('u.url', $url->getId()))
391
            ->andWhere($qb->expr()->in('s.id', ':id_list'))
392
            ->setParameter('id_list', $idList)
393
        ;
394
395
        return $qb;
396
    }
397
398
    /**
399
     * @return array<int, Session>
400
     *
401
     * @throws Exception
402
     */
403
    public function getSubscribedSessionOfUserInUrl(
404
        User $user,
405
        AccessUrl $url,
406
        bool $ignoreVisibilityForAdmin = false,
407
    ): array {
408
        $sessions = $this->getSessionsByUser($user, $url)->getQuery()->getResult();
409
410
        $filterSessions = function (Session $session) use ($user, $ignoreVisibilityForAdmin) {
411
            $visibility = $session->setAccessVisibilityByUser($user);
412
413
            if (Session::VISIBLE !== $visibility) {
414
                $closedOrHiddenCourses = $session->getClosedOrHidenCourses();
415
416
                if ($closedOrHiddenCourses->count() === $session->getCourses()->count()) {
417
                    $visibility = Session::INVISIBLE;
418
                }
419
            }
420
421
            switch ($visibility) {
422
                case Session::READ_ONLY:
423
                case Session::VISIBLE:
424
                case Session::AVAILABLE:
425
                    break;
426
427
                case Session::INVISIBLE:
428
                    if (!$ignoreVisibilityForAdmin) {
429
                        return false;
430
                    }
431
            }
432
433
            return true;
434
        };
435
436
        return array_filter($sessions, $filterSessions);
437
    }
438
}
439