Passed
Push — master ( 3001d0...50d443 )
by Angel Fernando Quiroz
08:01 queued 14s
created

CourseRepository::getPersonalSessionCourses()   F

Complexity

Conditions 14
Paths 320

Size

Total Lines 194
Code Lines 114

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 114
nc 320
nop 4
dl 0
loc 194
rs 3.1466
c 0
b 0
f 0

How to fix   Long Method    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\Node;
8
9
use Chamilo\CoreBundle\Component\Utils\ChamiloApi;
10
use Chamilo\CoreBundle\Entity\AccessUrl;
11
use Chamilo\CoreBundle\Entity\Course;
12
use Chamilo\CoreBundle\Entity\CourseRelUser;
13
use Chamilo\CoreBundle\Entity\Session;
14
use Chamilo\CoreBundle\Entity\SessionRelCourse;
15
use Chamilo\CoreBundle\Entity\SessionRelCourseRelUser;
16
use Chamilo\CoreBundle\Entity\User;
17
use Chamilo\CoreBundle\Repository\ResourceRepository;
18
use Chamilo\CoreBundle\Repository\SessionRepository;
19
use Doctrine\Common\Collections\Criteria;
20
use Doctrine\ORM\AbstractQuery;
21
use Doctrine\ORM\Exception\NotSupported;
22
use Doctrine\ORM\Query\Expr\Join;
23
use Doctrine\ORM\QueryBuilder;
24
use Doctrine\Persistence\ManagerRegistry;
25
26
/**
27
 * Class CourseRepository.
28
 *
29
 * The functions inside this class should return an instance of QueryBuilder.
30
 */
31
class CourseRepository extends ResourceRepository
32
{
33
    public function __construct(ManagerRegistry $registry)
34
    {
35
        parent::__construct($registry, Course::class);
36
    }
37
38
    public function deleteCourse(Course $course): void
39
    {
40
        $em = $this->getEntityManager();
41
42
        // Deleting all nodes connected to the course:
43
        // $node = $course->getResourceNode();
44
        // $children = $node->getChildren();
45
        // /* var ResourceNode $child
46
        /*foreach ($children as $child) {
47
            var_dump($child->getId().'-'.$child->getTitle().'<br />');
48
            var_dump(get_class($child));
49
            $em->remove($child);
50
        }*/
51
52
        $em->remove($course);
53
        $em->flush();
54
        $em->clear();
55
    }
56
57
    public function findOneByCode(string $code): ?Course
58
    {
59
        return $this->findOneBy([
60
            'code' => $code,
61
        ]);
62
    }
63
64
    /**
65
     * Get course user relationship based in the course_rel_user table.
66
     *
67
     * @return array<int, CourseRelUser>
68
     */
69
    public function getCoursesByUser(User $user, AccessUrl $url): array
70
    {
71
        $qb = $this->getEntityManager()->createQueryBuilder();
72
73
        $qb
74
            ->select('courseRelUser')
75
            ->from(Course::class, 'c')
76
            ->innerJoin(CourseRelUser::class, 'courseRelUser')
77
            // ->innerJoin('c.users', 'courseRelUser')
78
            ->innerJoin('c.urls', 'accessUrlRelCourse')
79
            ->where('courseRelUser.user = :user')
80
            ->andWhere('accessUrlRelCourse.url = :url')
81
            ->setParameters([
82
                'user' => $user,
83
                'url' => $url,
84
            ])
85
        ;
86
87
        $query = $qb->getQuery();
88
89
        return $query->getResult();
90
    }
91
92
    /**
93
     * Get info from courses where the user has the given role.
94
     *
95
     * @return Course[]
96
     */
97
    public function getCoursesInfoByUser(User $user, AccessUrl $url, int $status, string $keyword = ''): array
98
    {
99
        $qb = $this->getEntityManager()->createQueryBuilder();
100
101
        $qb->select('DISTINCT c.id, c.title, c.code')
102
            ->from(Course::class, 'c')
103
            ->innerJoin(CourseRelUser::class, 'courseRelUser')
104
            ->innerJoin('c.urls', 'accessUrlRelCourse')
105
            ->where('accessUrlRelCourse.url = :url')
106
            ->andWhere('courseRelUser.user = :user')
107
            ->andWhere('courseRelUser.status = :status')
108
            ->setParameters([
109
                'user' => $user,
110
                'url' => $url,
111
                'status' => $status,
112
            ])
113
        ;
114
115
        if (!empty($keyword)) {
116
            $qb->andWhere($qb->expr()->orX(
117
                $qb->expr()->like('c.title', ':keyword'),
118
                $qb->expr()->like('c.code', ':keyword')
119
            ))
120
                ->setParameter('keyword', '%'.$keyword.'%')
121
            ;
122
        }
123
124
        $query = $qb->getQuery();
125
126
        return $query->getArrayResult();
127
    }
128
129
    /**
130
     * Get all users that are registered in the course. No matter the status.
131
     *
132
     * @return QueryBuilder
133
     */
134
    public function getSubscribedUsers(Course $course)
135
    {
136
        // Course builder
137
        $queryBuilder = $this->createQueryBuilder('c');
138
139
        // Selecting user info.
140
        $queryBuilder->select('DISTINCT user');
141
142
        // Selecting courses for users.
143
        $queryBuilder->innerJoin('c.users', 'subscriptions');
144
        $queryBuilder->innerJoin(
145
            User::class,
146
            'user',
147
            Join::WITH,
148
            'subscriptions.user = user.id'
149
        );
150
151
        if (api_is_western_name_order()) {
152
            $queryBuilder->orderBy('user.firstname', Criteria::ASC);
153
        } else {
154
            $queryBuilder->orderBy('user.lastname', Criteria::ASC);
155
        }
156
157
        $wherePart = $queryBuilder->expr()->andx();
158
159
        // Get only users subscribed to this course
160
        $wherePart->add($queryBuilder->expr()->eq('c.id', $course->getId()));
161
162
        // $wherePart->add($queryBuilder->expr()->eq('c.status', $status));
163
164
        $queryBuilder->where($wherePart);
165
166
        return $queryBuilder;
167
    }
168
169
    /**
170
     * Gets students subscribed in the course.
171
     *
172
     * @return QueryBuilder
173
     */
174
    public function getSubscribedStudents(Course $course)
175
    {
176
        return $this->getSubscribedUsersByStatus($course, STUDENT);
177
    }
178
179
    /**
180
     * Gets the students subscribed in the course.
181
     *
182
     * @return QueryBuilder
183
     */
184
    public function getSubscribedCoaches(Course $course)
185
    {
186
        return $this->getSubscribedUsers($course);
187
    }
188
189
    /**
190
     * Gets the teachers subscribed in the course.
191
     *
192
     * @return QueryBuilder
193
     */
194
    public function getSubscribedTeachers(Course $course)
195
    {
196
        return $this->getSubscribedUsersByStatus($course, ChamiloApi::COURSE_MANAGER);
197
    }
198
199
    /**
200
     * @param int $status use legacy chamilo constants COURSEMANAGER|STUDENT
201
     *
202
     * @return QueryBuilder
203
     */
204
    public function getSubscribedUsersByStatus(Course $course, int $status)
205
    {
206
        $queryBuilder = $this->getSubscribedUsers($course);
207
        $queryBuilder
208
            ->andWhere(
209
                $queryBuilder->expr()->eq('subscriptions.status', $status)
210
            )
211
        ;
212
213
        return $queryBuilder;
214
    }
215
216
    public function courseCodeExists(string $code): bool
217
    {
218
        $qb = $this->createQueryBuilder('c')
219
            ->select('count(c.id)')
220
            ->where('c.code = :code OR c.visualCode = :code')
221
            ->setParameter('code', $code)
222
            ->getQuery()
223
        ;
224
225
        return (int) $qb->getSingleScalarResult() > 0;
226
    }
227
228
    public function findCourseAsArray($id)
229
    {
230
        $qb = $this->createQueryBuilder('c')
231
            ->select('c.id, c.code, c.title, c.visualCode, c.courseLanguage, c.departmentUrl, c.departmentName')
232
            ->where('c.id = :id')
233
            ->setParameter('id', $id)
234
        ;
235
236
        $query = $qb->getQuery();
237
238
        return $query->getOneOrNullResult(AbstractQuery::HYDRATE_ARRAY);
239
    }
240
241
    public function getPersonalSessionCourses(
242
        User $user,
243
        AccessUrl $url,
244
        bool $isAllowedToCreateCourse,
245
        ?int $sessionLimit = null,
246
    ): array {
247
        $em = $this->getEntityManager();
248
249
        /** @var SessionRepository $sessionRepo */
250
        $sessionRepo = $em->getRepository(Session::class);
251
        $sessionCourseUserRepo = $em->getRepository(SessionRelCourseRelUser::class);
252
253
        $qb = $em->createQueryBuilder();
254
255
        $courseListSqlResult = $qb
256
            ->select('c.id AS cid')
257
            ->from(CourseRelUser::class, 'cru')
258
            ->leftJoin('cru.course', 'c')
259
            ->leftJoin('c.urls', 'urc')
260
            ->where($qb->expr()->eq('cru.user', ':user'))
261
            ->andWhere($qb->expr()->neq('cru.relationType', ':relationType'))
262
            ->andWhere($qb->expr()->eq('urc.url', ':url'))
263
            ->setParameters([
264
                'user' => $user->getId(),
265
                'relationType' => COURSE_RELATION_TYPE_RRHH,
266
                'url' => $url->getId(),
267
            ])
268
            ->getQuery()
269
            ->getResult()
270
        ;
271
272
        $personalCourseList = $courseListSqlResult;
273
274
        $sessionListFromCourseCoach = [];
275
        // Getting sessions that are related to a coach in the session_rel_course_rel_user table
276
        if ($isAllowedToCreateCourse) {
277
            $sessionListFromCourseCoach = array_map(
278
                fn(SessionRelCourseRelUser $srcru) => $srcru->getSession()->getId(),
279
                $sessionCourseUserRepo->findBy(['user' => $user->getId(), 'status' => Session::COURSE_COACH])
280
            );
281
        }
282
283
        // Get the list of sessions where the user is subscribed
284
        // This is divided into two different queries
285
        /** @var array<int, Session> $sessions */
286
        $sessions = [];
287
288
        $qb = $sessionRepo->createQueryBuilder('s');
289
        $qbParams = [
290
            'user' => $user->getId(),
291
            'relationType' => Session::STUDENT,
292
        ];
293
294
        $qb
295
            ->innerJoin('s.users', 'su')
296
            ->where(
297
                $qb->expr()->andX(
298
                    $qb->expr()->eq('su.user', ':user'),
299
                    $qb->expr()->neq('su.relationType', ':relationType')
300
                )
301
            )
302
        ;
303
304
        if ($sessionListFromCourseCoach) {
305
            $qb->orWhere($qb->expr()->in('s.id', ':sessionListFromCourseCoach'));
306
307
            $qbParams['coachCourseConditions'] = $sessionListFromCourseCoach;
308
        }
309
310
        $result = $qb
311
            ->orderBy('s.accessStartDate')
312
            ->addOrderBy('s.accessEndDate')
313
            ->addOrderBy('s.title')
314
            ->setMaxResults($sessionLimit)
315
            ->setParameters($qbParams)
316
            ->getQuery()
317
            ->getResult()
318
        ;
319
320
        /** @var Session $row */
321
        foreach ($result as $row) {
322
            $row->setAccessVisibilityByUser($user);
323
324
            $sessions[$row->getId()] = $row;
325
        }
326
327
        $qb = $sessionRepo->createQueryBuilder('s');
328
        $qbParams = [
329
            'user' => $user->getId(),
330
            'relationType' => Session::GENERAL_COACH,
331
        ];
332
333
        $qb
334
            ->innerJoin('s.users', 'sru')
335
            ->where(
336
                $qb->expr()->andX(
337
                    $qb->expr()->eq('sru.user', ':user'),
338
                    $qb->expr()->neq('sru.relationType', ':relationType')
339
                )
340
            )
341
        ;
342
343
        if ($sessionListFromCourseCoach) {
344
            $qb->orWhere($qb->expr()->in('s.id', ':sessionListFromCourseCoach'));
345
346
            $qbParams['coachCourseConditions'] = $sessionListFromCourseCoach;
347
        }
348
349
        $result = $qb
350
            ->orderBy('s.accessStartDate')
351
            ->addOrderBy('s.accessEndDate')
352
            ->addOrderBy('s.title')
353
            ->setParameters($qbParams)
354
            ->getQuery()
355
            ->getResult()
356
        ;
357
358
        /** @var Session $row */
359
        foreach ($result as $row) {
360
            $row->setAccessVisibilityByUser($user);
361
362
            $sessions[$row->getId()] = $row;
363
        }
364
365
        if ($isAllowedToCreateCourse) {
366
            foreach ($sessions as $enreg) {
367
                if (Session::INVISIBLE == $enreg->getAccessVisibility()) {
368
                    continue;
369
                }
370
371
                $coursesAsGeneralCoach = $sessionRepo->getSessionCoursesByStatusInUserSubscription(
372
                    $user,
373
                    $enreg,
374
                    Session::GENERAL_COACH,
375
                    $url
376
                );
377
                $coursesAsCourseCoach = $sessionRepo->getSessionCoursesByStatusInCourseSubscription(
378
                    $user,
379
                    $enreg,
380
                    Session::COURSE_COACH,
381
                    $url
382
                );
383
384
                // This query is horribly slow when more than a few thousand
385
                // users and just a few sessions to which they are subscribed
386
                $coursesInSession = array_merge($coursesAsGeneralCoach, $coursesAsCourseCoach);
387
388
                /** @var SessionRelCourse $resultRow */
389
                foreach ($coursesInSession as $resultRow) {
390
                    $sid = $resultRow->getSession()->getId();
391
                    $cid = $resultRow->getCourse()->getId();
392
393
                    $personalCourseList["$sid - $cid"] = [
394
                        'cid' => $cid,
395
                        'sid' => $sid,
396
                    ];
397
                }
398
            }
399
        }
400
401
        foreach ($sessions as $enreg) {
402
            if (Session::INVISIBLE == $enreg->getAccessVisibility()) {
403
                continue;
404
            }
405
406
            // This query is very similar to the above query,
407
            // but it will check the session_rel_course_user table if there are courses registered to our user or not */
408
            $qb = $sessionCourseUserRepo->createQueryBuilder('scu');
409
410
            $result = $qb
411
                ->select('c.id as cid', 's.id AS sid')
412
                ->innerJoin('scu.course', 'c', Join::WITH, 'scu.session = :session')
413
                ->innerJoin('scu.session', 's')
414
                ->leftJoin('scu.user', 'u')
415
                ->where($qb->expr()->eq('scu.user', ':user'))
416
                ->orderBy('c.title')
417
                ->setParameters([
418
                    'session' => $enreg->getId(),
419
                    'user' => $user->getId(),
420
                ])
421
                ->getQuery()
422
                ->getResult()
423
            ;
424
425
            foreach ($result as $resultRow) {
426
                $key = $resultRow['sid'].' - '.$resultRow['cid'];
427
428
                if (!isset($personalCourseList[$key])) {
429
                    $personalCourseList[$key] = $resultRow;
430
                }
431
            }
432
        }
433
434
        return $personalCourseList;
435
    }
436
}
437