Passed
Push — translations ( 6cd971...bddd68 )
by Yannick
35:39 queued 27:44
created

CourseManager::get_courses_list()   F

Complexity

Conditions 21
Paths 10368

Size

Total Lines 116
Code Lines 72

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 21
eloc 72
nc 10368
nop 10
dl 0
loc 116
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

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:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
3
/* For licensing terms, see /license.txt*/
4
5
use Chamilo\CoreBundle\Entity\AccessUrlRelSession;
6
use Chamilo\CoreBundle\Entity\Course;
7
use Chamilo\CoreBundle\Entity\CourseRelUser;
8
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
9
use Chamilo\CoreBundle\Entity\SequenceResource;
10
use Chamilo\CoreBundle\Entity\Session as SessionEntity;
11
use Chamilo\CoreBundle\Entity\User;
12
use Chamilo\CoreBundle\Framework\Container;
13
use Chamilo\CoreBundle\Repository\SequenceResourceRepository;
14
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
15
use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
16
use Chamilo\CourseBundle\Entity\CGroup;
17
use ChamiloSession as Session;
18
use Doctrine\Common\Collections\Criteria;
19
use Chamilo\CoreBundle\Component\Utils\ActionIcon;
20
use Chamilo\CoreBundle\Component\Utils\ObjectIcon;
21
22
/**
23
 * Class CourseManager.
24
 *
25
 * This is the course library for Chamilo.
26
 *
27
 * All main course functions should be placed here.
28
 *
29
 * There are probably some places left with the wrong code.
30
 */
31
class CourseManager
32
{
33
    public const MAX_COURSE_LENGTH_CODE = 40;
34
    /** This constant is used to show separate user names in the course
35
     * list (userportal), footer, etc */
36
    public const USER_SEPARATOR = ' |';
37
38
    /**
39
     * Creates a course.
40
     *
41
     * @param array $params      Columns in the main.course table.
42
     * @param int   $authorId    Optional.
43
     * @param int   $accessUrlId Optional.
44
     *
45
     * @return Course|null
46
     */
47
    public static function create_course($params, $authorId = 0, $accessUrlId = 0)
48
    {
49
        // Check portal limits
50
        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : api_get_current_access_url_id();
51
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
52
53
        if (empty($params['title'])) {
54
            return false;
55
        }
56
57
        if (empty($params['wanted_code'])) {
58
            $params['wanted_code'] = $params['title'];
59
            // Check whether the requested course code has already been occupied.
60
            $substring = api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE);
61
            if (false === $substring || empty($substring)) {
62
                return false;
63
            } else {
64
                $params['wanted_code'] = self::generate_course_code($substring);
65
            }
66
        }
67
68
        // Create the course keys
69
        $keys = AddCourse::define_course_keys($params['wanted_code']);
70
        $params['exemplary_content'] = $params['exemplary_content'] ?? false;
71
72
        if (count($keys)) {
73
            $params['code'] = $keys['currentCourseCode'];
74
            $params['visual_code'] = $keys['currentCourseId'];
75
            $params['directory'] = $keys['currentCourseRepository'];
76
            $courseInfo = api_get_course_info($params['code']);
77
            if (empty($courseInfo)) {
78
                $course = AddCourse::register_course($params);
79
                if (null !== $course) {
80
                    self::fillCourse($course, $params, $authorId);
81
82
                    return $course;
83
                }
84
            }
85
        }
86
87
        return null;
88
    }
89
90
    /**
91
     * Returns all the information of a given course code.
92
     *
93
     * @param string $course_code , the course code
94
     *
95
     * @return array with all the fields of the course table
96
     *
97
     * @deprecated Use api_get_course_info() instead
98
     *
99
     * @author Patrick Cool <[email protected]>, Ghent University
100
     * @assert ('') === false
101
     */
102
    public static function get_course_information($course_code)
103
    {
104
        return Database::fetch_array(
105
            Database::query(
106
                "SELECT *, id as real_id FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
107
                WHERE code = '".Database::escape_string($course_code)."'"
108
            ),
109
            'ASSOC'
110
        );
111
    }
112
113
    /**
114
     * Returns a list of courses. Should work with quickform syntax.
115
     *
116
     * @param int    $from               Offset (from the 7th = '6'). Optional.
117
     * @param int    $howmany            Number of results we want. Optional.
118
     * @param string $orderby            The column we want to order it by. Optional, defaults to first column.
119
     * @param string $orderdirection     The direction of the order (ASC or DESC). Optional, defaults to ASC.
120
     * @param int    $visibility         the visibility of the course, or all by default
121
     * @param string $startwith          If defined, only return results for which the course *title* begins with this
122
     *                                   string
123
     * @param string $urlId              The Access URL ID, if using multiple URLs
124
     * @param bool   $alsoSearchCode     An extension option to indicate that we also want to search for course codes
125
     *                                   (not *only* titles)
126
     * @param array  $conditionsLike
127
     * @param array  $onlyThisCourseList
128
     *
129
     * @return array
130
     */
131
    public static function get_courses_list(
132
        $from = 0,
133
        $howmany = 0,
134
        $orderby = 'title',
135
        $orderdirection = 'ASC',
136
        $visibility = -1,
137
        $startwith = '',
138
        $urlId = null,
139
        $alsoSearchCode = false,
140
        $conditionsLike = [],
141
        $onlyThisCourseList = []
142
    ) {
143
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
144
        $sql = "SELECT course.*, course.id as real_id
145
                FROM $courseTable course  ";
146
147
        if (!empty($urlId)) {
148
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
149
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
150
        }
151
152
        $visibility = (int) $visibility;
153
154
        if (!empty($startwith)) {
155
            $sql .= "WHERE (title LIKE '".Database::escape_string($startwith)."%' ";
156
            if ($alsoSearchCode) {
157
                $sql .= "OR code LIKE '".Database::escape_string($startwith)."%' ";
158
            }
159
            $sql .= ') ';
160
            if (-1 !== $visibility) {
161
                $sql .= " AND visibility = $visibility ";
162
            }
163
        } else {
164
            $sql .= 'WHERE 1 ';
165
            if (-1 !== $visibility) {
166
                $sql .= " AND visibility = $visibility ";
167
            }
168
        }
169
170
        if (!empty($urlId)) {
171
            $urlId = (int) $urlId;
172
            $sql .= " AND access_url_id = $urlId";
173
        }
174
175
        if (!empty($onlyThisCourseList)) {
176
            $onlyThisCourseList = array_map('intval', $onlyThisCourseList);
177
            $onlyThisCourseList = implode("','", $onlyThisCourseList);
178
            $sql .= " AND course.id IN ('$onlyThisCourseList') ";
179
        }
180
181
        $allowedFields = [
182
            'title',
183
            'code',
184
        ];
185
186
        if (count($conditionsLike) > 0) {
187
            $sql .= ' AND ';
188
            $temp_conditions = [];
189
            foreach ($conditionsLike as $field => $value) {
190
                if (!in_array($field, $allowedFields)) {
191
                    continue;
192
                }
193
                $field = Database::escape_string($field);
194
                $value = Database::escape_string($value);
195
                $simple_like = false;
196
                if ($simple_like) {
197
                    $temp_conditions[] = $field." LIKE '$value%'";
198
                } else {
199
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
200
                }
201
            }
202
            $condition = ' AND ';
203
            if (!empty($temp_conditions)) {
204
                $sql .= implode(' '.$condition.' ', $temp_conditions);
205
            }
206
        }
207
208
        if (empty($orderby)) {
209
            $sql .= ' ORDER BY title ';
210
        } else {
211
            if (in_array($orderby, ['title'])) {
212
                $sql .= " ORDER BY `".Database::escape_string($orderby)."` ";
213
            } else {
214
                $sql .= ' ORDER BY title ';
215
            }
216
        }
217
218
        $orderdirection = strtoupper($orderdirection);
219
        if (!in_array($orderdirection, ['ASC', 'DESC'])) {
220
            $sql .= 'ASC';
221
        } else {
222
            $sql .= 'ASC' === $orderdirection ? 'ASC' : 'DESC';
223
        }
224
225
        $howmany = (int) $howmany;
226
        if (!empty($howmany)) {
227
            $sql .= ' LIMIT '.$howmany;
228
        } else {
229
            $sql .= ' LIMIT 1000000'; //virtually no limit
230
        }
231
        if (!empty($from)) {
232
            $from = intval($from);
233
            $sql .= ' OFFSET '.intval($from);
234
        } else {
235
            $sql .= ' OFFSET 0';
236
        }
237
238
        $data = [];
239
        $res = Database::query($sql);
240
        if (Database::num_rows($res) > 0) {
241
            while ($row = Database::fetch_array($res, 'ASSOC')) {
242
                $data[] = $row;
243
            }
244
        }
245
246
        return $data;
247
    }
248
249
    /**
250
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
251
     *
252
     * @param int $userId
253
     * @param int $courseId
254
     *
255
     * @return int|bool the status of the user in that course (or false if the user is not in that course)
256
     */
257
    public static function getUserInCourseStatus($userId, $courseId)
258
    {
259
        $courseId = (int) $courseId;
260
        $userId = (int) $userId;
261
        if (empty($courseId)) {
262
            return false;
263
        }
264
265
        $result = Database::fetch_array(
266
            Database::query(
267
                "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
268
                WHERE
269
                    c_id  = $courseId AND
270
                    user_id = $userId"
271
            )
272
        );
273
274
        if (empty($result['status'])) {
275
            return false;
276
        }
277
278
        return $result['status'];
279
    }
280
281
    /**
282
     * @param int $userId
283
     * @param int $courseId
284
     *
285
     * @return mixed
286
     */
287
    public static function getUserCourseInfo($userId, $courseId)
288
    {
289
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
290
                WHERE
291
                    c_id  = ".intval($courseId)." AND
292
                    user_id = ".intval($userId);
293
294
        return Database::fetch_array(Database::query($sql));
295
    }
296
297
    /**
298
     * @param int  $userId
299
     * @param int  $courseId
300
     * @param bool $isTutor
301
     *
302
     * @return bool
303
     */
304
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
305
    {
306
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
307
308
        $courseId = (int) $courseId;
309
        $isTutor = (int) $isTutor;
310
311
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
312
			    WHERE
313
				    user_id = ".$userId." AND
314
				    c_id = ".$courseId;
315
316
        $result = Database::query($sql);
317
318
        if (Database::affected_rows($result) > 0) {
319
            return true;
320
        }
321
322
        return false;
323
    }
324
325
    /**
326
     * @param int $userId
327
     * @param int $courseId
328
     *
329
     * @return mixed
330
     */
331
    public static function get_tutor_in_course_status($userId, $courseId)
332
    {
333
        $userId = intval($userId);
334
        $courseId = intval($courseId);
335
        $result = Database::fetch_array(
336
            Database::query(
337
                "SELECT is_tutor
338
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
339
                WHERE
340
                    c_id = $courseId AND
341
                    user_id = $userId"
342
            )
343
        );
344
345
        return $result['is_tutor'];
346
    }
347
348
    /**
349
     * Unsubscribe one or more users from a course.
350
     *
351
     * @param   mixed   user_id or an array with user ids
352
     * @param   string  course code
353
     * @param   int     session id
354
     *
355
     * @return bool
356
     *
357
     * @assert ('', '') === false
358
     */
359
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
360
    {
361
        if (empty($user_id)) {
362
            return false;
363
        }
364
        if (!is_array($user_id)) {
365
            $user_id = [$user_id];
366
        }
367
368
        if (0 == count($user_id)) {
369
            return false;
370
        }
371
372
        if (!empty($session_id)) {
373
            $session_id = (int) $session_id;
374
        } else {
375
            $session_id = api_get_session_id();
376
        }
377
378
        if (empty($course_code)) {
379
            return false;
380
        }
381
382
        $userList = [];
383
        // Cleaning the $user_id variable
384
        if (is_array($user_id)) {
385
            $new_user_id_list = [];
386
            foreach ($user_id as $my_user_id) {
387
                $new_user_id_list[] = (int) $my_user_id;
388
            }
389
            $new_user_id_list = array_filter($new_user_id_list);
390
            $userList = $new_user_id_list;
391
            $user_ids = implode(',', $new_user_id_list);
392
        } else {
393
            $user_ids = (int) $user_id;
394
            $userList[] = $user_id;
395
        }
396
397
        $course_info = api_get_course_info($course_code);
398
        $course_id = $course_info['real_id'];
399
400
        // Unsubscribe user from all groups in the course.
401
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_USER)."
402
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
403
        Database::query($sql);
404
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
405
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
406
        Database::query($sql);
407
408
        // Erase user student publications (works) in the course - by André Boivin
409
        // @todo this should be handled by doctrine.
410
        /*if (!empty($userList)) {
411
            foreach ($userList as $userId) {
412
                // Getting all work from user
413
                $workList = getWorkPerUser($userId);
414
                if (!empty($workList)) {
415
                    foreach ($workList as $work) {
416
                        $work = $work['work'];
417
                        // Getting user results
418
                        if (!empty($work->user_results)) {
419
                            foreach ($work->user_results as $workSent) {
420
                                deleteWorkItem($workSent['id'], $course_info);
421
                            }
422
                        }
423
                    }
424
                }
425
            }
426
        }*/
427
428
        // Unsubscribe user from all blogs in the course.
429
        /*$sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_REL_USER)."
430
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
431
        Database::query($sql);
432
433
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER)."
434
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
435
        Database::query($sql);*/
436
437
        // Deleting users in forum_notification and mailqueue course tables
438
        $sql = "DELETE FROM  ".Database::get_course_table(TABLE_FORUM_NOTIFICATION)."
439
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
440
        Database::query($sql);
441
442
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_FORUM_MAIL_QUEUE)."
443
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
444
        Database::query($sql);
445
446
        // Unsubscribe user from the course.
447
        if (!empty($session_id)) {
448
            foreach ($userList as $uid) {
449
                SessionManager::unSubscribeUserFromCourseSession($uid, $course_id, $session_id);
450
451
                // check if a user is register in the session with other course
452
                $sql = "SELECT user_id FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
453
                        WHERE session_id = $session_id AND user_id = $uid";
454
                $rs = Database::query($sql);
455
456
                if (0 == Database::num_rows($rs)) {
457
                    SessionManager::unsubscribe_user_from_session($uid, $session_id);
458
                }
459
            }
460
461
            Event::addEvent(
462
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
463
                LOG_COURSE_CODE,
464
                $course_code,
465
                api_get_utc_datetime(),
466
                $user_id,
467
                $course_id,
468
                $session_id
469
            );
470
        } else {
471
            $sql = "DELETE FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
472
                    WHERE
473
                        user_id IN ($user_ids) AND
474
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
475
                        c_id = $course_id";
476
            Database::query($sql);
477
478
            // add event to system log
479
            $user_id = api_get_user_id();
480
481
            Event::addEvent(
482
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
483
                LOG_COURSE_CODE,
484
                $course_code,
485
                api_get_utc_datetime(),
486
                $user_id,
487
                $course_id
488
            );
489
490
            foreach ($userList as $userId) {
491
                $userInfo = api_get_user_info($userId);
492
                Event::addEvent(
493
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
494
                    LOG_USER_OBJECT,
495
                    $userInfo,
496
                    api_get_utc_datetime(),
497
                    $user_id,
498
                    $course_id
499
                );
500
            }
501
        }
502
        if ('true' === api_get_setting('session.catalog_course_subscription_in_user_s_session')) {
503
            // Also unlink the course from the users' currently accessible sessions
504
            /** @var Course $course */
505
            $course = Container::getCourseRepository()->findOneBy([
506
                'code' => $course_code,
507
            ]);
508
            if (is_null($course)) {
509
                return false;
510
            }
511
            /** @var Chamilo\CoreBundle\Entity\User $user */
512
            foreach (UserManager::getRepository()->matching(
513
                Criteria::create()->where(Criteria::expr()->in('id', $userList))
514
            ) as $user) {
515
                foreach ($user->getCurrentlyAccessibleSessions() as $session) {
516
                    $session->removeCourse($course);
517
                    // unsubscribe user from course within this session
518
                    SessionManager::unSubscribeUserFromCourseSession($user->getId(), $course->getId(), $session->getId());
519
                }
520
            }
521
            try {
522
                Database::getManager()->flush();
523
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
524
                Display::addFlash(
525
                    Display::return_message(
526
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
527
                        'warning'
528
                    )
529
                );
530
531
                return false;
532
            }
533
        }
534
535
        return true;
536
    }
537
538
    /**
539
     * @param string $courseCode
540
     * @param int    $status
541
     *
542
     * @return bool
543
     */
544
    public static function autoSubscribeToCourse($courseCode, $status = STUDENT)
545
    {
546
        if (api_is_anonymous()) {
547
            return false;
548
        }
549
550
        $course = Container::getCourseRepository()->findOneBy(['code' => $courseCode]);
551
552
        if (null === $course) {
553
            return false;
554
        }
555
556
        $visibility = (int) $course->getVisibility();
557
558
        if (in_array($visibility, [
559
                Course::CLOSED,
560
                //Course::REGISTERED,
561
                Course::HIDDEN,
562
        ])) {
563
            Display::addFlash(
564
                Display::return_message(
565
                    get_lang('SubscribingNotAllowed'),
566
                    'warning'
567
        )
568
            );
569
570
            return false;
571
        }
572
573
        // Private course can allow auto subscription
574
        if (Course::REGISTERED === $visibility && false === $course->getSubscribe()) {
575
            Display::addFlash(
576
                Display::return_message(
577
                    get_lang('Subscribing not allowed'),
578
                    'warning'
579
                )
580
            );
581
582
            return false;
583
        }
584
585
        $userId = api_get_user_id();
586
587
        if ('true' === api_get_setting('session.catalog_course_subscription_in_user_s_session')) {
588
            $user = api_get_user_entity($userId);
589
            $sessions = $user->getCurrentlyAccessibleSessions();
590
            if (empty($sessions)) {
591
                // user has no accessible session
592
                if ($user->getSessionsAsStudent()) {
593
                    // user has ancient or future student session(s) but not available now
594
                    Display::addFlash(
595
                        Display::return_message(
596
                            get_lang('CanNotSubscribeToCourseUserSessionExpired'),
597
                            'warning'
598
                        )
599
                    );
600
601
                    return false;
602
                }
603
                // user has no session at all, create one starting now
604
                $numberOfDays = (int) api_get_setting('session.user_s_session_duration');
605
                try {
606
                    $duration = new DateInterval(sprintf('P%dD', $numberOfDays));
607
                } catch (Exception $exception) {
608
                    Display::addFlash(
609
                        Display::return_message(
610
                            get_lang('WrongNumberOfDays').': '.$numberOfDays.': '.$exception->getMessage(),
611
                            'warning'
612
                        )
613
                    );
614
615
                    return false;
616
                }
617
                $endDate = new DateTime();
618
                $endDate->add($duration);
619
                $session = new SessionEntity();
620
                $session->setTitle(
621
                    sprintf(get_lang('FirstnameLastnameCourses'), $user->getFirstname(), $user->getLastname())
622
                );
623
                $session->setAccessEndDate($endDate);
624
                $session->setCoachAccessEndDate($endDate);
625
                $session->setDisplayEndDate($endDate);
626
                $session->setSendSubscriptionNotification(false);
627
                $adminId = (int) api_get_setting('session.session_automatic_creation_user_id');
628
                $session->addSessionAdmin(api_get_user_entity($adminId));
629
                $session->addUserInSession(0, $user);
630
                Database::getManager()->persist($session);
631
                try {
632
                    Database::getManager()->flush();
633
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
634
                    Display::addFlash(
635
                        Display::return_message(
636
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
637
                            'warning'
638
                        )
639
                    );
640
641
                    return false;
642
                }
643
                $accessUrlRelSession = new AccessUrlRelSession();
644
                $accessUrlRelSession->setUrl(api_get_url_entity());
645
                $accessUrlRelSession->setSession($session);
646
                Database::getManager()->persist($accessUrlRelSession);
647
                try {
648
                    Database::getManager()->flush();
649
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
650
                    Display::addFlash(
651
                        Display::return_message(
652
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
653
                            'warning'
654
                        )
655
                    );
656
657
                    return false;
658
                }
659
            } else {
660
                // user has at least one accessible session, let's use it
661
                $session = $sessions[0];
662
            }
663
            // add chosen course to the user session
664
            $session->addCourse($course);
665
            Database::getManager()->persist($session);
666
            try {
667
                Database::getManager()->flush();
668
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
669
                Display::addFlash(
670
                    Display::return_message(
671
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
672
                        'warning'
673
                    )
674
                );
675
676
                return false;
677
            }
678
            // subscribe user to course within this session
679
            SessionManager::subscribe_users_to_session_course([$userId], $session->getId(), $course->getCode());
680
681
            return true;
682
        }
683
684
        return self::subscribeUser($userId, $course->getId(), $status, 0);
685
    }
686
687
    /**
688
     * Subscribe a user to a course. No checks are performed here to see if
689
     * course subscription is allowed.
690
     *
691
     * @param int  $userId
692
     * @param int  $courseId
693
     * @param int  $status                 (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
694
     * @param int  $sessionId
695
     * @param int  $userCourseCategoryId
696
     * @param bool $checkTeacherPermission
697
     *
698
     * @return bool True on success, false on failure
699
     *
700
     * @assert ('', '') === false
701
     */
702
    public static function subscribeUser(
703
        $userId,
704
        $courseId,
705
        $status = STUDENT,
706
        $sessionId = 0,
707
        $userCourseCategoryId = 0,
708
        $checkTeacherPermission = true
709
    ) {
710
        $userId = (int) $userId;
711
        $status = (int) $status;
712
713
        if (empty($userId) || empty($courseId)) {
714
            return false;
715
        }
716
717
        $course = api_get_course_entity($courseId);
718
719
        if (null === $course) {
720
            Display::addFlash(Display::return_message(get_lang('This course doesn\'t exist'), 'warning'));
721
722
            return false;
723
        }
724
725
        $user = api_get_user_entity($userId);
726
727
        if (null === $user) {
728
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
729
730
            return false;
731
        }
732
733
        $courseCode = $course->getCode();
734
        $userCourseCategoryId = (int) $userCourseCategoryId;
735
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
736
        $status = STUDENT === $status || COURSEMANAGER === $status ? $status : STUDENT;
737
738
        if (!empty($sessionId)) {
739
            SessionManager::subscribe_users_to_session_course(
740
                [$userId],
741
                $sessionId,
742
                $courseCode
743
            );
744
745
            return true;
746
        } else {
747
            // Check whether the user has not been already subscribed to the course.
748
            $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
749
                    WHERE
750
                        user_id = $userId AND
751
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
752
                        c_id = $courseId
753
                    ";
754
            if (Database::num_rows(Database::query($sql)) > 0) {
755
                Display::addFlash(Display::return_message(get_lang('Already registered in course'), 'warning'));
756
757
                return false;
758
            }
759
760
            if ($checkTeacherPermission && !api_is_course_admin()) {
761
                // Check in advance whether subscription is allowed or not for this course.
762
                if (SUBSCRIBE_NOT_ALLOWED === (int) $course->getSubscribe()) {
763
                    Display::addFlash(Display::return_message(get_lang('Subscription not allowed'), 'warning'));
764
765
                    return false;
766
                }
767
            }
768
769
            if (STUDENT === $status) {
770
                // Check if max students per course extra field is set
771
                $extraFieldValue = new ExtraFieldValue('course');
772
                $value = $extraFieldValue->get_values_by_handler_and_field_variable(
773
                    $courseId,
774
                    'max_subscribed_students'
775
                );
776
                if (!empty($value) && isset($value['value']) && '' !== $value['value']) {
777
                    $maxStudents = (int) $value['value'];
778
                    $count = self::get_user_list_from_course_code(
779
                        $courseCode,
780
                        0,
781
                        null,
782
                        null,
783
                        STUDENT,
784
                        true,
785
                        false
786
                    );
787
788
                    if ($count >= $maxStudents) {
789
                        Display::addFlash(
790
                            Display::return_message(
791
                                get_lang(
792
                                    'The maximum number of student has already been reached, it is not possible to subscribe more student.'
793
                                ),
794
                                'warning'
795
                            )
796
                        );
797
798
                        return false;
799
                    }
800
                }
801
            }
802
803
            $maxSort = api_max_sort_value(0, $userId) + 1;
804
805
            $insertId = self::insertUserInCourse(
806
                $user,
807
                $course,
808
                ['status' => $status, 'sort' => $maxSort, 'user_course_cat' => $userCourseCategoryId]
809
            );
810
811
            if ($insertId) {
812
                Display::addFlash(
813
                    Display::return_message(
814
                        sprintf(
815
                            get_lang('User %s has been registered to course %s'),
816
                            UserManager::formatUserFullName($user, true),
817
                            $course->getTitle()
818
                        )
819
                    )
820
                );
821
822
                $send = (int) api_get_course_setting('email_alert_to_teacher_on_new_user_in_course', $course);
823
824
                if (1 === $send) {
825
                    self::email_to_tutor(
826
                        $userId,
827
                        $courseId,
828
                        false
829
                    );
830
                } elseif (2 === $send) {
831
                    self::email_to_tutor(
832
                        $userId,
833
                        $courseId,
834
                        true
835
                    );
836
                }
837
838
                $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications', $course);
839
                if (1 === $subscribe) {
840
                    /*$forums = get_forums(0,  true, $sessionId);
841
                    foreach ($forums as $forum) {
842
                        set_notification('forum', $forum->getIid(), false, $userInfo, $courseInfo);
843
                    }*/
844
                }
845
846
                return true;
847
            }
848
849
            return false;
850
        }
851
    }
852
853
    /**
854
     * Get the course id based on the original id and field name in the
855
     * extra fields. Returns 0 if course was not found.
856
     *
857
     * @param string $original_course_id_value
858
     * @param string $original_course_id_name
859
     *
860
     * @return int Course id
861
     *
862
     * @assert ('', '') === false
863
     */
864
    public static function get_course_code_from_original_id(
865
        $original_course_id_value,
866
        $original_course_id_name
867
    ) {
868
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
869
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
870
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
871
        $original_course_id_value = Database::escape_string($original_course_id_value);
872
        $original_course_id_name = Database::escape_string($original_course_id_name);
873
874
        $sql = "SELECT item_id
875
                FROM $table_field cf
876
                INNER JOIN $t_cfv cfv
877
                ON cfv.field_id=cf.id
878
                WHERE
879
                    variable = '$original_course_id_name' AND
880
                    value = '$original_course_id_value' AND
881
                    cf.item_type = $extraFieldType
882
                ";
883
        $res = Database::query($sql);
884
        $row = Database::fetch_object($res);
885
        if ($row) {
886
            return $row->item_id;
887
        } else {
888
            return 0;
889
        }
890
    }
891
892
    /**
893
     * Gets the course code from the course id. Returns null if course id was not found.
894
     *
895
     * @param int $id Course id
896
     *
897
     * @return string Course code
898
     * @assert ('') === false
899
     */
900
    public static function get_course_code_from_course_id($id)
901
    {
902
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
903
        $id = intval($id);
904
        $sql = "SELECT code FROM $table WHERE id = $id ";
905
        $res = Database::query($sql);
906
        $row = Database::fetch_object($res);
907
        if ($row) {
908
            return $row->code;
909
        } else {
910
            return null;
911
        }
912
    }
913
914
    /**
915
     * Add the user $userId visibility to the course $courseCode in the catalogue.
916
     *
917
     * @author David Nos (https://github.com/dnos)
918
     *
919
     * @param int    $userId     the id of the user
920
     * @param string $courseCode the course code
921
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
922
     *
923
     * @return bool true if added succesfully, false otherwise
924
     */
925
    public static function addUserVisibilityToCourseInCatalogue(
926
        $userId,
927
        $courseCode,
928
        $visible = 1
929
    ) {
930
        $debug = false;
931
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
932
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
933
        $visible = (int) $visible;
934
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
935
            return false;
936
        }
937
938
        $courseCode = Database::escape_string($courseCode);
939
        $courseInfo = api_get_course_info($courseCode);
940
        $courseId = $courseInfo['real_id'];
941
942
        // Check in advance whether the user has already been registered on the platform.
943
        $sql = "SELECT status FROM ".$userTable." WHERE user_id = $userId ";
944
        if (0 == Database::num_rows(Database::query($sql))) {
945
            return false; // The user has not been registered to the platform.
946
        }
947
948
        // Check whether the user has already been registered to the course visibility in the catalogue.
949
        $sql = "SELECT * FROM $courseUserTable
950
                WHERE
951
                    user_id = $userId AND
952
                    visible = $visible AND
953
                    c_id = $courseId";
954
        if (Database::num_rows(Database::query($sql)) > 0) {
955
            return true; // The visibility of the user to the course in the catalogue does already exist.
956
        }
957
958
        // Register the user visibility to course in catalogue.
959
        $params = [
960
            'user_id' => $userId,
961
            'c_id' => $courseId,
962
            'visible' => $visible,
963
        ];
964
965
        return Database::insert($courseUserTable, $params);
966
    }
967
968
    /**
969
     * Remove the user $userId visibility to the course $courseCode in the catalogue.
970
     *
971
     * @author David Nos (https://github.com/dnos)
972
     *
973
     * @param int    $userId     the id of the user
974
     * @param string $courseCode the course code
975
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
976
     *
977
     * @return bool true if removed succesfully or register not found, false otherwise
978
     */
979
    public static function removeUserVisibilityToCourseInCatalogue(
980
        $userId,
981
        $courseCode,
982
        $visible = 1
983
    ) {
984
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
985
986
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
987
            return false;
988
        }
989
990
        $courseCode = Database::escape_string($courseCode);
991
        $courseInfo = api_get_course_info($courseCode);
992
        $courseId = $courseInfo['real_id'];
993
994
        // Check whether the user has already been registered to the course visibility in the catalogue.
995
        $sql = "SELECT * FROM $courseUserTable
996
                WHERE
997
                    user_id = $userId AND
998
                    visible = $visible AND
999
                    c_id = $courseId";
1000
        if (Database::num_rows(Database::query($sql)) > 0) {
1001
            $cond = [
1002
                'user_id = ? AND c_id = ? AND visible = ? ' => [
1003
                    $userId,
1004
                    $courseId,
1005
                    $visible,
1006
                ],
1007
            ];
1008
1009
            return Database::delete($courseUserTable, $cond);
1010
        } else {
1011
            return true; // Register does not exist
1012
        }
1013
    }
1014
1015
    /**
1016
     * @param string $code
1017
     *
1018
     * @return bool if there already are one or more courses
1019
     *              with the same code OR visual_code (visualcode), false otherwise
1020
     */
1021
    public static function course_code_exists($code)
1022
    {
1023
        $code = Database::escape_string($code);
1024
        $sql = "SELECT COUNT(*) as number
1025
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
1026
                WHERE code = '$code' OR visual_code = '$code'";
1027
        $result = Database::fetch_array(Database::query($sql));
1028
1029
        return $result['number'] > 0;
1030
    }
1031
1032
    /**
1033
     * @param int    $userId
1034
     * @param string $keyword
1035
     *
1036
     * @return array an array with the course info of all the courses (real and virtual)
1037
     *               of which the current user is course admin
1038
     */
1039
    public static function get_course_list_of_user_as_course_admin($userId, $keyword = ''): array
1040
    {
1041
        $user = api_get_user_entity($userId);
1042
1043
        if (null === $user) {
1044
            return [];
1045
        }
1046
1047
        $url = api_get_url_entity();
1048
        $repo = Container::getCourseRepository();
1049
1050
        return $repo->getCoursesInfoByUser($user, $url, COURSEMANAGER, $keyword);
1051
    }
1052
1053
    /**
1054
     * @param int   $userId
1055
     * @param array $courseInfo
1056
     *
1057
     * @return bool|null
1058
     */
1059
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
1060
    {
1061
        $userId = intval($userId);
1062
1063
        if (!api_is_drh()) {
1064
            return false;
1065
        }
1066
1067
        if (empty($courseInfo) || empty($userId)) {
1068
            return false;
1069
        }
1070
1071
        $courseId = intval($courseInfo['real_id']);
1072
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1073
1074
        $sql = "SELECT * FROM $table
1075
                WHERE
1076
                    user_id = $userId AND
1077
                    relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
1078
                    c_id = $courseId";
1079
1080
        $result = Database::fetch_array(Database::query($sql));
1081
1082
        if (!empty($result)) {
1083
            // The user has been registered in this course.
1084
            return true;
1085
        }
1086
    }
1087
1088
    /**
1089
     * Check if user is subscribed inside a course.
1090
     *
1091
     * @param int    $userId
1092
     * @param string $course_code  , if this parameter is null, it'll check for all courses
1093
     * @param bool   $in_a_session True for checking inside sessions too, by default is not checked
1094
     * @param int    $session_id
1095
     *
1096
     * @return bool $session_id true if the user is registered in the course, false otherwise
1097
     */
1098
    public static function is_user_subscribed_in_course(
1099
        $userId,
1100
        $course_code = null,
1101
        $in_a_session = false,
1102
        $session_id = 0
1103
    ) {
1104
        $userId = (int) $userId;
1105
        $session_id = (int) $session_id;
1106
1107
        if ('true' === api_get_setting('session.catalog_course_subscription_in_user_s_session')) {
1108
            // with this option activated, only check whether the course is in one of the users' sessions
1109
            $course = Container::getCourseRepository()->findOneBy([
1110
                'code' => $course_code,
1111
            ]);
1112
            if (is_null($course)) {
1113
                return false;
1114
            }
1115
1116
            $user = api_get_user_entity($userId);
1117
            if (is_null($user)) {
1118
                return false;
1119
            }
1120
            foreach ($user->getSessionsAsStudent() as $session) {
1121
                if ($session->hasCourse($course)) {
1122
                    return true;
1123
                }
1124
            }
1125
1126
            return false;
1127
        }
1128
1129
        if (empty($session_id)) {
1130
            $session_id = api_get_session_id();
1131
        }
1132
1133
        $condition_course = '';
1134
        if (isset($course_code)) {
1135
            $courseInfo = api_get_course_info($course_code);
1136
            if (empty($courseInfo)) {
1137
                return false;
1138
            }
1139
            $courseId = $courseInfo['real_id'];
1140
            $condition_course = " AND c_id = $courseId";
1141
        }
1142
1143
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1144
                WHERE
1145
                    user_id = $userId AND
1146
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1147
                    $condition_course ";
1148
1149
        $result = Database::fetch_array(Database::query($sql));
1150
1151
        if (!empty($result)) {
1152
            // The user has been registered in this course.
1153
            return true;
1154
        }
1155
1156
        if (!$in_a_session) {
1157
            // The user has not been registered in this course.
1158
            return false;
1159
        }
1160
1161
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1162
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1163
                WHERE user_id = $userId AND session_id = $session_id $condition_course";
1164
1165
        if (Database::num_rows(Database::query($sql)) > 0) {
1166
            return true;
1167
        }
1168
1169
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1170
                WHERE user_id = $userId AND session_id = $session_id AND status = ".SessionEntity::COURSE_COACH." $condition_course";
1171
1172
        if (Database::num_rows(Database::query($sql)) > 0) {
1173
            return true;
1174
        }
1175
1176
        $sql = "SELECT s.id FROM ".Database::get_main_table(TABLE_MAIN_SESSION)." s
1177
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_USER)." sru
1178
                ON (sru.session_id = s.id AND sru.relation_type = ".SessionEntity::GENERAL_COACH.")
1179
                WHERE sru.user_id = $userId AND s.id = $session_id";
1180
1181
        if (Database::num_rows(Database::query($sql)) > 0) {
1182
            return true;
1183
        }
1184
1185
        return false;
1186
    }
1187
1188
    /**
1189
     * Is the user a teacher in the given course?
1190
     *
1191
     * @param int $userId
1192
     * @param int $courseId
1193
     *
1194
     * @return bool if the user is a teacher in the course, false otherwise
1195
     */
1196
    public static function isCourseTeacher($userId, $courseId)
1197
    {
1198
        $userId = (int) $userId;
1199
        $courseId = (int) $courseId;
1200
1201
        if (empty($courseId) || empty($userId)) {
1202
            return false;
1203
        }
1204
1205
        $sql = "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1206
                WHERE c_id = $courseId AND user_id = $userId ";
1207
        $result = Database::query($sql);
1208
1209
        if (Database::num_rows($result) > 0) {
1210
            return 1 == Database::result($result, 0, 'status');
1211
        }
1212
1213
        return false;
1214
    }
1215
1216
    /**
1217
     * Get user info array of all users registered in a course, by course code.
1218
     * Wrapper: This method calls getUserListFromCourseId() in the background.
1219
     * @param string|null $courseCode Cours code is allowed to be null if we want all users
1220
     * @param int         $sessionId
1221
     * @param string      $limit
1222
     * @param string      $order_by the field to order the users by.
1223
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email',
1224
     *                                    'official_code' OR a part of a SQL statement that starts with ORDER BY ...
1225
     * @param int|null    $filter_by_status if using the session_id: 0 or 2 (student, coach),
1226
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1227
     * @param bool|null   $return_count
1228
     * @param bool        $add_reports
1229
     * @param bool        $resumed_report
1230
     * @param array       $extra_field
1231
     * @param array       $courseCodeList
1232
     * @param array       $userIdList
1233
     * @param bool        $filterByActive
1234
     * @param array       $sessionIdList
1235
     * @param string      $searchByKeyword
1236
     *
1237
     * @return array|int
1238
     * @throws Exception
1239
     */
1240
    public static function get_user_list_from_course_code(
1241
        $courseCode,
1242
        $sessionId = 0,
1243
        $limit = null,
1244
        $order_by = null,
1245
        $filter_by_status = null,
1246
        $return_count = null,
1247
        $add_reports = false,
1248
        $resumed_report = false,
1249
        $extra_field = [],
1250
        $courseCodeList = [],
1251
        $userIdList = [],
1252
        $filterByActive = null,
1253
        $sessionIdList = [],
1254
        $searchByKeyword = '',
1255
        $options = []
1256
    )
1257
    {
1258
        $courseId = api_get_course_int_id($courseCode);
1259
        return self::getUserListFromCourseId(
1260
            $courseId,
1261
            $sessionId,
1262
            $limit,
1263
            $order_by,
1264
            $filter_by_status,
1265
            $return_count,
1266
            $add_reports,
1267
            $resumed_report,
1268
            $extra_field,
1269
            $courseCodeList,
1270
            $userIdList,
1271
            $filterByActive,
1272
            $sessionIdList,
1273
            $searchByKeyword,
1274
            $options
1275
        );
1276
    }
1277
1278
    /**
1279
     * Return user info array of all users registered in a course (by course ID and session ID).
1280
     * This only returns the users that are registered in this actual course, not linked courses.
1281
     *
1282
     * @param ?int    $courseCode Course ID is allowed to be null if we want all users
1283
     * @param ?int    $sessionId
1284
     * @param ?string $limit
1285
     * @param ?string $order_by the field to order the users by.
1286
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email',
1287
     *                                    'official_code' OR a part of a SQL statement that starts with ORDER BY ...
1288
     * @param ?int    $filter_by_status if using the session_id: 0 or 2 (student, coach),
1289
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1290
     * @param ?bool   $return_count
1291
     * @param ?bool   $add_reports
1292
     * @param ?bool   $resumed_report
1293
     * @param ?array  $extra_field
1294
     * @param ?array  $courseCodeList
1295
     * @param ?array  $userIdList
1296
     * @param ?bool   $filterByActive
1297
     * @param ?array  $sessionIdList
1298
     * @param ?string $searchByKeyword
1299
     * @param ?array
1300
     *
1301
     * @return array|int
1302
     * @throws Exception
1303
     */
1304
    public static function getUserListFromCourseId(
1305
        ?int $courseId = null,
1306
        ?int $sessionId = 0,
1307
        ?string $limit = null,
1308
        ?string $order_by = null,
1309
        ?int $filter_by_status = null,
1310
        ?bool $return_count = null,
1311
        ?bool $add_reports = false,
1312
        ?bool $resumed_report = false,
1313
        ?array $extra_field = [],
1314
        ?array $courseIdsList = [],
1315
        ?array $userIdList = [],
1316
        ?bool $filterByActive = null,
1317
        ?array $sessionIdList = [],
1318
        ?string $searchByKeyword = '',
1319
        ?array $options = []
1320
    ) {
1321
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1322
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1323
1324
        $sessionId = (int) $sessionId;
1325
        $session = null;
1326
        if (!empty($sessionId)) {
1327
            $session = api_get_session_entity($sessionId);
1328
        }
1329
        $where = [];
1330
        if (empty($order_by)) {
1331
            $order_by = 'user.lastname, user.firstname';
1332
            if (api_is_western_name_order()) {
1333
                $order_by = 'user.firstname, user.lastname';
1334
            }
1335
        }
1336
1337
        // if the $order_by does not contain 'ORDER BY'
1338
        // we have to check if it is a valid field that can be sorted on
1339
        if (!strstr($order_by, 'ORDER BY')) {
1340
            if (!empty($order_by)) {
1341
                $order_by = "ORDER BY $order_by";
1342
            } else {
1343
                $order_by = '';
1344
            }
1345
        }
1346
1347
        $filter_by_status_condition = null;
1348
        $whereExtraField = '';
1349
        $injectExtraFields = ' , ';
1350
        $sqlInjectJoins = '';
1351
        if (!empty($options)) {
1352
            $extraFieldModel = new ExtraField('user');
1353
            $conditions = $extraFieldModel->parseConditions($options, 'user');
1354
            if (!empty($conditions)) {
1355
                $injectExtraFields = $conditions['inject_extra_fields'];
1356
1357
                if (!empty($injectExtraFields)) {
1358
                    $injectExtraFields = ', '.$injectExtraFields;
1359
                } else {
1360
                    $injectExtraFields = ' , ';
1361
                }
1362
                $sqlInjectJoins = $conditions['inject_joins'];
1363
                $whereExtraField = $conditions['where'];
1364
            }
1365
        }
1366
1367
        if (!empty($sessionId) || !empty($sessionIdList)) {
1368
            $sql = 'SELECT DISTINCT
1369
                        user.id as user_id,
1370
                        user.email,
1371
                        session_course_user.status as status_session,
1372
                        session_id,
1373
                        user.*,
1374
                        course.*,
1375
                        course.id AS c_id
1376
                         '.$injectExtraFields.'
1377
                        session.title as session_name
1378
                    ';
1379
            if ($return_count) {
1380
                $sql = ' SELECT COUNT(user.id) as count';
1381
            }
1382
1383
            $sessionCondition = " session_course_user.session_id = $sessionId";
1384
            if (!empty($sessionIdList)) {
1385
                $sessionIdListToString = implode("','", array_map('intval', $sessionIdList));
1386
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListToString') ";
1387
            }
1388
1389
            $courseCondition = " course.id IS NOT NULL ";
1390
            if (!empty($courseId)) {
1391
                $courseCondition = " course.id = $courseId";
1392
            }
1393
            if (!empty($courseCodeList)) {
1394
                $courseCodeListForSession = array_map(['Database', 'escape_string'], $courseCodeList);
1395
                $courseCodeListForSession = implode("','", $courseCodeListForSession);
1396
                $courseCondition = " course.code IN ('$courseCodeListForSession')  ";
1397
            }
1398
1399
            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
1400
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." as session_course_user
1401
                      ON
1402
                        user.id = session_course_user.user_id AND
1403
                        $sessionCondition
1404
                        INNER JOIN $course_table course
1405
                        ON session_course_user.c_id = course.id AND
1406
                        $courseCondition
1407
                        INNER JOIN $sessionTable session
1408
                        ON session_course_user.session_id = session.id
1409
                    $sqlInjectJoins
1410
                   ";
1411
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1412
            $where[] = ' user.active <> '.USER_SOFT_DELETED.' ';
1413
1414
            // 2 = coach
1415
            // 0 = student
1416
            if (isset($filter_by_status)) {
1417
                $filter_by_status = $filter_by_status;
1418
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1419
            }
1420
        } else {
1421
            if ($return_count) {
1422
                $sql = " SELECT COUNT(*) as count";
1423
            } else {
1424
                if (empty($courseCode)) {
1425
                    $sql = 'SELECT DISTINCT
1426
                                course.title,
1427
                                course.code,
1428
                                course.id AS c_id,
1429
                                course_rel_user.status as status_rel,
1430
                                user.id as user_id,
1431
                                user.email,
1432
                                course_rel_user.is_tutor
1433
                                '.$injectExtraFields.'
1434
                                user.*  ';
1435
                } else {
1436
                    $sql = 'SELECT DISTINCT
1437
                                course_rel_user.status as status_rel,
1438
                                user.id as user_id,
1439
                                user.email,
1440
                                course_rel_user.is_tutor
1441
                                '.$injectExtraFields.'
1442
                                user.*  ';
1443
                }
1444
            }
1445
1446
            $sql .= " FROM ".Database::get_main_table(TABLE_MAIN_USER)." as user
1447
                      LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." as course_rel_user
1448
                      ON
1449
                        user.id = course_rel_user.user_id AND
1450
                        course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1451
                       INNER JOIN $course_table course
1452
                       ON (course_rel_user.c_id = course.id)
1453
                       $sqlInjectJoins
1454
                       ";
1455
1456
            if (!empty($courseId)) {
1457
                $sql .= " AND course_rel_user.c_id = $courseId";
1458
            }
1459
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1460
1461
            if (isset($filter_by_status)) {
1462
                $filter_by_status = $filter_by_status;
1463
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1464
            }
1465
        }
1466
1467
        $multiple_access_url = api_get_multiple_access_url();
1468
        if ($multiple_access_url) {
1469
            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au
1470
                      ON (au.user_id = user.id) ';
1471
        }
1472
1473
        $extraFieldWasAdded = false;
1474
        if ($return_count && $resumed_report) {
1475
            foreach ($extra_field as $extraField) {
1476
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1477
                if (!empty($extraFieldInfo)) {
1478
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1479
                    $sql .= " LEFT JOIN $fieldValuesTable as ufv
1480
                            ON (
1481
                                user.id = ufv.item_id AND
1482
                                (field_id = ".$extraFieldInfo['id']." OR field_id IS NULL)
1483
                            )";
1484
                    $extraFieldWasAdded = true;
1485
                }
1486
            }
1487
        }
1488
1489
        $sql .= " WHERE user.active <> ".USER_SOFT_DELETED." AND
1490
            $filter_by_status_condition
1491
            ".implode(' OR ', $where);
1492
1493
        if ($multiple_access_url) {
1494
            $current_access_url_id = api_get_current_access_url_id();
1495
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1496
        }
1497
1498
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1499
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1500
        }
1501
1502
        if (!empty($courseIdsList)) {
1503
            $courseIdsList = array_map('intval', $courseIdsList);
1504
            $courseIdsList = implode('","', $courseIdsList);
1505
            if (empty($sessionIdList)) {
1506
                $sql .= ' AND course.id IN ("'.$courseIdsList.'")';
1507
            }
1508
        }
1509
1510
        if (!empty($userIdList)) {
1511
            $userIdList = array_map('intval', $userIdList);
1512
            $userIdList = implode('","', $userIdList);
1513
            $sql .= ' AND user.id IN ("'.$userIdList.'")';
1514
        }
1515
1516
        if (isset($filterByActive)) {
1517
            $filterByActive = (int) $filterByActive;
1518
            $sql .= " AND user.active = $filterByActive";
1519
        }
1520
1521
        if (!empty($searchByKeyword)) {
1522
            $searchByKeyword = Database::escape_string($searchByKeyword);
1523
            $sql .= " AND (
1524
                        user.firstname LIKE '$searchByKeyword' OR
1525
                        user.username LIKE '$searchByKeyword' OR
1526
                        user.lastname LIKE '$searchByKeyword'
1527
                    ) ";
1528
        }
1529
1530
        $sql .= $whereExtraField;
1531
        $sql .= " $order_by $limit";
1532
1533
        $rs = Database::query($sql);
1534
        $users = [];
1535
1536
        $extra_fields = UserManager::get_extra_fields(
1537
            0,
1538
            100,
1539
            null,
1540
            null,
1541
            true,
1542
            true
1543
        );
1544
1545
        $counter = 1;
1546
        $count_rows = Database::num_rows($rs);
1547
1548
        if ($return_count && $resumed_report) {
1549
            return $count_rows;
1550
        }
1551
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1552
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1553
        if ($count_rows) {
1554
            while ($user = Database::fetch_array($rs)) {
1555
                if ($return_count) {
1556
                    return $user['count'];
1557
                }
1558
1559
                $report_info = [];
1560
                $user_info = $user;
1561
                $user_info['status'] = $user['status'];
1562
                if (isset($user['is_tutor'])) {
1563
                    $user_info['is_tutor'] = $user['is_tutor'];
1564
                }
1565
                if (!empty($sessionId)) {
1566
                    $user_info['status_session'] = $user['status_session'];
1567
                }
1568
1569
                $sessionId = $user['session_id'] ?? 0;
1570
                $sessionName = isset($user['session_name']) ? ' ('.$user['session_name'].') ' : '';
1571
1572
                if ($add_reports) {
1573
                    if ($resumed_report) {
1574
                        $extra = [];
1575
                        if (!empty($extra_fields)) {
1576
                            foreach ($extra_fields as $extra) {
1577
                                if (in_array($extra['1'], $extra_field)) {
1578
                                    $user_data = UserManager::get_extra_user_data_by_field(
1579
                                        $user['user_id'],
1580
                                        $extra['1']
1581
                                    );
1582
                                    break;
1583
                                }
1584
                            }
1585
                        }
1586
1587
                        $row_key = '-1';
1588
                        $name = '-';
1589
                        if (!empty($extra)) {
1590
                            if (!empty($user_data[$extra['1']])) {
1591
                                $row_key = $user_data[$extra['1']];
1592
                                $name = $user_data[$extra['1']];
1593
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1594
                            }
1595
                        }
1596
1597
                        if (empty($users[$row_key])) {
1598
                            $users[$row_key] = [];
1599
                        }
1600
1601
                        if (!array_key_exists('training_hours', $users[$row_key])) {
1602
                            $users[$row_key]['training_hours'] = 0;
1603
                        }
1604
1605
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1606
                            $user['user_id'],
1607
                            $user['c_id'],
1608
                            $sessionId
1609
                        );
1610
1611
                        if (!array_key_exists('count_users', $users[$row_key])) {
1612
                            $users[$row_key]['count_users'] = 0;
1613
                        }
1614
1615
                        $users[$row_key]['count_users'] += $counter;
1616
1617
                        $registered_users_with_extra_field = self::getCountRegisteredUsersWithCourseExtraField(
1618
                            $name,
1619
                            $tableExtraField,
1620
                            $table_user_field_value
1621
                        );
1622
1623
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1624
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1625
1626
                        $category = Category::load(
1627
                            null,
1628
                            null,
1629
                            $user['c_id'],
1630
                            null,
1631
                            null,
1632
                            $sessionId
1633
                        );
1634
1635
                        if (!isset($users[$row_key]['count_certificates'])) {
1636
                            $users[$row_key]['count_certificates'] = 0;
1637
                        }
1638
1639
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1640
                            $users[$row_key]['count_certificates']++;
1641
                        }
1642
1643
                        foreach ($extra_fields as $extra) {
1644
                            if ('ruc' === $extra['1']) {
1645
                                continue;
1646
                            }
1647
1648
                            if (!isset($users[$row_key][$extra['1']])) {
1649
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1650
                                if (!empty($user_data[$extra['1']])) {
1651
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1652
                                }
1653
                            }
1654
                        }
1655
                    } else {
1656
                        $report_info['course'] = $user['title'].$sessionName;
1657
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1658
                        $report_info['email'] = $user['email'];
1659
                        $report_info['time'] = api_time_to_hms(
1660
                            Tracking::get_time_spent_on_the_course(
1661
                                $user['user_id'],
1662
                                $user['c_id'],
1663
                                $sessionId
1664
                            )
1665
                        );
1666
1667
                        $category = Category:: load(
1668
                            null,
1669
                            null,
1670
                            $user['c_id'],
1671
                            null,
1672
                            null,
1673
                            $sessionId
1674
                        );
1675
1676
                        $report_info['certificate'] = Display::label(get_lang('No'));
1677
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1678
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1679
                        }
1680
                        $course = api_get_course_entity($user['c_id']);
1681
                        $progress = (int) Tracking::get_avg_student_progress(
1682
                            $user['user_id'],
1683
                            $course,
1684
                            [],
1685
                            $session
1686
                        );
1687
1688
                        $report_info['progress_100'] = 100 == $progress ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1689
                        $report_info['progress'] = $progress."%";
1690
                        foreach ($extra_fields as $extra) {
1691
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1692
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1693
                        }
1694
                        $report_info['user_id'] = $user['user_id'];
1695
                        $users[] = $report_info;
1696
                    }
1697
                } else {
1698
                    $users[$user['user_id']] = $user_info;
1699
                }
1700
            }
1701
        }
1702
1703
        return $users;
1704
    }
1705
1706
    /**
1707
     * @param bool  $resumed_report
1708
     * @param array $extra_field
1709
     * @param array $courseCodeList
1710
     * @param array $userIdList
1711
     * @param array $sessionIdList
1712
     * @param array $options
1713
     *
1714
     * @return array|int
1715
     */
1716
    public static function get_count_user_list_from_course_code(
1717
        $resumed_report = false,
1718
        $extra_field = [],
1719
        $courseCodeList = [],
1720
        $userIdList = [],
1721
        $sessionIdList = [],
1722
        $options = []
1723
    ) {
1724
        return self::get_user_list_from_course_code(
1725
            null,
1726
            0,
1727
            null,
1728
            null,
1729
            null,
1730
            true,
1731
            false,
1732
            $resumed_report,
1733
            $extra_field,
1734
            $courseCodeList,
1735
            $userIdList,
1736
            null,
1737
            $sessionIdList,
1738
            null,
1739
            $options
1740
        );
1741
    }
1742
1743
    /**
1744
     * Gets subscribed users in a course or in a course/session.
1745
     *
1746
     * @param string $course_code
1747
     * @param int    $session_id
1748
     *
1749
     * @return int
1750
     */
1751
    public static function get_users_count_in_course(
1752
        $course_code,
1753
        $session_id = 0,
1754
        $status = null
1755
    ) {
1756
        // variable initialisation
1757
        $session_id = (int) $session_id;
1758
        $course_code = Database::escape_string($course_code);
1759
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
1760
        $tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1761
        $tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1762
        $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1763
1764
        $courseInfo = api_get_course_info($course_code);
1765
        $courseId = $courseInfo['real_id'];
1766
1767
        $sql = "
1768
            SELECT DISTINCT count(user.id) as count
1769
            FROM $tblUser as user
1770
        ";
1771
        $where = [];
1772
        if (!empty($session_id)) {
1773
            $sql .= "
1774
                LEFT JOIN $tblSessionCourseUser as session_course_user
1775
                ON user.id = session_course_user.user_id
1776
                    AND session_course_user.c_id = $courseId
1777
                    AND session_course_user.session_id = $session_id
1778
            ";
1779
1780
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1781
        } else {
1782
            $sql .= "
1783
                LEFT JOIN $tblCourseUser as course_rel_user
1784
                    ON user.id = course_rel_user.user_id
1785
                    AND course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1786
                    AND course_rel_user.c_id = $courseId
1787
            ";
1788
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1789
        }
1790
1791
        $multiple_access_url = api_get_multiple_access_url();
1792
        if ($multiple_access_url) {
1793
            $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.id) ";
1794
        }
1795
1796
        $sql .= ' WHERE user.active <> '.USER_SOFT_DELETED.' AND '.implode(' OR ', $where);
1797
1798
        if ($multiple_access_url) {
1799
            $current_access_url_id = api_get_current_access_url_id();
1800
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1801
        }
1802
        $rs = Database::query($sql);
1803
        $count = 0;
1804
        if (Database::num_rows($rs)) {
1805
            $user = Database::fetch_array($rs);
1806
            $count = $user['count'];
1807
        }
1808
1809
        return $count;
1810
    }
1811
1812
    /**
1813
     * Get a list of coaches of a course and a session.
1814
     *
1815
     * @param string $course_code
1816
     * @param int    $session_id
1817
     * @param bool   $addGeneralCoach
1818
     *
1819
     * @return array List of users
1820
     */
1821
    public static function get_coach_list_from_course_code(
1822
        $course_code,
1823
        $session_id,
1824
        $addGeneralCoach = true
1825
    ) {
1826
        if (empty($course_code) || empty($session_id)) {
1827
            return [];
1828
        }
1829
1830
        $course_code = Database::escape_string($course_code);
1831
        $courseInfo = api_get_course_info($course_code);
1832
        $courseId = $courseInfo['real_id'];
1833
        $session_id = (int) $session_id;
1834
        $users = [];
1835
1836
        // We get the coach for the given course in a given session.
1837
        $sql = 'SELECT user_id FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).
1838
               " WHERE session_id = $session_id AND c_id = $courseId AND status = ".SessionEntity::COURSE_COACH;
1839
        $rs = Database::query($sql);
1840
        while ($user = Database::fetch_array($rs)) {
1841
            $userInfo = api_get_user_info($user['user_id']);
1842
            if ($userInfo) {
1843
                $users[$user['user_id']] = $userInfo;
1844
            }
1845
        }
1846
1847
        if ($addGeneralCoach) {
1848
            $generalCoachesId = SessionManager::getGeneralCoachesIdForSession($session_id);
1849
1850
            foreach ($generalCoachesId as $session_id_coach) {
1851
                $userInfo = api_get_user_info($session_id_coach);
1852
                if ($userInfo) {
1853
                    $users[$session_id_coach] = $userInfo;
1854
                }
1855
            }
1856
        }
1857
1858
        return $users;
1859
    }
1860
1861
    /**
1862
     *  Return user info array of all users registered in a course
1863
     *  This only returns the users that are registered in this actual course, not linked courses.
1864
     *
1865
     * @param string $course_code
1866
     * @param bool   $with_session
1867
     * @param int    $sessionId
1868
     * @param string $date_from
1869
     * @param string $date_to
1870
     * @param bool   $includeInvitedUsers Whether include the invited users
1871
     * @param int    $groupId
1872
     * @param bool   $getCount
1873
     * @param int    $start
1874
     * @param int    $limit
1875
     *
1876
     * @return array with user id
1877
     */
1878
    public static function get_student_list_from_course_code(
1879
        $course_code,
1880
        $with_session = false,
1881
        $sessionId = 0,
1882
        $date_from = null,
1883
        $date_to = null,
1884
        $includeInvitedUsers = true,
1885
        $groupId = 0,
1886
        $getCount = false,
1887
        $start = 0,
1888
        $limit = 0
1889
    ) {
1890
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1891
        $sessionId = (int) $sessionId;
1892
        $courseInfo = api_get_course_info($course_code);
1893
        if (empty($courseInfo)) {
1894
            return [];
1895
        }
1896
        $courseId = $courseInfo['real_id'];
1897
        $students = [];
1898
1899
        $limitCondition = '';
1900
        if (isset($start) && isset($limit) && !empty($limit)) {
1901
            $start = (int) $start;
1902
            $limit = (int) $limit;
1903
            $limitCondition = " LIMIT $start, $limit";
1904
        }
1905
1906
        $select = '*';
1907
        if ($getCount) {
1908
            $select = 'count(u.id) as count';
1909
        }
1910
1911
        if (empty($sessionId)) {
1912
            if (empty($groupId)) {
1913
                // students directly subscribed to the course
1914
                $sql = "SELECT $select
1915
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1916
                        INNER JOIN $userTable u
1917
                        ON cu.user_id = u.id
1918
                        WHERE u.active <> ".USER_SOFT_DELETED." AND c_id = $courseId AND cu.status = ".STUDENT;
1919
1920
                if (!$includeInvitedUsers) {
1921
                    $sql .= " AND u.status != ".INVITEE;
1922
                }
1923
                $sql .= $limitCondition;
1924
                $rs = Database::query($sql);
1925
1926
                if ($getCount) {
1927
                    $row = Database::fetch_array($rs);
1928
1929
                    return (int) $row['count'];
1930
                }
1931
1932
                while ($student = Database::fetch_array($rs)) {
1933
                    $students[$student['user_id']] = $student;
1934
                }
1935
            } else {
1936
                $students = GroupManager::get_users(
1937
                    $groupId,
1938
                    false,
1939
                    $start,
1940
                    $limit,
1941
                    $getCount,
1942
                    $courseInfo['real_id']
1943
                );
1944
                $students = array_flip($students);
1945
            }
1946
        }
1947
1948
        // students subscribed to the course through a session
1949
        if ($with_session) {
1950
            $joinSession = '';
1951
            //Session creation date
1952
            if (!empty($date_from) && !empty($date_to)) {
1953
                $joinSession = "INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s";
1954
            }
1955
1956
            $sql = "SELECT $select
1957
                      FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
1958
                      $joinSession
1959
                      INNER JOIN $userTable u
1960
                      ON scu.user_id = u.id
1961
                      WHERE u.active <> ".USER_SOFT_DELETED." AND scu.c_id = $courseId AND scu.status = ".SessionEntity::STUDENT;
1962
1963
            if (!empty($date_from) && !empty($date_to)) {
1964
                $date_from = Database::escape_string($date_from);
1965
                $date_to = Database::escape_string($date_to);
1966
                $sql .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
1967
            }
1968
1969
            if (0 != $sessionId) {
1970
                $sql .= " AND scu.session_id = $sessionId";
1971
            }
1972
1973
            if (!$includeInvitedUsers) {
1974
                $sql .= " AND u.status != ".INVITEE;
1975
            }
1976
            $sql .= $limitCondition;
1977
1978
            $rs = Database::query($sql);
1979
1980
            if ($getCount) {
1981
                $row = Database::fetch_array($rs);
1982
1983
                return (int) $row['count'];
1984
            }
1985
1986
            while ($student = Database::fetch_array($rs)) {
1987
                $students[$student['user_id']] = $student;
1988
            }
1989
        }
1990
1991
        return $students;
1992
    }
1993
1994
    /**
1995
     * Return user info array of all teacher-users registered in a course
1996
     * This only returns the users that are registered in this actual course, not linked courses.
1997
     *
1998
     * @param string $course_code
1999
     *
2000
     * @return array with user id
2001
     */
2002
    public static function get_teacher_list_from_course_code($course_code)
2003
    {
2004
        $courseInfo = api_get_course_info($course_code);
2005
        $courseId = $courseInfo['real_id'];
2006
        if (empty($courseId)) {
2007
            return false;
2008
        }
2009
2010
        $sql = "SELECT DISTINCT
2011
                    u.id as user_id,
2012
                    u.lastname,
2013
                    u.firstname,
2014
                    u.email,
2015
                    u.username,
2016
                    u.status
2017
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2018
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2019
                ON (cu.user_id = u.id)
2020
                WHERE
2021
                    cu.c_id = $courseId AND
2022
                    cu.status = 1 ";
2023
        $rs = Database::query($sql);
2024
        $teachers = [];
2025
        while ($teacher = Database::fetch_array($rs)) {
2026
            $teachers[$teacher['user_id']] = $teacher;
2027
        }
2028
2029
        return $teachers;
2030
    }
2031
2032
    /**
2033
     * Return user info array of all teacher-users registered in a course
2034
     * This only returns the users that are registered in this actual course, not linked courses.
2035
     *
2036
     * @param int  $courseId
2037
     * @param bool $loadAvatars
2038
     *
2039
     * @return array with user id
2040
     */
2041
    public static function getTeachersFromCourse($courseId, $loadAvatars = true)
2042
    {
2043
        $courseId = (int) $courseId;
2044
2045
        if (empty($courseId)) {
2046
            return false;
2047
        }
2048
2049
        $sql = "SELECT DISTINCT
2050
                    u.id as user_id,
2051
                    u.lastname,
2052
                    u.firstname,
2053
                    u.email,
2054
                    u.username,
2055
                    u.status
2056
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2057
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2058
                ON (cu.user_id = u.id)
2059
                WHERE
2060
                    cu.c_id = $courseId AND
2061
                    cu.status = 1 ";
2062
        $rs = Database::query($sql);
2063
        $listTeachers = [];
2064
        $teachers = [];
2065
        $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&course_id='.$courseId;
2066
        while ($teacher = Database::fetch_array($rs)) {
2067
            $teachers['id'] = $teacher['user_id'];
2068
            $teachers['lastname'] = $teacher['lastname'];
2069
            $teachers['firstname'] = $teacher['firstname'];
2070
            $teachers['email'] = $teacher['email'];
2071
            $teachers['username'] = $teacher['username'];
2072
            $teachers['status'] = $teacher['status'];
2073
            $teachers['fullname'] = api_get_person_name($teacher['firstname'], $teacher['lastname']);
2074
            $teachers['avatar'] = '';
2075
            /*if ($loadAvatars) {
2076
                $userPicture = UserManager::getUserPicture($teacher['user_id'], USER_IMAGE_SIZE_SMALL);
2077
                $teachers['avatar'] = $userPicture;
2078
            }*/
2079
            $teachers['url'] = $url.'&user_id='.$teacher['user_id'];
2080
            $listTeachers[] = $teachers;
2081
        }
2082
2083
        return $listTeachers;
2084
    }
2085
2086
    /**
2087
     * Returns a string list of teachers assigned to the given course.
2088
     *
2089
     * @param string $course_code
2090
     * @param string $separator           between teachers names
2091
     * @param bool   $add_link_to_profile Whether to add a link to the teacher's profile
2092
     * @param bool   $orderList
2093
     *
2094
     * @return string List of teachers teaching the course
2095
     */
2096
    public static function getTeacherListFromCourseCodeToString(
2097
        $course_code,
2098
        $separator = self::USER_SEPARATOR,
2099
        $add_link_to_profile = false,
2100
        $orderList = false
2101
    ) {
2102
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
2103
        $html = '';
2104
        $list = [];
2105
        if (!empty($teacher_list)) {
2106
            foreach ($teacher_list as $teacher) {
2107
                $teacher_name = api_get_person_name(
2108
                    $teacher['firstname'],
2109
                    $teacher['lastname']
2110
                );
2111
                if ($add_link_to_profile) {
2112
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$teacher['user_id'];
2113
                    $teacher_name = Display::url(
2114
                        $teacher_name,
2115
                        $url,
2116
                        [
2117
                            'class' => 'ajax',
2118
                            'data-title' => $teacher_name,
2119
                        ]
2120
                    );
2121
                }
2122
                $list[] = $teacher_name;
2123
            }
2124
2125
            if (!empty($list)) {
2126
                if (true === $orderList) {
2127
                    $html .= '<ul class="user-teacher">';
2128
                    foreach ($list as $teacher) {
2129
                        $html .= '<li>';
2130
                        $html .= Display::getMdiIcon(ObjectIcon::TEACHER, 'ch-tool-icon', null, ICON_SIZE_TINY);
2131
                        $html .= ' '.$teacher;
2132
                        $html .= '</li>';
2133
                    }
2134
                    $html .= '</ul>';
2135
                } else {
2136
                    $html .= array_to_string($list, $separator);
2137
                }
2138
            }
2139
        }
2140
2141
        return $html;
2142
    }
2143
2144
    /**
2145
     * This function returns information about coachs from a course in session.
2146
     *
2147
     * @param int $session_id
2148
     * @param int $courseId
2149
     *
2150
     * @return array containing user_id, lastname, firstname, username
2151
     */
2152
    public static function get_coachs_from_course($session_id = 0, $courseId = 0)
2153
    {
2154
        if (!empty($session_id)) {
2155
            $session_id = intval($session_id);
2156
        } else {
2157
            $session_id = api_get_session_id();
2158
        }
2159
2160
        if (!empty($courseId)) {
2161
            $courseId = intval($courseId);
2162
        } else {
2163
            $courseId = api_get_course_int_id();
2164
        }
2165
2166
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2167
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2168
2169
        $sql = "SELECT DISTINCT
2170
                    u.id as user_id,
2171
                    u.lastname,
2172
                    u.firstname,
2173
                    u.username
2174
                FROM $tbl_user u
2175
                INNER JOIN $tbl_session_course_user scu
2176
                ON (u.id = scu.user_id)
2177
                WHERE
2178
                    scu.session_id = $session_id AND
2179
                    scu.c_id = $courseId AND
2180
                    scu.status = ".SessionEntity::COURSE_COACH;
2181
        $rs = Database::query($sql);
2182
2183
        $coaches = [];
2184
        if (Database::num_rows($rs) > 0) {
2185
            while ($row = Database::fetch_array($rs)) {
2186
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
2187
                $coaches[] = $row + ['full_name' => $completeName];
2188
            }
2189
        }
2190
2191
        return $coaches;
2192
    }
2193
2194
    /**
2195
     * @param int    $session_id
2196
     * @param int    $courseId
2197
     * @param string $separator
2198
     * @param bool   $add_link_to_profile
2199
     * @param bool   $orderList
2200
     *
2201
     * @return string
2202
     */
2203
    public static function get_coachs_from_course_to_string(
2204
        $session_id = 0,
2205
        $courseId = 0,
2206
        $separator = self::USER_SEPARATOR,
2207
        $add_link_to_profile = false,
2208
        $orderList = false
2209
    ) {
2210
        $coachList = self::get_coachs_from_course($session_id, $courseId);
2211
        $course_coachs = [];
2212
        if (!empty($coachList)) {
2213
            foreach ($coachList as $coach_course) {
2214
                $coach_name = $coach_course['full_name'];
2215
                if ($add_link_to_profile) {
2216
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coach_course['user_id'].'&course_id='.$courseId.'&session_id='.$session_id;
2217
                    $coach_name = Display::url(
2218
                        $coach_name,
2219
                        $url,
2220
                        [
2221
                            'class' => 'ajax',
2222
                            'data-title' => $coach_name,
2223
                        ]
2224
                    );
2225
                }
2226
                $course_coachs[] = $coach_name;
2227
            }
2228
        }
2229
2230
        $html = '';
2231
        if (!empty($course_coachs)) {
2232
            if (true === $orderList) {
2233
                $html .= '<ul class="user-coachs">';
2234
                foreach ($course_coachs as $coachs) {
2235
                    $html .= Display::tag(
2236
                        'li',
2237
                        Display::getMdiIcon(
2238
                            ObjectIcon::TEACHER,
2239
                            'ch-tool-icon',
2240
                            null,
2241
                            ICON_SIZE_TINY,
2242
                            get_lang('Coach')
2243
                        ).' '.$coachs
2244
                    );
2245
                }
2246
                $html .= '</ul>';
2247
            } else {
2248
                $html = array_to_string($course_coachs, $separator);
2249
            }
2250
        }
2251
2252
        return $html;
2253
    }
2254
2255
    /**
2256
     * Get the list of groups from the course.
2257
     *
2258
     * @param string $course_code
2259
     * @param int    $session_id     Session ID (optional)
2260
     * @param int    $getEmptyGroups get empty groups (optional)
2261
     *
2262
     * @return CGroup[]
2263
     */
2264
    public static function get_group_list_of_course(
2265
        $course_code,
2266
        $session_id = 0,
2267
        $getEmptyGroups = 0,
2268
        $asArray = false
2269
    ) {
2270
        $course_info = api_get_course_info($course_code);
2271
2272
        if (empty($course_info)) {
2273
            return [];
2274
        }
2275
        $course_id = $course_info['real_id'];
2276
2277
        if (empty($course_id)) {
2278
            return [];
2279
        }
2280
2281
        $repo = Container::getGroupRepository();
2282
2283
        $course = api_get_course_entity($course_info['real_id']);
2284
        $session = api_get_session_entity($session_id);
2285
        $qb = $repo->getResourcesByCourse($course, $session);
2286
        $groups = $qb->getQuery()->getResult();
2287
        $groupList = [];
2288
        /** @var CGroup $group */
2289
        foreach ($groups as $group) {
2290
            if (0 === $getEmptyGroups) {
2291
                if (!$group->hasMembers()) {
2292
                    continue;
2293
                }
2294
            }
2295
            if ($asArray) {
2296
                $groupList[$group->getIid()] = ['id' => $group->getIid(), 'name' => $group->getTitle()];
2297
            } else {
2298
                $groupList[$group->getIid()] = $group;
2299
            }
2300
        }
2301
2302
        /* 0 != $session_id ? $session_condition = ' WHERE g.session_id IN(1,'.intval($session_id).')' : $session_condition = ' WHERE g.session_id = 0';
2303
         if (0 == $in_get_empty_group) {
2304
             // get only groups that are not empty
2305
             $sql = "SELECT DISTINCT g.iid, g.title
2306
                     FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2307
                     INNER JOIN ".Database::get_course_table(TABLE_GROUP_USER)." gu
2308
                     ON (g.iid = gu.group_id)
2309
                     $session_condition
2310
                     ORDER BY g.title";
2311
         } else {
2312
             // get all groups even if they are empty
2313
             $sql = "SELECT g.iid, g.title
2314
                     FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2315
                     $session_condition
2316
                     AND c_id = $course_id";
2317
         }
2318
2319
         $result = Database::query($sql);
2320
         $groupList = [];
2321
         while ($groupData = Database::fetch_array($result)) {
2322
             $groupData['userNb'] = GroupManager::number_of_students($groupData['iid'], $course_id);
2323
             $groupList[$groupData['iid']] = $groupData;
2324
         }*/
2325
2326
        return $groupList;
2327
    }
2328
2329
    /**
2330
     * Delete a course
2331
     * This function deletes a whole course-area from the platform. When the
2332
     * given course is a virtual course, the database and directory will not be
2333
     * deleted.
2334
     * When the given course is a real course, also all virtual courses refering
2335
     * to the given course will be deleted.
2336
     * Considering the fact that we remove all traces of the course in the main
2337
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2338
     * so that a new course created with this code would not use the remains of an older
2339
     * course.
2340
     *
2341
     * @param string $code The code of the course to delete
2342
     */
2343
    public static function delete_course($code)
2344
    {
2345
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2346
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2347
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2348
2349
        $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
2350
        $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2351
        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2352
        $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
2353
        $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2354
        $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2355
        $table_stats_online = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
2356
        $table_stats_downloads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
2357
        $table_stats_links = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
2358
        $table_stats_uploads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
2359
2360
        if (empty($code)) {
2361
            return false;
2362
        }
2363
2364
        $courseRepo = Container::getCourseRepository();
2365
        /** @var Course $course */
2366
        $course = $courseRepo->findOneBy(['code' => $code]);
2367
2368
        if (null === $course) {
2369
            return false;
2370
        }
2371
2372
        $courseId = $course->getId();
2373
2374
        /** @var SequenceResourceRepository $repo */
2375
        $repo = Database::getManager()->getRepository(SequenceResource::class);
2376
        $sequenceResource = $repo->findRequirementForResource(
2377
            $courseId,
2378
            SequenceResource::COURSE_TYPE
2379
        );
2380
2381
        if ($sequenceResource) {
2382
            Display::addFlash(
2383
                Display::return_message(
2384
                    get_lang('ThereIsASequenceResourceLinkedToThisCourseYouNeedToDeleteItFirst'),
2385
                    'error'
2386
                )
2387
            );
2388
2389
            return false;
2390
        }
2391
2392
        $count = 0;
2393
        if (api_is_multiple_url_enabled()) {
2394
            $url_id = 1;
2395
            if (-1 != api_get_current_access_url_id()) {
2396
                $url_id = api_get_current_access_url_id();
2397
            }
2398
            UrlManager::delete_url_rel_course($courseId, $url_id);
2399
            $count = UrlManager::getCountUrlRelCourse($courseId);
2400
        }
2401
2402
        if (0 === $count) {
2403
            // Cleaning group categories
2404
            $groupCategories = GroupManager::get_categories($course);
2405
            if (!empty($groupCategories)) {
2406
                foreach ($groupCategories as $category) {
2407
                    GroupManager::delete_category($category['iid'], $course->getCode());
2408
                }
2409
            }
2410
2411
            $course_tables = AddCourse::get_course_tables();
2412
            // Cleaning c_x tables
2413
            if (!empty($courseId)) {
2414
                foreach ($course_tables as $table) {
2415
                    if ('document' === $table) {
2416
                        // Table document will be deleted by Doctrine.
2417
                        continue;
2418
                    }
2419
                    $table = Database::get_course_table($table);
2420
                }
2421
            }
2422
2423
            $resourceLink = $course->getFirstResourceLink();
2424
            $resourceLinkId = $resourceLink?->getId();
2425
2426
            // Unsubscribe all users from the course
2427
            $sql = "DELETE FROM $table_course_user WHERE c_id = $courseId";
2428
            Database::query($sql);
2429
            // Delete the course from the sessions tables
2430
            $sql = "DELETE FROM $table_session_course WHERE c_id = $courseId";
2431
            Database::query($sql);
2432
            $sql = "DELETE FROM $table_session_course_user WHERE c_id = $courseId";
2433
            Database::query($sql);
2434
2435
            // Delete from Course - URL
2436
            // Already deleted because of entities.
2437
            //$sql = "DELETE FROM $table_course_rel_url WHERE c_id = $courseId";
2438
            //Database::query($sql);
2439
2440
            // Delete the course from the stats tables
2441
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2442
            Database::query($sql);
2443
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2444
            Database::query($sql);
2445
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2446
            Database::query($sql);
2447
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2448
            Database::query($sql);
2449
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2450
            Database::query($sql);
2451
            // Do not delete rows from track_e_default as these include course
2452
            // creation and other important things that do not take much space
2453
            // but give information on the course history
2454
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2455
            //Database::query($sql);
2456
            if ($resourceLinkId) {
2457
                $sql = "DELETE FROM $table_stats_downloads WHERE resource_link_id = $resourceLinkId";
2458
                Database::query($sql);
2459
            }
2460
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2461
            Database::query($sql);
2462
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2463
            Database::query($sql);
2464
2465
            // Update ticket
2466
            $table = Database::get_main_table(TABLE_TICKET_TICKET);
2467
            $sql = "UPDATE $table SET course_id = NULL WHERE course_id = $courseId";
2468
            Database::query($sql);
2469
2470
            $repo->deleteSequenceResource(
2471
                $courseId,
2472
                SequenceResource::COURSE_TYPE
2473
            );
2474
2475
            // Class
2476
            $table = Database::get_main_table(TABLE_USERGROUP_REL_COURSE);
2477
            $sql = "DELETE FROM $table
2478
                    WHERE course_id = $courseId";
2479
            Database::query($sql);
2480
2481
            // Skills
2482
            $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
2483
            $argumentation = Database::escape_string(
2484
                sprintf(
2485
                    get_lang('This skill was obtained through course %s which has been removed since then.'),
2486
                    $course->getCode()
2487
                )
2488
            );
2489
            $sql = "UPDATE $table SET course_id = NULL, session_id = NULL, argumentation = '$argumentation'
2490
                    WHERE course_id = $courseId";
2491
            Database::query($sql);
2492
2493
            // Should be deleted by doctrine
2494
            //$sql = "DELETE FROM skill_rel_course WHERE c_id = $courseId";
2495
            //Database::query($sql);
2496
2497
            // Deletes all groups, group-users, group-tutors information
2498
            // To prevent fK mix up on some tables
2499
            //GroupManager::deleteAllGroupsFromCourse($courseId);
2500
2501
            $appPlugin = new AppPlugin();
2502
            $appPlugin->performActionsWhenDeletingItem('course', $courseId);
2503
2504
            //$repo = Container::getQuizRepository();
2505
            //$repo->deleteAllByCourse($courseEntity);
2506
2507
            // Delete the course from the database
2508
            $courseRepo->deleteCourse($course);
2509
2510
            // delete extra course fields
2511
            $extraFieldValues = new ExtraFieldValue('course');
2512
            $extraFieldValues->deleteValuesByItem($courseId);
2513
2514
            // Add event to system log
2515
            Event::addEvent(
2516
                LOG_COURSE_DELETE,
2517
                LOG_COURSE_CODE,
2518
                $code,
2519
                api_get_utc_datetime(),
2520
                api_get_user_id(),
2521
                $courseId
2522
            );
2523
2524
            return true;
2525
        }
2526
    }
2527
2528
    /**
2529
     * Sort courses for a specific user ??
2530
     *
2531
     * @param int    $user_id     User ID
2532
     * @param string $course_code Course code
2533
     *
2534
     * @return int Minimum course order
2535
     *
2536
     * @todo Review documentation
2537
     */
2538
    public static function userCourseSort($user_id, $course_code)
2539
    {
2540
        $user_id = (int) $user_id;
2541
2542
        if (empty($user_id) || empty($course_code)) {
2543
            return 0;
2544
        }
2545
2546
        $course_code = Database::escape_string($course_code);
2547
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2548
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2549
2550
        $course_title = Database::result(
2551
            Database::query(
2552
                "SELECT title FROM $TABLECOURSE WHERE code = '$course_code'"
2553
            ),
2554
            0,
2555
            0
2556
        );
2557
        if (false === $course_title) {
2558
            $course_title = '';
2559
        }
2560
2561
        $sql = "SELECT course.code as code, course.title as title, cu.sort as sort
2562
                FROM $TABLECOURSUSER as cu, $TABLECOURSE as course
2563
                WHERE   course.id = cu.c_id AND user_id = $user_id AND
2564
                        cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2565
                        user_course_cat = 0
2566
                ORDER BY cu.sort";
2567
        $result = Database::query($sql);
2568
2569
        $course_title_precedent = '';
2570
        $counter = 0;
2571
        $course_found = false;
2572
        $course_sort = 1;
2573
2574
        if (Database::num_rows($result) > 0) {
2575
            while ($courses = Database::fetch_array($result)) {
2576
                if ('' == $course_title_precedent) {
2577
                    $course_title_precedent = $courses['title'];
2578
                }
2579
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2580
                    $course_found = true;
2581
                    if (!empty($courses['sort'])) {
2582
                        $course_sort = $courses['sort'];
2583
                    }
2584
                    if (0 == $counter) {
2585
                        $sql = "UPDATE $TABLECOURSUSER
2586
                                SET sort = sort+1
2587
                                WHERE
2588
                                    user_id= $user_id AND
2589
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2590
                                    AND user_course_cat = 0
2591
                                    AND sort > $course_sort";
2592
                        $course_sort++;
2593
                    } else {
2594
                        $sql = "UPDATE $TABLECOURSUSER SET sort = sort+1
2595
                                WHERE
2596
                                    user_id= $user_id AND
2597
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2598
                                    user_course_cat = 0 AND
2599
                                    sort >= $course_sort";
2600
                    }
2601
                    Database::query($sql);
2602
                    break;
2603
                } else {
2604
                    $course_title_precedent = $courses['title'];
2605
                }
2606
                $counter++;
2607
            }
2608
2609
            // We must register the course in the beginning of the list
2610
            if (!$course_found) {
2611
                $course_sort = Database::result(
2612
                    Database::query(
2613
                        'SELECT min(sort) as min_sort FROM '.$TABLECOURSUSER.' WHERE user_id = "'.$user_id.'" AND user_course_cat="0"'
2614
                    ),
2615
                    0,
2616
                    0
2617
                );
2618
                Database::query("UPDATE $TABLECOURSUSER SET sort = sort+1 WHERE user_id = $user_id AND user_course_cat = 0");
2619
            }
2620
        }
2621
2622
        return (int) $course_sort;
2623
    }
2624
2625
    /**
2626
     * check if course exists.
2627
     *
2628
     * @param string $courseCode
2629
     *
2630
     * @return int if exists, false else
2631
     */
2632
    public static function course_exists($courseCode)
2633
    {
2634
        $courseCode = Database::escape_string($courseCode);
2635
        $sql = "SELECT 1 FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2636
                WHERE code = '$courseCode'";
2637
2638
        return Database::num_rows(Database::query($sql));
2639
    }
2640
2641
    /**
2642
     * Send an email to tutor after the auth-suscription of a student in your course.
2643
     *
2644
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2645
     *
2646
     * @param int    $user_id            the id of the user
2647
     * @param string $courseId           the course code
2648
     * @param bool   $send_to_tutor_also
2649
     *
2650
     * @return false|null we return the message that is displayed when the action is successful
2651
     */
2652
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2653
    {
2654
        $user_id = (int) $user_id;
2655
        $courseId = (int) $courseId;
2656
        $information = api_get_course_info_by_id($courseId);
2657
        $course_code = $information['code'];
2658
        $student = api_get_user_info($user_id);
2659
2660
        $name_course = $information['title'];
2661
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
2662
                WHERE c_id = $courseId";
2663
2664
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2665
        //if ($send_to_tutor_also = true)
2666
        // Proposed change:
2667
        if ($send_to_tutor_also) {
2668
            $sql .= ' AND is_tutor = 1';
2669
        } else {
2670
            $sql .= ' AND status = 1';
2671
        }
2672
2673
        $result = Database::query($sql);
2674
        while ($row = Database::fetch_array($result)) {
2675
            $tutor = api_get_user_info($row['user_id']);
2676
            $emailto = $tutor['email'];
2677
            $emailsubject = get_lang('New user in the course').': '.$name_course;
2678
            $emailbody = get_lang('Dear').': '.api_get_person_name($tutor['firstname'], $tutor['lastname'])."\n";
2679
            $emailbody .= get_lang('MessageNew user in the course').': '.$name_course."\n";
2680
            $emailbody .= get_lang('Username').': '.$student['username']."\n";
2681
            if (api_is_western_name_order()) {
2682
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2683
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2684
            } else {
2685
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2686
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2687
            }
2688
            $emailbody .= get_lang('e-mail').': <a href="mailto:'.$student['email'].'">'.$student['email']."</a>\n\n";
2689
            $recipient_name = api_get_person_name(
2690
                $tutor['firstname'],
2691
                $tutor['lastname'],
2692
                null,
2693
                PERSON_NAME_EMAIL_ADDRESS
2694
            );
2695
            $sender_name = api_get_person_name(
2696
                api_get_setting('administratorName'),
2697
                api_get_setting('administratorSurname'),
2698
                null,
2699
                PERSON_NAME_EMAIL_ADDRESS
2700
            );
2701
            $email_admin = api_get_setting('emailAdministrator');
2702
2703
            api_mail_html(
2704
                $recipient_name,
2705
                $emailto,
2706
                $emailsubject,
2707
                $emailbody,
2708
                $sender_name,
2709
                $email_admin
2710
            );
2711
        }
2712
    }
2713
2714
    /**
2715
     * @return array
2716
     */
2717
    public static function get_special_course_list()
2718
    {
2719
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2720
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
2721
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2722
        $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2723
2724
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2725
2726
        $courseList = [];
2727
        // get course list auto-register
2728
2729
        $sql = "SELECT id FROM $tbl_course_field
2730
                WHERE item_type = $extraFieldType AND
2731
                variable = 'special_course'";
2732
        $result = Database::query($sql);
2733
        $courseList = [];
2734
2735
        if (Database::num_rows($result) > 0) {
2736
            $row = Database::fetch_assoc($result);
2737
            // Get list of special courses (appear to all)
2738
            // Note: The value is better indexed as string, so
2739
            // using '1' instead of integer is more efficient
2740
            $sql = "SELECT DISTINCT(item_id) as cid
2741
                FROM $tbl_course_field_value
2742
                WHERE field_id = ".$row['id']." AND field_value = '1'";
2743
            $result = Database::query($sql);
2744
            while ($row = Database::fetch_assoc($result)) {
2745
                $courseList[] = $row['cid'];
2746
            }
2747
            if (count($courseList) < 1) {
2748
                return $courseList;
2749
            }
2750
            if (api_get_multiple_access_url()) {
2751
                //we filter the courses by the active URL
2752
                $coursesSelect = '';
2753
                if (1 == count($courseList)) {
2754
                    $coursesSelect = $courseList[0];
2755
                } else {
2756
                    $coursesSelect = implode(',', $courseList);
2757
                }
2758
                $access_url_id = api_get_current_access_url_id();
2759
                if (-1 != $access_url_id) {
2760
                    $sql = "SELECT c_id FROM $tbl_url_course
2761
                            WHERE access_url_id = $access_url_id
2762
                            AND c_id IN ($coursesSelect)";
2763
                    $result = Database::query($sql);
2764
                    while ($row = Database::fetch_assoc($result)) {
2765
                        $courseList[] = $row['c_id'];
2766
                    }
2767
                }
2768
            }
2769
        }
2770
2771
        return $courseList;
2772
    }
2773
2774
    /**
2775
     * Get the course codes that have been restricted in the catalogue, and if byUserId is set
2776
     * then the courses that the user is allowed or not to see in catalogue.
2777
     *
2778
     * @param bool $allowed  Either if the courses have some users that are or are not allowed to see in catalogue
2779
     * @param int  $byUserId if the courses are or are not allowed to see to the user
2780
     *
2781
     * @return array Course codes allowed or not to see in catalogue by some user or the user
2782
     */
2783
    public static function getCatalogCourseList($allowed = true, $byUserId = -1)
2784
    {
2785
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2786
        $tblCourseRelUserCatalogue = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
2787
        $visibility = $allowed ? 1 : 0;
2788
2789
        // Restriction by user id
2790
        $currentUserRestriction = '';
2791
2792
        $byUserId = (int) $byUserId;
2793
        if ($byUserId > 0) {
2794
            $currentUserRestriction = " AND tcruc.user_id = $byUserId ";
2795
        }
2796
2797
        //we filter the courses from the URL
2798
        $joinAccessUrl = '';
2799
        $whereAccessUrl = '';
2800
        if (api_get_multiple_access_url()) {
2801
            $accessUrlId = api_get_current_access_url_id();
2802
            if (-1 != $accessUrlId) {
2803
                $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2804
                $joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
2805
                                  ON url_rel_course.c_id = c.id ";
2806
                $whereAccessUrl = " AND access_url_id = $accessUrlId ";
2807
            }
2808
        }
2809
2810
        // get course list auto-register
2811
        $sql = "SELECT DISTINCT(c.code)
2812
                FROM $tblCourseRelUserCatalogue tcruc
2813
                INNER JOIN $courseTable c
2814
                ON (c.id = tcruc.c_id) $joinAccessUrl
2815
                WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
2816
2817
        $result = Database::query($sql);
2818
        $courseList = [];
2819
2820
        if (Database::num_rows($result) > 0) {
2821
            while ($resultRow = Database::fetch_array($result)) {
2822
                $courseList[] = $resultRow['code'];
2823
            }
2824
        }
2825
2826
        return $courseList;
2827
    }
2828
2829
    /**
2830
     * Get list of courses for a given user.
2831
     *
2832
     * @param int   $user_id
2833
     * @param bool  $include_sessions                   Whether to include courses from session or not
2834
     * @param bool  $adminGetsAllCourses                If the user is platform admin,
2835
     *                                                  whether he gets all the courses or just his. Note: This does
2836
     *                                                  *not* include all sessions
2837
     * @param bool  $loadSpecialCourses
2838
     * @param array $skipCourseList                     List of course ids to skip
2839
     * @param bool  $useUserLanguageFilterIfAvailable
2840
     * @param bool  $showCoursesSessionWithDifferentKey
2841
     *
2842
     * @return array List of codes and db name
2843
     *
2844
     * @author isaac flores paz
2845
     */
2846
    public static function get_courses_list_by_user_id(
2847
        $user_id,
2848
        $include_sessions = false,
2849
        $adminGetsAllCourses = false,
2850
        $loadSpecialCourses = true,
2851
        $skipCourseList = [],
2852
        $useUserLanguageFilterIfAvailable = true,
2853
        $showCoursesSessionWithDifferentKey = false
2854
    ) {
2855
        $user_id = intval($user_id);
2856
        $urlId = api_get_current_access_url_id();
2857
        $course_list = [];
2858
        $codes = [];
2859
2860
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2861
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2862
        $tableCourseUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2863
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
2864
2865
        $languageCondition = '';
2866
        $onlyInUserLanguage = ('true' === api_get_setting('course.my_courses_show_courses_in_user_language_only'));
2867
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
2868
            $userInfo = api_get_user_info(api_get_user_id());
2869
            if (!empty($userInfo['language'])) {
2870
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
2871
            }
2872
        }
2873
2874
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
2875
            // get the whole courses list
2876
            $sql = "SELECT DISTINCT(course.code), course.id as real_id, course.title
2877
                    FROM $tbl_course course
2878
                    INNER JOIN $tableCourseUrl url
2879
                    ON (course.id = url.c_id)
2880
                    WHERE
2881
                        url.access_url_id = $urlId
2882
                        $languageCondition
2883
                ";
2884
        } else {
2885
            $withSpecialCourses = $withoutSpecialCourses = '';
2886
2887
            if ($loadSpecialCourses) {
2888
                $specialCourseList = self::get_special_course_list();
2889
                if (!empty($specialCourseList)) {
2890
                    $specialCourseToString = '"'.implode('","', $specialCourseList).'"';
2891
                    $withSpecialCourses = ' AND course.id IN ('.$specialCourseToString.')';
2892
                    $withoutSpecialCourses = ' AND course.id NOT IN ('.$specialCourseToString.')';
2893
                }
2894
2895
                if (!empty($withSpecialCourses)) {
2896
                    $sql = "SELECT DISTINCT (course.code),
2897
                            course.id as real_id,
2898
                            course.title
2899
                            FROM $tbl_course_user course_rel_user
2900
                            LEFT JOIN $tbl_course course
2901
                            ON course.id = course_rel_user.c_id
2902
                            INNER JOIN $tableCourseUrl url
2903
                            ON (course.id = url.c_id)
2904
                            WHERE url.access_url_id = $urlId
2905
                            $withSpecialCourses
2906
                            $languageCondition
2907
                            GROUP BY course.code
2908
                            ORDER BY course.title, course_rel_user.sort ASC
2909
                    ";
2910
                    $result = Database::query($sql);
2911
                    if (Database::num_rows($result) > 0) {
2912
                        while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2913
                            $result_row['special_course'] = 1;
2914
                            $course_list[] = $result_row;
2915
                            $codes[] = $result_row['real_id'];
2916
                        }
2917
                    }
2918
                }
2919
            }
2920
2921
            // get course list not auto-register. Use Distinct to avoid multiple
2922
            // entries when a course is assigned to a HRD (DRH) as watcher
2923
            $sql = "SELECT
2924
                        DISTINCT(course.code),
2925
                        course.id as real_id,
2926
                        course.title
2927
                    FROM $tbl_course course
2928
                    INNER JOIN $tbl_course_user cru
2929
                    ON (course.id = cru.c_id)
2930
                    INNER JOIN $tableCourseUrl url
2931
                    ON (course.id = url.c_id)
2932
                    WHERE
2933
                        url.access_url_id = $urlId AND
2934
                        cru.user_id = $user_id
2935
                        $withoutSpecialCourses
2936
                        $languageCondition
2937
                    ORDER BY course.title
2938
                    ";
2939
        }
2940
        $result = Database::query($sql);
2941
2942
        if (Database::num_rows($result)) {
2943
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2944
                if (!empty($skipCourseList)) {
2945
                    if (in_array($row['real_id'], $skipCourseList)) {
2946
                        continue;
2947
                    }
2948
                }
2949
                $course_list[] = $row;
2950
                $codes[] = $row['real_id'];
2951
            }
2952
        }
2953
2954
        if (true === $include_sessions) {
2955
            $sql = "SELECT DISTINCT (c.code),
2956
                        c.id as real_id,
2957
                        s.id as session_id,
2958
                        s.name as session_name
2959
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
2960
                    INNER JOIN $tbl_course c
2961
                    ON (scu.c_id = c.id)
2962
                    INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s
2963
                    ON (s.id = scu.session_id)
2964
                    WHERE user_id = $user_id ";
2965
            $r = Database::query($sql);
2966
            while ($row = Database::fetch_array($r, 'ASSOC')) {
2967
                if (!empty($skipCourseList)) {
2968
                    if (in_array($row['real_id'], $skipCourseList)) {
2969
                        continue;
2970
                    }
2971
                }
2972
2973
                if ($showCoursesSessionWithDifferentKey) {
2974
                    $course_list[] = $row;
2975
                } else {
2976
                    if (!in_array($row['real_id'], $codes)) {
2977
                        $course_list[] = $row;
2978
                    }
2979
                }
2980
            }
2981
        }
2982
2983
        return $course_list;
2984
    }
2985
2986
    /**
2987
     * Get course ID from a given course directory name.
2988
     *
2989
     * @param string $path Course directory (without any slash)
2990
     *
2991
     * @return string Course code, or false if not found
2992
     */
2993
    public static function getCourseCodeFromDirectory($path)
2994
    {
2995
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
2996
        $res = Database::query("SELECT code FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2997
                WHERE directory LIKE BINARY '$path'");
2998
        if (false === $res) {
2999
            return false;
3000
        }
3001
        if (1 != Database::num_rows($res)) {
3002
            return false;
3003
        }
3004
        $row = Database::fetch_array($res);
3005
3006
        return $row['code'];
3007
    }
3008
3009
    /**
3010
     * Get course code(s) from visual code.
3011
     *
3012
     * @param   string  Visual code
3013
     *
3014
     * @return array List of codes for the given visual code
3015
     */
3016
    public static function get_courses_info_from_visual_code($code)
3017
    {
3018
        $result = [];
3019
        $sql_result = Database::query("SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
3020
                WHERE visual_code = '".Database::escape_string($code)."'");
3021
        while ($virtual_course = Database::fetch_array($sql_result)) {
3022
            $result[] = $virtual_course;
3023
        }
3024
3025
        return $result;
3026
    }
3027
3028
    /**
3029
     * Creates a new extra field for a given course.
3030
     *
3031
     * @param string $variable    Field's internal variable name
3032
     * @param int    $fieldType   Field's type
3033
     * @param string $displayText Field's language var name
3034
     * @param string $default     Optional. The default value
3035
     *
3036
     * @return int New extra field ID
3037
     */
3038
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default = '')
3039
    {
3040
        $extraField = new ExtraField('course');
3041
        $params = [
3042
            'variable' => $variable,
3043
            'value_type' => $fieldType,
3044
            'display_text' => $displayText,
3045
            'default_value' => $default,
3046
        ];
3047
3048
        return $extraField->save($params);
3049
    }
3050
3051
    /**
3052
     * Update course attributes. Will only update attributes with a non-empty value.
3053
     * Note that you NEED to check that your attributes are valid before using this function.
3054
     *
3055
     * @param int Course id
3056
     * @param array Associative array with field names as keys and field values as values
3057
     *
3058
     * @return Doctrine\DBAL\Driver\Statement|null True if update was successful, false otherwise
3059
     */
3060
    public static function update_attributes($id, $attributes)
3061
    {
3062
        $id = (int) $id;
3063
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3064
        $sql = "UPDATE $table SET ";
3065
        $i = 0;
3066
        foreach ($attributes as $name => $value) {
3067
            if ('' != $value) {
3068
                if ($i > 0) {
3069
                    $sql .= ", ";
3070
                }
3071
                $sql .= " $name = '".Database::escape_string($value)."'";
3072
                $i++;
3073
            }
3074
        }
3075
        $sql .= " WHERE id = $id";
3076
3077
        return Database::query($sql);
3078
    }
3079
3080
    /**
3081
     * Update an extra field value for a given course.
3082
     *
3083
     * @param string $course_code Course code
3084
     * @param string $variable    Field variable name
3085
     * @param string $value       Optional. Default field value
3086
     *
3087
     * @return bool|int An integer when register a new extra field. And boolean when update the extrafield
3088
     */
3089
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
3090
    {
3091
        $courseInfo = api_get_course_info($course_code);
3092
        $courseId = $courseInfo['real_id'];
3093
3094
        $extraFieldValues = new ExtraFieldValue('course');
3095
        $params = [
3096
            'item_id' => $courseId,
3097
            'variable' => $variable,
3098
            'value' => $value,
3099
        ];
3100
3101
        return $extraFieldValues->save($params);
3102
    }
3103
3104
    /**
3105
     * @param int $sessionId
3106
     *
3107
     * @return mixed
3108
     */
3109
    public static function get_session_category_id_by_session_id($sessionId)
3110
    {
3111
        if (empty($sessionId)) {
3112
            return [];
3113
        }
3114
        $sessionId = intval($sessionId);
3115
        $sql = 'SELECT sc.id session_category
3116
                FROM '.Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY).' sc
3117
                INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION).' s
3118
                ON sc.id = s.session_category_id
3119
                WHERE s.id = '.$sessionId;
3120
3121
        return Database::result(
3122
            Database::query($sql),
3123
            0,
3124
            'session_category'
3125
        );
3126
    }
3127
3128
    /**
3129
     * Gets the value of a course extra field. Returns null if it was not found.
3130
     *
3131
     * @param string $variable Name of the extra field
3132
     * @param string $code     Course code
3133
     *
3134
     * @return string Value
3135
     */
3136
    public static function get_course_extra_field_value($variable, $code)
3137
    {
3138
        $courseInfo = api_get_course_info($code);
3139
        $courseId = $courseInfo['real_id'];
3140
3141
        $extraFieldValues = new ExtraFieldValue('course');
3142
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($courseId, $variable);
3143
        if (!empty($result['value'])) {
3144
            return $result['value'];
3145
        }
3146
3147
        return null;
3148
    }
3149
3150
    /**
3151
     * Gets extra field value data and formatted values of a course
3152
     * for extra fields listed in configuration.php in my_course_course_extrafields_to_be_presented
3153
     * (array of variables as value of key 'fields').
3154
     *
3155
     * @param $courseId  int The numeric identifier of the course
3156
     *
3157
     * @return array of data and formatted values as returned by ExtraField::getDataAndFormattedValues
3158
     */
3159
    public static function getExtraFieldsToBePresented($courseId)
3160
    {
3161
        $extraFields = [];
3162
        $fields = api_get_configuration_sub_value('my_course_course_extrafields_to_be_presented/fields');
3163
        if (!empty($fields) && is_array($fields)) {
3164
            $extraFieldManager = new ExtraField('course');
3165
            $dataAndFormattedValues = $extraFieldManager->getDataAndFormattedValues($courseId);
3166
            foreach ($fields as $variable) {
3167
                foreach ($dataAndFormattedValues as $value) {
3168
                    if ($value['variable'] === $variable && !empty($value['value'])) {
3169
                        $extraFields[] = $value;
3170
                    }
3171
                }
3172
            }
3173
        }
3174
3175
        return $extraFields;
3176
    }
3177
3178
    /**
3179
     * Lists details of the course description.
3180
     *
3181
     * @param array        The course description
3182
     * @param string    The encoding
3183
     * @param bool        If true is displayed if false is hidden
3184
     *
3185
     * @return string The course description in html
3186
     */
3187
    public static function get_details_course_description_html(
3188
        $descriptions,
3189
        $charset,
3190
        $action_show = true
3191
    ) {
3192
        $data = null;
3193
        if (isset($descriptions) && count($descriptions) > 0) {
3194
            foreach ($descriptions as $description) {
3195
                $data .= '<div class="sectiontitle">';
3196
                if (api_is_allowed_to_edit() && $action_show) {
3197
                    //delete
3198
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=delete&description_id='.$description->id.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(
3199
                        get_lang('Please confirm your choice'),
3200
                                ENT_QUOTES,
3201
                        $charset
3202
                    )).'\')) return false;">';
3203
                    $data .= Display::getMdiIcon(
3204
                        ActionIcon::DELETE,
3205
                        'ch-tool-icon',
3206
                        'vertical-align:middle;float:right;',
3207
                        ICON_SIZE_SMALL,
3208
                        get_lang('Delete')
3209
                    );
3210
                    $data .= '</a> ';
3211
                    //edit
3212
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&description_id='.$description->id.'">';
3213
                    $data .= Display::getMdiIcon(
3214
                        ActionIcon::EDIT,
3215
                        'ch-tool-icon',
3216
                        'vertical-align:middle;float:right; padding-right:4px;',
3217
                        ICON_SIZE_SMALL,
3218
                        get_lang('Edit')
3219
                    );
3220
                    $data .= '</a> ';
3221
                }
3222
                $data .= $description->title;
3223
                $data .= '</div>';
3224
                $data .= '<div class="sectioncomment">';
3225
                $data .= Security::remove_XSS($description->content);
3226
                $data .= '</div>';
3227
            }
3228
        } else {
3229
            $data .= '<em>'.get_lang('There is no course description so far.').'</em>';
3230
        }
3231
3232
        return $data;
3233
    }
3234
3235
    /**
3236
     * Returns the details of a course category.
3237
     *
3238
     * @param string $code Category code
3239
     *
3240
     * @return array Course category
3241
     */
3242
    public static function get_course_category($code)
3243
    {
3244
        $table = Database::get_main_table(TABLE_MAIN_CATEGORY);
3245
        $code = Database::escape_string($code);
3246
        $sql = "SELECT * FROM $table WHERE code = '$code'";
3247
3248
        return Database::fetch_array(Database::query($sql));
3249
    }
3250
3251
    /**
3252
     * Subscribes courses to human resource manager (Dashboard feature).
3253
     *
3254
     * @param int   $hr_manager_id Human Resource Manager id
3255
     * @param array $courses_list  Courses code
3256
     *
3257
     * @return int
3258
     */
3259
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
3260
    {
3261
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3262
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3263
3264
        $hr_manager_id = intval($hr_manager_id);
3265
        $affected_rows = 0;
3266
3267
        //Deleting assigned courses to hrm_id
3268
        if (api_is_multiple_url_enabled()) {
3269
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
3270
                    INNER JOIN $tbl_course_rel_access_url a
3271
                    ON (a.c_id = s.c_id)
3272
                    WHERE
3273
                        user_id = $hr_manager_id AND
3274
                        relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
3275
                        access_url_id = ".api_get_current_access_url_id();
3276
        } else {
3277
            $sql = "SELECT c_id FROM $tbl_course_rel_user
3278
                    WHERE user_id = $hr_manager_id AND relation_type = ".COURSE_RELATION_TYPE_RRHH;
3279
        }
3280
        $result = Database::query($sql);
3281
        if (Database::num_rows($result) > 0) {
3282
            while ($row = Database::fetch_array($result)) {
3283
                $sql = "DELETE FROM $tbl_course_rel_user
3284
                        WHERE
3285
                            c_id = {$row['c_id']} AND
3286
                            user_id = $hr_manager_id AND
3287
                            relation_type = ".COURSE_RELATION_TYPE_RRHH;
3288
                Database::query($sql);
3289
            }
3290
        }
3291
3292
        // inserting new courses list
3293
        if (is_array($courses_list)) {
3294
            foreach ($courses_list as $course_code) {
3295
                $courseInfo = api_get_course_info($course_code);
3296
                $courseId = $courseInfo['real_id'];
3297
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
3298
                        VALUES($courseId, $hr_manager_id, ".DRH.", ".COURSE_RELATION_TYPE_RRHH.")";
3299
                $result = Database::query($sql);
3300
                if (Database::affected_rows($result)) {
3301
                    $affected_rows++;
3302
                }
3303
            }
3304
        }
3305
3306
        return $affected_rows;
3307
    }
3308
3309
    /**
3310
     * get courses followed by human resources manager.
3311
     *
3312
     * @param int    $user_id
3313
     * @param int    $status
3314
     * @param int    $from
3315
     * @param int    $limit
3316
     * @param string $column
3317
     * @param string $direction
3318
     * @param bool   $getCount
3319
     *
3320
     * @return array courses
3321
     */
3322
    public static function get_courses_followed_by_drh(
3323
        $user_id,
3324
        $status = DRH,
3325
        $from = null,
3326
        $limit = null,
3327
        $column = null,
3328
        $direction = null,
3329
        $getCount = false
3330
    ) {
3331
        return self::getCoursesFollowedByUser(
3332
            $user_id,
3333
            $status,
3334
            $from,
3335
            $limit,
3336
            $column,
3337
            $direction,
3338
            $getCount
3339
        );
3340
    }
3341
3342
    /**
3343
     * get courses followed by user.
3344
     *
3345
     * @param int    $user_id
3346
     * @param int    $status
3347
     * @param int    $from
3348
     * @param int    $limit
3349
     * @param string $column
3350
     * @param string $direction
3351
     * @param bool   $getCount
3352
     * @param string $keyword
3353
     * @param int    $sessionId
3354
     * @param bool   $showAllAssignedCourses
3355
     *
3356
     * @return array courses
3357
     */
3358
    public static function getCoursesFollowedByUser(
3359
        $user_id,
3360
        $status = null,
3361
        $from = null,
3362
        $limit = null,
3363
        $column = null,
3364
        $direction = null,
3365
        $getCount = false,
3366
        $keyword = null,
3367
        $sessionId = 0,
3368
        $showAllAssignedCourses = false
3369
    ) {
3370
        // Database Table Definitions
3371
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3372
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3373
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3374
        $sessionId = (int) $sessionId;
3375
        $user_id = (int) $user_id;
3376
        $select = "SELECT DISTINCT c.*, c.id as real_id ";
3377
3378
        if ($getCount) {
3379
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3380
        }
3381
3382
        $whereConditions = '';
3383
        switch ($status) {
3384
            case COURSEMANAGER:
3385
                $whereConditions .= " AND cru.user_id = $user_id";
3386
                if (!$showAllAssignedCourses) {
3387
                    $whereConditions .= " AND cru.status = ".COURSEMANAGER;
3388
                } else {
3389
                    $whereConditions .= " AND relation_type = ".COURSE_RELATION_TYPE_COURSE_MANAGER;
3390
                }
3391
                break;
3392
            case DRH:
3393
                $whereConditions .= " AND
3394
                    cru.user_id = $user_id AND
3395
                    cru.status = ".DRH." AND
3396
                    relation_type = '".COURSE_RELATION_TYPE_RRHH."'
3397
                ";
3398
                break;
3399
        }
3400
3401
        $keywordCondition = null;
3402
        if (!empty($keyword)) {
3403
            $keyword = Database::escape_string($keyword);
3404
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3405
        }
3406
3407
        $orderBy = null;
3408
        $extraInnerJoin = null;
3409
3410
        if (!empty($sessionId)) {
3411
            if (COURSEMANAGER == $status) {
3412
                // Teacher of course or teacher inside session
3413
                $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = ".SessionEntity::COURSE_COACH.") ";
3414
            }
3415
            $courseList = SessionManager::get_course_list_by_session_id($sessionId);
3416
            if (!empty($courseList)) {
3417
                $courseListToString = implode("','", array_keys($courseList));
3418
                $whereConditions .= " AND c.id IN ('".$courseListToString."')";
3419
            }
3420
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3421
            $tableSessionRelCourseRelUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3422
            $orderBy = ' ORDER BY position';
3423
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3424
                                ON (c.id = src.c_id AND src.session_id = $sessionId)
3425
                                INNER JOIN $tableSessionRelCourseRelUser srcru
3426
                                ON (src.session_id = srcru.session_id AND srcru.c_id = src.c_id)
3427
                            ";
3428
        }
3429
3430
        $whereConditions .= $keywordCondition;
3431
        $sql = "$select
3432
                FROM $tbl_course c
3433
                INNER JOIN $tbl_course_rel_user cru
3434
                ON (cru.c_id = c.id)
3435
                INNER JOIN $tbl_course_rel_access_url a
3436
                ON (a.c_id = c.id)
3437
                $extraInnerJoin
3438
                WHERE
3439
                    access_url_id = ".api_get_current_access_url_id()."
3440
                    $whereConditions
3441
                $orderBy
3442
                ";
3443
        if (isset($from) && isset($limit)) {
3444
            $from = intval($from);
3445
            $limit = intval($limit);
3446
            $sql .= " LIMIT $from, $limit";
3447
        }
3448
3449
        $result = Database::query($sql);
3450
3451
        if ($getCount) {
3452
            $row = Database::fetch_array($result);
3453
3454
            return $row['count'];
3455
        }
3456
3457
        $courses = [];
3458
        if (Database::num_rows($result) > 0) {
3459
            while ($row = Database::fetch_array($result)) {
3460
                $courses[$row['code']] = $row;
3461
            }
3462
        }
3463
3464
        return $courses;
3465
    }
3466
3467
    /**
3468
     * check if a course is special (autoregister).
3469
     *
3470
     * @param int $courseId
3471
     *
3472
     * @return bool
3473
     */
3474
    public static function isSpecialCourse($courseId)
3475
    {
3476
        $extraFieldValue = new ExtraFieldValue('course');
3477
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3478
            $courseId,
3479
            'special_course'
3480
        );
3481
3482
        if (!empty($result)) {
3483
            if (1 == $result['field_value']) {
3484
                return true;
3485
            }
3486
        }
3487
3488
        return false;
3489
    }
3490
3491
    /**
3492
     * Display special courses (and only these) as several HTML divs of class userportal-course-item.
3493
     *
3494
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3495
     * in the sense that any user clicking them is registered as a student
3496
     *
3497
     * @param int  $user_id                          User id
3498
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3499
     * @param bool $useUserLanguageFilterIfAvailable
3500
     *
3501
     * @return array
3502
     */
3503
    public static function returnSpecialCourses(
3504
        $user_id,
3505
        $load_dirs = false,
3506
        $useUserLanguageFilterIfAvailable = true
3507
    ) {
3508
        $user_id = (int) $user_id;
3509
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3510
        $specialCourseList = self::get_special_course_list();
3511
3512
        if (empty($specialCourseList)) {
3513
            return [];
3514
        }
3515
3516
        // Filter by language
3517
        $languageCondition = '';
3518
        $onlyInUserLanguage = ('true' === api_get_setting('course.my_courses_show_courses_in_user_language_only'));
3519
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3520
            $userInfo = api_get_user_info(api_get_user_id());
3521
            if (!empty($userInfo['language'])) {
3522
                $languageCondition = " AND course_language = '".$userInfo['language']."' ";
3523
            }
3524
        }
3525
3526
        $sql = "SELECT
3527
                    id,
3528
                    code,
3529
                    subscribe subscr,
3530
                    unsubscribe unsubscr
3531
                FROM $table
3532
                WHERE
3533
                    id IN ('".implode("','", $specialCourseList)."')
3534
                    $languageCondition
3535
                GROUP BY code";
3536
3537
        $rs_special_course = Database::query($sql);
3538
        $number_of_courses = Database::num_rows($rs_special_course);
3539
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3540
3541
        $courseList = [];
3542
        if ($number_of_courses > 0) {
3543
            while ($course = Database::fetch_array($rs_special_course)) {
3544
                $course_info = api_get_course_info($course['code']);
3545
                $courseId = $course['id'];
3546
                if (Course::HIDDEN == $course_info['visibility']) {
3547
                    continue;
3548
                }
3549
3550
                $params = [];
3551
                $params['c_id'] = $courseId;
3552
                //Param (course_code) needed to get the student info in page "My courses"
3553
                $params['course_code'] = $course['code'];
3554
                $params['code'] = $course['code'];
3555
                // Get notifications.
3556
                $course_info['id_session'] = null;
3557
                $courseUserInfo = self::getUserCourseInfo($user_id, $courseId);
3558
3559
                if (empty($courseUserInfo)) {
3560
                    $course_info['status'] = STUDENT;
3561
                } else {
3562
                    $course_info['status'] = $courseUserInfo['status'];
3563
                }
3564
3565
                $params['edit_actions'] = '';
3566
                $params['document'] = '';
3567
                if (api_is_platform_admin()) {
3568
                    $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'];
3569
                    if ($load_dirs) {
3570
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn--secondary-outline btn-sm" href="javascript:void(0);">'
3571
                           .Display::getMdiIcon('folder-open-outline').'</a>';
3572
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3573
                    }
3574
                } else {
3575
                    if (Course::CLOSED != $course_info['visibility'] && $load_dirs) {
3576
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn--secondary-outline btn-sm" href="javascript:void(0);">'
3577
                           .Display::getMdiIcon('folder-open-outline').'</a>';
3578
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3579
                    }
3580
                }
3581
3582
                $params['visibility'] = $course_info['visibility'];
3583
                $params['status'] = $course_info['status'];
3584
                $params['category'] = $course_info['categoryName'];
3585
                $params['category_code'] = $course_info['categoryCode'];
3586
                $params['icon'] = Display::getMdiIcon(
3587
                    ObjectIcon::PIN,
3588
                    'ch-tool-icon',
3589
                    null,
3590
                    ICON_SIZE_LARGE
3591
                );
3592
3593
                if ('true' == api_get_setting('display_coursecode_in_courselist')) {
3594
                    $params['code_course'] = '('.$course_info['visual_code'].')';
3595
                }
3596
3597
                $params['title'] = $course_info['title'];
3598
                $params['title_cut'] = $course_info['title'];
3599
                $params['link'] = $course_info['course_public_url'].'?sid=0&autoreg=1';
3600
                if ('true' === api_get_setting('display_teacher_in_courselist')) {
3601
                    $params['teachers'] = self::getTeachersFromCourse(
3602
                        $courseId,
3603
                        true
3604
                    );
3605
                }
3606
3607
                $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3608
3609
                if ('true' === $showCustomIcon) {
3610
                    $params['thumbnails'] = $course_info['course_image'];
3611
                    $params['image'] = $course_info['course_image_large'];
3612
                }
3613
3614
                $params['is_special_course'] = true;
3615
                $courseList[] = $params;
3616
            }
3617
        }
3618
3619
        return $courseList;
3620
    }
3621
3622
    /**
3623
     *  Display courses inside a category (without special courses) as HTML dics of
3624
     *  class userportal-course-item.
3625
     *
3626
     * @param int  $user_category_id                 User category id
3627
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3628
     * @param int  $user_id
3629
     * @param bool $useUserLanguageFilterIfAvailable
3630
     *
3631
     * @return array
3632
     */
3633
    public static function returnCoursesCategories(
3634
        $user_category_id,
3635
        $load_dirs = false,
3636
        $user_id = 0,
3637
        $useUserLanguageFilterIfAvailable = true
3638
    ) {
3639
        $user_id = $user_id ? (int) $user_id : api_get_user_id();
3640
        $user_category_id = (int) $user_category_id;
3641
3642
        // Table definitions
3643
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
3644
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3645
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3646
        $current_url_id = api_get_current_access_url_id();
3647
3648
        // Get course list auto-register
3649
        $special_course_list = self::get_special_course_list();
3650
        $without_special_courses = '';
3651
        if (!empty($special_course_list)) {
3652
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
3653
        }
3654
3655
        $userCategoryCondition = " (course_rel_user.user_course_cat = $user_category_id) ";
3656
        if (empty($user_category_id)) {
3657
            $userCategoryCondition = ' (course_rel_user.user_course_cat = 0 OR course_rel_user.user_course_cat IS NULL) ';
3658
        }
3659
3660
        $languageCondition = '';
3661
        $onlyInUserLanguage = ('true' === api_get_setting('course.my_courses_show_courses_in_user_language_only'));
3662
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3663
            $userInfo = api_get_user_info(api_get_user_id());
3664
            if (!empty($userInfo['language'])) {
3665
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
3666
            }
3667
        }
3668
3669
        $sql = "SELECT DISTINCT
3670
                    course.id,
3671
                    course_rel_user.status status,
3672
                    course.code as course_code,
3673
                    user_course_cat,
3674
                    course_rel_user.sort
3675
                FROM $TABLECOURS course
3676
                INNER JOIN $TABLECOURSUSER course_rel_user
3677
                ON (course.id = course_rel_user.c_id)
3678
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
3679
                ON (url.c_id = course.id)
3680
                WHERE
3681
                    course_rel_user.user_id = $user_id AND
3682
                    $userCategoryCondition
3683
                    $without_special_courses
3684
                    $languageCondition
3685
                ";
3686
        // If multiple URL access mode is enabled, only fetch courses
3687
        // corresponding to the current URL.
3688
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
3689
            $sql .= " AND access_url_id = $current_url_id";
3690
        }
3691
        // Use user's classification for courses (if any).
3692
        $sql .= ' ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC';
3693
        $result = Database::query($sql);
3694
3695
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3696
        // Browse through all courses.
3697
        $courseAdded = [];
3698
        $courseList = [];
3699
3700
        while ($row = Database::fetch_array($result)) {
3701
            $course_info = api_get_course_info_by_id($row['id']);
3702
            if (empty($course_info)) {
3703
                continue;
3704
            }
3705
3706
            if (isset($course_info['visibility']) &&
3707
                Course::HIDDEN == $course_info['visibility']
3708
            ) {
3709
                continue;
3710
            }
3711
3712
            // Skip if already in list
3713
            if (in_array($course_info['real_id'], $courseAdded)) {
3714
                continue;
3715
            }
3716
            $course_info['id_session'] = null;
3717
            $course_info['status'] = $row['status'];
3718
            $iconName = basename($course_info['course_image']);
3719
3720
            $params = [];
3721
            //Param (course_code) needed to get the student process
3722
            $params['course_code'] = $row['course_code'];
3723
            $params['code'] = $row['course_code'];
3724
3725
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3726
                $params['thumbnails'] = $course_info['course_image'];
3727
                $params['image'] = $course_info['course_image_large'];
3728
            }
3729
3730
            $thumbnails = null;
3731
            $image = null;
3732
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3733
                $thumbnails = $course_info['course_image'];
3734
                $image = $course_info['course_image_large'];
3735
            } else {
3736
                $image = Display::return_icon(
3737
                    'session_default.png',
3738
                    null,
3739
                    null,
3740
                    null,
3741
                    null,
3742
                    true
3743
                );
3744
            }
3745
3746
            $params['course_id'] = $course_info['real_id'];
3747
            $params['edit_actions'] = '';
3748
            $params['document'] = '';
3749
            if (api_is_platform_admin()) {
3750
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course_info['real_id'];
3751
                if ($load_dirs) {
3752
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn--plain btn-sm" href="javascript:void(0);">'
3753
                               .Display::getMdiIcon('folder-open-outline').'</a>';
3754
                    $params['document'] .= Display::div(
3755
                        '',
3756
                        [
3757
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
3758
                            'class' => 'document_preview_container',
3759
                        ]
3760
                    );
3761
                }
3762
            }
3763
            if ($load_dirs) {
3764
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn--plain btn-sm" href="javascript:void(0);">'
3765
                    .Display::getMdiIcon('folder-open-outline').'</a>';
3766
                $params['document'] .= Display::div(
3767
                    '',
3768
                    [
3769
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
3770
                        'class' => 'document_preview_container',
3771
                    ]
3772
                );
3773
            }
3774
3775
            $courseUrl = $course_info['course_public_url'].'?sid=0';
3776
            $teachers = [];
3777
            if ('true' === api_get_setting('display_teacher_in_courselist')) {
3778
                $teachers = self::getTeachersFromCourse(
3779
                    $course_info['real_id'],
3780
                    true
3781
                );
3782
            }
3783
3784
            $params['status'] = $row['status'];
3785
            if ('true' === api_get_setting('display_coursecode_in_courselist')) {
3786
                $params['code_course'] = '('.$course_info['visual_code'].') ';
3787
            }
3788
3789
            $params['current_user_is_teacher'] = false;
3790
            /** @var array $teacher */
3791
            foreach ($teachers as $teacher) {
3792
                if ($teacher['id'] != $user_id) {
3793
                    continue;
3794
                }
3795
                $params['current_user_is_teacher'] = true;
3796
            }
3797
3798
            $params['visibility'] = $course_info['visibility'];
3799
            $params['link'] = $courseUrl;
3800
            $params['thumbnails'] = $thumbnails;
3801
            $params['image'] = $image;
3802
            $params['title'] = $course_info['title'];
3803
            $params['title_cut'] = $params['title'];
3804
            $params['category'] = $course_info['categoryName'];
3805
            $params['category_code'] = $course_info['categoryCode'];
3806
            $params['teachers'] = $teachers;
3807
            $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3808
            $params['real_id'] = $course_info['real_id'];
3809
3810
            if ('true' === api_get_setting('course.enable_unsubscribe_button_on_my_course_page')
3811
                && '1' === $course_info['unsubscribe']
3812
            ) {
3813
                $params['unregister_button'] = CoursesAndSessionsCatalog::return_unregister_button(
3814
                    $course_info,
3815
                    Security::get_existing_token(),
3816
                    '',
3817
                    ''
3818
                );
3819
            }
3820
3821
            $courseAdded[] = $course_info['real_id'];
3822
            $courseList[] = $params;
3823
        }
3824
3825
        return $courseList;
3826
    }
3827
3828
    /**
3829
     * Get the course id based on the original id and field name in the extra fields.
3830
     * Returns 0 if course was not found.
3831
     *
3832
     * @param string $value    Original course code
3833
     * @param string $variable Original field name
3834
     *
3835
     * @return array
3836
     */
3837
    public static function getCourseInfoFromOriginalId($value, $variable)
3838
    {
3839
        $extraFieldValue = new ExtraFieldValue('course');
3840
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
3841
            $variable,
3842
            $value
3843
        );
3844
3845
        if (!empty($result)) {
3846
            return api_get_course_info_by_id($result['item_id']);
3847
        }
3848
3849
        return [];
3850
    }
3851
3852
    /**
3853
     * Display code for one specific course a logged in user is subscribed to.
3854
     * Shows a link to the course, what's new icons...
3855
     *
3856
     * $my_course['d'] - course directory
3857
     * $my_course['i'] - course title
3858
     * $my_course['c'] - visual course code
3859
     * $my_course['k']  - system course code
3860
     *
3861
     * @param   array       Course details
3862
     * @param   int     Session ID
3863
     * @param   string      CSS class to apply to course entry
3864
     * @param   bool     Whether the session is supposedly accessible now
3865
     * (not in the case it has passed and is in invisible/unaccessible mode)
3866
     * @param bool      Whether to show the document quick-loader or not
3867
     *
3868
     * @return string The HTML to be printed for the course entry
3869
     *
3870
     * @version 1.0.3
3871
     *
3872
     * @todo refactor into different functions for database calls | logic | display
3873
     * @todo replace single-character $my_course['d'] indices
3874
     * @todo move code for what's new icons to a separate function to clear things up
3875
     * @todo add a parameter user_id so that it is possible to show the
3876
     * courselist of other users (=generalisation).
3877
     * This will prevent having to write a new function for this.
3878
     */
3879
    public static function get_logged_user_course_html(
3880
        $course,
3881
        $session_id = 0,
3882
        $class = 'courses',
3883
        $session_accessible = true,
3884
        $load_dirs = false
3885
    ) {
3886
        $now = date('Y-m-d h:i:s');
3887
        $user_id = api_get_user_id();
3888
        $course_info = api_get_course_info_by_id($course['real_id']);
3889
        $course_visibility = (int) $course_info['visibility'];
3890
        $allowUnsubscribe = ('true' === api_get_setting('course.enable_unsubscribe_button_on_my_course_page'));
3891
3892
        if (Course::HIDDEN === $course_visibility) {
3893
            return '';
3894
        }
3895
3896
        $sessionInfo = [];
3897
        if (!empty($session_id)) {
3898
            $sessionInfo = api_get_session_info($session_id);
3899
        }
3900
        $userInCourseStatus = self::getUserInCourseStatus($user_id, $course_info['real_id']);
3901
        $course_info['status'] = empty($session_id) ? $userInCourseStatus : STUDENT;
3902
        $course_info['id_session'] = $session_id;
3903
3904
        $is_coach = api_is_coach($session_id, $course_info['real_id']);
3905
        $isAdmin = api_is_platform_admin();
3906
3907
        // Display course entry.
3908
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
3909
        $session_url = '';
3910
        $params = [];
3911
        $params['icon'] = Display::getMdiIcon(
3912
            ObjectIcon::SESSION,
3913
            'ch-tool-icon',
3914
            null,
3915
            ICON_SIZE_LARGE
3916
        );
3917
        $params['real_id'] = $course_info['real_id'];
3918
        $params['visibility'] = $course_info['visibility'];
3919
3920
        $sessionCourseAvailable = false;
3921
        if ($session_accessible) {
3922
            if (Course::CLOSED != $course_visibility ||
3923
                COURSEMANAGER == $userInCourseStatus
3924
            ) {
3925
                if (empty($course_info['id_session'])) {
3926
                    $course_info['id_session'] = 0;
3927
                }
3928
3929
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
3930
3931
                if (in_array(
3932
                    $sessionCourseStatus,
3933
                    [SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE]
3934
                )) {
3935
                    $sessionCourseAvailable = true;
3936
                }
3937
3938
                if (COURSEMANAGER === $userInCourseStatus || $sessionCourseAvailable) {
3939
                    $session_url = $course_info['course_public_url'].'?sid='.$course_info['id_session'];
3940
                    $session_title = '<a title="'.$course_info['name'].'" href="'.$session_url.'">'.
3941
                        $course_info['name'].'</a>';
3942
                } else {
3943
                    $session_title = $course_info['name'];
3944
                }
3945
            } else {
3946
                $session_title =
3947
                    $course_info['name'].' '.
3948
                    Display::tag('span', get_lang('(the course is currently closed)'), ['class' => 'item_closed']);
3949
            }
3950
        } else {
3951
            $session_title = $course_info['name'];
3952
        }
3953
3954
        $thumbnails = null;
3955
        $image = null;
3956
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3957
        $iconName = basename($course_info['course_image']);
3958
3959
        if ('true' === $showCustomIcon && 'course.png' != $iconName) {
3960
            $thumbnails = $course_info['course_image'];
3961
            $image = $course_info['course_image_large'];
3962
        } else {
3963
            $image = Display::return_icon(
3964
                'session_default.png',
3965
                null,
3966
                null,
3967
                null,
3968
                null,
3969
                true
3970
            );
3971
        }
3972
        $params['thumbnails'] = $thumbnails;
3973
        $params['image'] = $image;
3974
        $params['html_image'] = '';
3975
        if (!empty($thumbnails)) {
3976
            $params['html_image'] = Display::img($thumbnails, $course_info['name'], ['class' => 'img-responsive']);
3977
        } else {
3978
            $params['html_image'] = Display::getMdiIcon(
3979
                ObjectIcon::SESSION,
3980
                'ch-tool-icon img-responsive',
3981
                null,
3982
                ICON_SIZE_LARGE,
3983
                $course_info['name']
3984
            );
3985
        }
3986
        $params['link'] = $session_url;
3987
        $entityManager = Database::getManager();
3988
        /** @var SequenceResourceRepository $repo */
3989
        $repo = $entityManager->getRepository(SequenceResource::class);
3990
3991
        $sequences = $repo->getRequirements($course_info['real_id'], SequenceResource::COURSE_TYPE);
3992
        $sequenceList = $repo->checkRequirementsForUser(
3993
            $sequences,
3994
            SequenceResource::COURSE_TYPE,
3995
            $user_id,
3996
            $session_id
3997
        );
3998
        $completed = $repo->checkSequenceAreCompleted($sequenceList);
3999
        //var_dump($course_info['real_id'], $completed);
4000
        $params['completed'] = $completed;
4001
        $params['requirements'] = '';
4002
4003
        if ($isAdmin ||
4004
            COURSEMANAGER === $userInCourseStatus ||
4005
            $is_coach ||
4006
            SessionManager::sessionHasSessionAdmin($session_id, $user_id)
4007
        ) {
4008
            $params['completed'] = true;
4009
            $params['requirements'] = '';
4010
        } else {
4011
            if ($sequences && false === $completed) {
4012
                $hasRequirements = false;
4013
                foreach ($sequences as $sequence) {
4014
                    if (!empty($sequence['requirements'])) {
4015
                        $hasRequirements = true;
4016
                        break;
4017
                    }
4018
                }
4019
                if ($hasRequirements) {
4020
                    $params['requirements'] = CoursesAndSessionsCatalog::getRequirements(
4021
                    $course_info['real_id'],
4022
                    SequenceResource::COURSE_TYPE,
4023
                    false,
4024
                        false,
4025
                        $session_id
4026
                );
4027
                }
4028
            }
4029
        }
4030
4031
        $params['title'] = $session_title;
4032
        $params['name'] = $course_info['name'];
4033
        $params['edit_actions'] = '';
4034
        $params['document'] = '';
4035
        $params['category'] = $course_info['categoryName'];
4036
        if (Course::CLOSED != $course_visibility &&
4037
            false === $is_coach && $allowUnsubscribe && '1' === $course_info['unsubscribe']) {
4038
            $params['unregister_button'] =
4039
                CoursesAndSessionsCatalog::return_unregister_button(
4040
                    ['code' => $course_info['code']],
4041
                    Security::get_existing_token(),
4042
                    '',
4043
                    '',
4044
                    $session_id
4045
                );
4046
        }
4047
4048
        if (Course::CLOSED != $course_visibility &&
4049
            Course::HIDDEN != $course_visibility
4050
        ) {
4051
            if ($isAdmin) {
4052
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4053
                if ($load_dirs) {
4054
                    $params['document'] .= '<a
4055
                        id="document_preview_'.$course_info['real_id'].'_'.$session_id.'"
4056
                        class="document_preview btn btn--plain btn-sm"
4057
                        href="javascript:void(0);">'.
4058
                        Display::getMdiIcon('folder-open-outline').'</a>';
4059
                    $params['document'] .= Display::div('', [
4060
                        'id' => 'document_result_'.$course_info['real_id'].'_'.$session_id,
4061
                        'class' => 'document_preview_container',
4062
                    ]);
4063
                }
4064
            }
4065
        }
4066
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
4067
            $teacher_list = self::getTeachersFromCourse($course_info['real_id'], true);
4068
            $course_coachs = self::get_coachs_from_course(
4069
                $session_id,
4070
                $course_info['real_id'],
4071
                true
4072
            );
4073
            $params['teachers'] = $teacher_list;
4074
4075
            if ((STUDENT == $course_info['status'] && !empty($session_id)) ||
4076
                ($is_coach && COURSEMANAGER != $course_info['status'])
4077
            ) {
4078
                $params['coaches'] = $course_coachs;
4079
            }
4080
        }
4081
        $special = isset($course['special_course']) ? true : false;
4082
        $params['title'] = $session_title;
4083
        $params['special'] = $special;
4084
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
4085
            $params['visual_code'] = '('.$course_info['visual_code'].')';
4086
        }
4087
        $params['extra'] = '';
4088
        $html = $params;
4089
4090
        $session_category_id = null;
4091
        $active = false;
4092
        if (!empty($session_id)) {
4093
            $sessionCoachName = implode(
4094
                ' - ',
4095
                SessionManager::getGeneralCoachesNamesForSession($session_id)
4096
            );
4097
4098
            $session_category_id = self::get_session_category_id_by_session_id($course_info['id_session']);
4099
4100
            if (
4101
                '0000-00-00 00:00:00' === $sessionInfo['access_start_date'] ||
4102
                empty($sessionInfo['access_start_date']) ||
4103
                '0000-00-00' === $sessionInfo['access_start_date']
4104
                ) {
4105
                $sessionInfo['dates'] = '';
4106
                if ('true' === api_get_setting('show_session_coach')) {
4107
                    $sessionInfo['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4108
                }
4109
                $active = true;
4110
            } else {
4111
                $sessionInfo['dates'] = ' - '.
4112
                    get_lang('From').' '.$sessionInfo['access_start_date'].' '.
4113
                    get_lang('To').' '.$sessionInfo['access_end_date'];
4114
                if ('true' === api_get_setting('show_session_coach')) {
4115
                    $sessionInfo['coach'] = get_lang('GeneralCoach').': '.$sessionCoachName;
4116
                }
4117
                $date_start = $sessionInfo['access_start_date'];
4118
                $date_end = $sessionInfo['access_end_date'];
4119
                $active = !$date_end ? ($date_start <= $now) : ($date_start <= $now && $date_end >= $now);
4120
            }
4121
        }
4122
        $user_course_category = '';
4123
        if (isset($course_info['user_course_cat'])) {
4124
            $user_course_category = $course_info['user_course_cat'];
4125
        }
4126
        $output = [
4127
                $user_course_category,
4128
                $html,
4129
                $course_info['id_session'],
4130
                $sessionInfo,
4131
                'active' => $active,
4132
                'session_category_id' => $session_category_id,
4133
            ];
4134
4135
        if (SkillModel::isAllowed($user_id, false)) {
4136
            $em = Database::getManager();
4137
            $objUser = api_get_user_entity($user_id);
4138
            $objCourse = api_get_course_entity($course['real_id']);
4139
            $objSession = api_get_session_entity($session_id);
4140
            $skill = $em->getRepository(\Chamilo\CoreBundle\Entity\Skill::class)->getLastByUser($objUser, $objCourse, $objSession);
4141
4142
            $output['skill'] = null;
4143
            if ($skill) {
4144
                $output['skill']['name'] = $skill->getTitle();
4145
                $output['skill']['icon'] = $skill->getIcon();
4146
            }
4147
        }
4148
4149
        return $output;
4150
    }
4151
4152
    /**
4153
     * @param string $source_course_code
4154
     * @param int    $source_session_id
4155
     * @param string $destination_course_code
4156
     * @param int    $destination_session_id
4157
     * @param array  $params
4158
     *
4159
     * @return bool
4160
     */
4161
    public static function copy_course(
4162
        $source_course_code,
4163
        $source_session_id,
4164
        $destination_course_code,
4165
        $destination_session_id,
4166
        $params = [],
4167
        $withBaseContent = true
4168
    ) {
4169
        $course_info = api_get_course_info($source_course_code);
4170
4171
        if (!empty($course_info)) {
4172
            $cb = new CourseBuilder('', $course_info);
4173
            $course = $cb->build($source_session_id, $source_course_code, $withBaseContent);
4174
            $restorer = new CourseRestorer($course);
4175
            $restorer->skip_content = $params;
4176
            $restorer->restore(
4177
                $destination_course_code,
4178
                $destination_session_id,
4179
                true,
4180
                $withBaseContent
4181
            );
4182
4183
            return true;
4184
        }
4185
4186
        return false;
4187
    }
4188
4189
    /**
4190
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code.
4191
     *
4192
     * @param string $new_title new course title
4193
     * @param string source course code
4194
     * @param int source session id
4195
     * @param int destination session id
4196
     * @param array $params
4197
     * @param bool  $copySessionContent
4198
     *
4199
     * @return Course|null
4200
     */
4201
    public static function copy_course_simple(
4202
        $new_title,
4203
        $source_course_code,
4204
        $source_session_id = 0,
4205
        $destination_session_id = 0,
4206
        $params = [],
4207
        $copySessionContent = false
4208
    ) {
4209
        $source_course_info = api_get_course_info($source_course_code);
4210
        if (!empty($source_course_info)) {
4211
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4212
            if ($new_course_code) {
4213
                $newCourse = self::create_course(
4214
                    $new_title,
4215
                    $new_course_code,
4216
                    false
4217
                );
4218
                if (null !== $newCourse) {
4219
                    $result = self::copy_course(
4220
                        $source_course_code,
4221
                        $source_session_id,
4222
                        $newCourse->getCode(),
4223
                        $destination_session_id,
4224
                        $params,
4225
                        true
4226
                    );
4227
                    if ($result) {
4228
                        return $newCourse;
4229
                    }
4230
                }
4231
            }
4232
        }
4233
4234
        return false;
4235
    }
4236
4237
    /**
4238
     * Creates a new course code based in a given code.
4239
     *
4240
     * @param string    wanted code
4241
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return:
4242
     * course3</code> if the course code doest not exist in the DB the same course code will be returned
4243
     *
4244
     * @return string wanted unused code
4245
     */
4246
    public static function generate_nice_next_course_code($wanted_code)
4247
    {
4248
        $course_code_ok = !self::course_code_exists($wanted_code);
4249
        if (!$course_code_ok) {
4250
            $wanted_code = self::generate_course_code($wanted_code);
4251
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4252
            $wanted_code = Database::escape_string($wanted_code);
4253
            $sql = "SELECT count(id) as count
4254
                    FROM $table
4255
                    WHERE code LIKE '$wanted_code%'";
4256
            $result = Database::query($sql);
4257
            if (Database::num_rows($result) > 0) {
4258
                $row = Database::fetch_array($result);
4259
                $count = $row['count'] + 1;
4260
                $wanted_code = $wanted_code.'_'.$count;
4261
                $result = api_get_course_info($wanted_code);
4262
                if (empty($result)) {
4263
                    return $wanted_code;
4264
                }
4265
            }
4266
4267
            return false;
4268
        }
4269
4270
        return $wanted_code;
4271
    }
4272
4273
    /**
4274
     * Gets the status of the users agreement in a course course-session.
4275
     *
4276
     * @param int    $user_id
4277
     * @param string $course_code
4278
     * @param int    $session_id
4279
     *
4280
     * @return bool
4281
     */
4282
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = 0)
4283
    {
4284
        $user_id = (int) $user_id;
4285
        $session_id = (int) $session_id;
4286
        $course_code = Database::escape_string($course_code);
4287
4288
        $courseInfo = api_get_course_info($course_code);
4289
        $courseId = $courseInfo['real_id'];
4290
4291
        // Course legal
4292
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4293
4294
        if ('true' == $enabled) {
4295
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4296
            $plugin = CourseLegalPlugin::create();
4297
4298
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4299
        }
4300
4301
        if (empty($session_id)) {
4302
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4303
            $sql = "SELECT legal_agreement FROM $table
4304
                    WHERE user_id = $user_id AND c_id = $courseId ";
4305
            $result = Database::query($sql);
4306
            if (Database::num_rows($result) > 0) {
4307
                $result = Database::fetch_array($result);
4308
                if (1 == $result['legal_agreement']) {
4309
                    return true;
4310
                }
4311
            }
4312
4313
            return false;
4314
        } else {
4315
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4316
            $sql = "SELECT legal_agreement FROM $table
4317
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4318
            $result = Database::query($sql);
4319
            if (Database::num_rows($result) > 0) {
4320
                $result = Database::fetch_array($result);
4321
                if (1 == $result['legal_agreement']) {
4322
                    return true;
4323
                }
4324
            }
4325
4326
            return false;
4327
        }
4328
    }
4329
4330
    /**
4331
     * Saves the user-course legal agreement.
4332
     *
4333
     * @param   int user id
4334
     * @param   string course code
4335
     * @param   int session id
4336
     *
4337
     * @return bool
4338
     */
4339
    public static function save_user_legal($user_id, $courseInfo, $session_id = 0)
4340
    {
4341
        if (empty($courseInfo)) {
4342
            return false;
4343
        }
4344
        $course_code = $courseInfo['code'];
4345
4346
        // Course plugin legal
4347
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4348
        if ('true' == $enabled) {
4349
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4350
            $plugin = CourseLegalPlugin::create();
4351
4352
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4353
        }
4354
4355
        $user_id = (int) $user_id;
4356
        $session_id = (int) $session_id;
4357
        $courseId = $courseInfo['real_id'];
4358
4359
        if (empty($session_id)) {
4360
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4361
            $sql = "UPDATE $table SET legal_agreement = '1'
4362
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4363
            Database::query($sql);
4364
        } else {
4365
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4366
            $sql = "UPDATE  $table SET legal_agreement = '1'
4367
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4368
            Database::query($sql);
4369
        }
4370
4371
        return true;
4372
    }
4373
4374
    /**
4375
     * @param int $user_id
4376
     * @param int $course_id
4377
     * @param int $session_id
4378
     * @param int $url_id
4379
     *
4380
     * @return bool
4381
     */
4382
    public static function get_user_course_vote($user_id, $course_id, $session_id = 0, $url_id = 0)
4383
    {
4384
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4385
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4386
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4387
        $user_id = intval($user_id);
4388
4389
        if (empty($user_id)) {
4390
            return false;
4391
        }
4392
4393
        $params = [
4394
            'user_id' => $user_id,
4395
            'c_id' => $course_id,
4396
            'session_id' => $session_id,
4397
            'url_id' => $url_id,
4398
        ];
4399
4400
        $result = Database::select(
4401
            'vote',
4402
            $table_user_course_vote,
4403
            [
4404
                'where' => [
4405
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params,
4406
                ],
4407
            ],
4408
            'first'
4409
        );
4410
        if (!empty($result)) {
4411
            return $result['vote'];
4412
        }
4413
4414
        return false;
4415
    }
4416
4417
    /**
4418
     * @param int $course_id
4419
     * @param int $session_id
4420
     * @param int $url_id
4421
     *
4422
     * @return array
4423
     */
4424
    public static function get_course_ranking(
4425
        $course_id,
4426
        $session_id = 0,
4427
        $url_id = 0
4428
    ) {
4429
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4430
4431
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4432
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4433
        $now = api_get_utc_datetime();
4434
4435
        $params = [
4436
            'c_id' => $course_id,
4437
            'session_id' => $session_id,
4438
            'url_id' => $url_id,
4439
            'creation_date' => $now,
4440
        ];
4441
4442
        $result = Database::select(
4443
            'c_id, accesses, total_score, users',
4444
            $table_course_ranking,
4445
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4446
            'first'
4447
        );
4448
4449
        $point_average_in_percentage = 0;
4450
        $point_average_in_star = 0;
4451
        $users_who_voted = 0;
4452
4453
        if (!empty($result['users'])) {
4454
            $users_who_voted = $result['users'];
4455
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4456
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4457
        }
4458
4459
        $result['user_vote'] = false;
4460
        if (!api_is_anonymous()) {
4461
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4462
        }
4463
4464
        $result['point_average'] = $point_average_in_percentage;
4465
        $result['point_average_star'] = $point_average_in_star;
4466
        $result['users_who_voted'] = $users_who_voted;
4467
4468
        return $result;
4469
    }
4470
4471
    /**
4472
     * Updates the course ranking.
4473
     *
4474
     * @param int   course id
4475
     * @param int $session_id
4476
     * @param int    url id
4477
     * @param $points_to_add
4478
     * @param bool $add_access
4479
     * @param bool $add_user
4480
     *
4481
     * @return array
4482
     */
4483
    public static function update_course_ranking(
4484
        $course_id = 0,
4485
        $session_id = 0,
4486
        $url_id = 0,
4487
        $points_to_add = null,
4488
        $add_access = true,
4489
        $add_user = true
4490
    ) {
4491
        // Course catalog stats modifications see #4191
4492
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4493
        $now = api_get_utc_datetime();
4494
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4495
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4496
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4497
4498
        $params = [
4499
            'c_id' => $course_id,
4500
            'session_id' => $session_id,
4501
            'url_id' => $url_id,
4502
            'creation_date' => $now,
4503
            'total_score' => 0,
4504
            'users' => 0,
4505
        ];
4506
4507
        $result = Database::select(
4508
            'id, accesses, total_score, users',
4509
            $table_course_ranking,
4510
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4511
            'first'
4512
        );
4513
4514
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4515
        if (empty($result)) {
4516
            if ($add_access) {
4517
                $params['accesses'] = 1;
4518
            }
4519
            //The votes and users are empty
4520
            if (isset($points_to_add) && !empty($points_to_add)) {
4521
                $params['total_score'] = intval($points_to_add);
4522
            }
4523
            if ($add_user) {
4524
                $params['users'] = 1;
4525
            }
4526
            $result = Database::insert($table_course_ranking, $params);
4527
        } else {
4528
            $my_params = [];
4529
4530
            if ($add_access) {
4531
                $my_params['accesses'] = intval($result['accesses']) + 1;
4532
            }
4533
            if (isset($points_to_add) && !empty($points_to_add)) {
4534
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4535
            }
4536
            if ($add_user) {
4537
                $my_params['users'] = $result['users'] + 1;
4538
            }
4539
4540
            if (!empty($my_params)) {
4541
                $result = Database::update(
4542
                    $table_course_ranking,
4543
                    $my_params,
4544
                    ['c_id = ? AND session_id = ? AND url_id = ?' => $params]
4545
                );
4546
            }
4547
        }
4548
4549
        return $result;
4550
    }
4551
4552
    /**
4553
     * Add user vote to a course.
4554
     *
4555
     * @param   int user id
4556
     * @param   int vote [1..5]
4557
     * @param   int course id
4558
     * @param   int session id
4559
     * @param   int url id (access_url_id)
4560
     *
4561
     * @return false|string 'added', 'updated' or 'nothing'
4562
     */
4563
    public static function add_course_vote(
4564
        $user_id,
4565
        $vote,
4566
        $course_id,
4567
        $session_id = 0,
4568
        $url_id = 0
4569
    ) {
4570
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4571
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4572
4573
        if (empty($course_id) || empty($user_id)) {
4574
            return false;
4575
        }
4576
4577
        if (!in_array($vote, [1, 2, 3, 4, 5])) {
4578
            return false;
4579
        }
4580
4581
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4582
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4583
        $vote = intval($vote);
4584
4585
        $params = [
4586
            'user_id' => intval($user_id),
4587
            'c_id' => $course_id,
4588
            'session_id' => $session_id,
4589
            'url_id' => $url_id,
4590
            'vote' => $vote,
4591
        ];
4592
4593
        $action_done = 'nothing';
4594
        $result = Database::select(
4595
            'id, vote',
4596
            $table_user_course_vote,
4597
            ['where' => ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4598
            'first'
4599
        );
4600
4601
        if (empty($result)) {
4602
            Database::insert($table_user_course_vote, $params);
4603
            $points_to_add = $vote;
4604
            $add_user = true;
4605
            $action_done = 'added';
4606
        } else {
4607
            $my_params = ['vote' => $vote];
4608
            $points_to_add = $vote - $result['vote'];
4609
            $add_user = false;
4610
4611
            Database::update(
4612
                $table_user_course_vote,
4613
                $my_params,
4614
                ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]
4615
            );
4616
            $action_done = 'updated';
4617
        }
4618
4619
        // Current points
4620
        if (!empty($points_to_add)) {
4621
            self::update_course_ranking(
4622
                $course_id,
4623
                $session_id,
4624
                $url_id,
4625
                $points_to_add,
4626
                false,
4627
                $add_user
4628
            );
4629
        }
4630
4631
        return $action_done;
4632
    }
4633
4634
    /**
4635
     * Remove course ranking + user votes.
4636
     *
4637
     * @param int $course_id
4638
     * @param int $session_id
4639
     * @param int $url_id
4640
     */
4641
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
4642
    {
4643
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4644
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4645
4646
        if (!empty($course_id) && isset($session_id)) {
4647
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4648
            $params = [
4649
                'c_id' => $course_id,
4650
                'session_id' => $session_id,
4651
                'url_id' => $url_id,
4652
            ];
4653
            Database::delete($table_course_ranking, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4654
            Database::delete($table_user_course_vote, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4655
        }
4656
    }
4657
4658
    /**
4659
     * Returns an array with the hottest courses.
4660
     *
4661
     * @param int $days  number of days
4662
     * @param int $limit number of hottest courses
4663
     *
4664
     * @return array
4665
     */
4666
    public static function return_hot_courses($days = 30, $limit = 6)
4667
    {
4668
        if (api_is_invitee()) {
4669
            return [];
4670
        }
4671
4672
        $limit = (int) $limit;
4673
        $userId = api_get_user_id();
4674
4675
        // Getting my courses
4676
        $my_course_list = self::get_courses_list_by_user_id($userId);
4677
4678
        $codeList = [];
4679
        foreach ($my_course_list as $course) {
4680
            $codeList[$course['real_id']] = $course['real_id'];
4681
        }
4682
4683
        if (api_is_drh()) {
4684
            $courses = self::get_courses_followed_by_drh($userId);
4685
            foreach ($courses as $course) {
4686
                $codeList[$course['real_id']] = $course['real_id'];
4687
            }
4688
        }
4689
4690
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4691
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4692
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4693
        $urlId = api_get_current_access_url_id();
4694
        //$table_course_access table uses the now() and interval ...
4695
        $now = api_get_utc_datetime();
4696
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
4697
                FROM $table_course c
4698
                INNER JOIN $table_course_access a
4699
                ON (c.id = a.c_id)
4700
                INNER JOIN $table_course_url u
4701
                ON u.c_id = c.id
4702
                WHERE
4703
                    u.access_url_id = $urlId AND
4704
                    login_course_date <= '$now' AND
4705
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
4706
                    visibility <> ".Course::CLOSED." AND
4707
                    visibility <> ".Course::HIDDEN."
4708
                GROUP BY a.c_id
4709
                ORDER BY course_count DESC
4710
                LIMIT $limit
4711
            ";
4712
4713
        $result = Database::query($sql);
4714
        $courses = [];
4715
        if (Database::num_rows($result)) {
4716
            $courses = Database::store_result($result, 'ASSOC');
4717
            $courses = self::processHotCourseItem($courses, $codeList);
4718
        }
4719
4720
        return $courses;
4721
    }
4722
4723
    /**
4724
     * Returns an array with the "hand picked" popular courses.
4725
     * Courses only appear in this list if their extra field 'popular_courses'
4726
     * has been selected in the admin page of the course.
4727
     *
4728
     * @return array
4729
     */
4730
    public static function returnPopularCoursesHandPicked()
4731
    {
4732
        if (api_is_invitee()) {
4733
            return [];
4734
        }
4735
4736
        $userId = api_get_user_id();
4737
4738
        // Getting my courses
4739
        $my_course_list = self::get_courses_list_by_user_id($userId);
4740
4741
        $codeList = [];
4742
        foreach ($my_course_list as $course) {
4743
            $codeList[$course['real_id']] = $course['real_id'];
4744
        }
4745
4746
        if (api_is_drh()) {
4747
            $courses = self::get_courses_followed_by_drh($userId);
4748
            foreach ($courses as $course) {
4749
                $codeList[$course['real_id']] = $course['real_id'];
4750
            }
4751
        }
4752
4753
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
4754
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
4755
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
4756
4757
        //we filter the courses from the URL
4758
        $join_access_url = $where_access_url = '';
4759
        if (api_get_multiple_access_url()) {
4760
            $access_url_id = api_get_current_access_url_id();
4761
            if (-1 != $access_url_id) {
4762
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4763
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
4764
                ON url_rel_course.c_id = tcfv.item_id ";
4765
                $where_access_url = " AND access_url_id = $access_url_id ";
4766
            }
4767
        }
4768
4769
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
4770
4771
        // get course list auto-register
4772
        $sql = "SELECT DISTINCT(c.id) AS c_id
4773
                FROM $tbl_course_field_value tcfv
4774
                INNER JOIN $tbl_course_field tcf
4775
                ON tcfv.field_id =  tcf.id $join_access_url
4776
                INNER JOIN $courseTable c
4777
                ON (c.id = tcfv.item_id)
4778
                WHERE
4779
                    tcf.item_type = $extraFieldType AND
4780
                    tcf.variable = 'popular_courses' AND
4781
                    tcfv.field_value = 1 AND
4782
                    visibility <> ".Course::CLOSED." AND
4783
                    visibility <> ".Course::HIDDEN." $where_access_url";
4784
4785
        $result = Database::query($sql);
4786
        $courses = [];
4787
        if (Database::num_rows($result)) {
4788
            $courses = Database::store_result($result, 'ASSOC');
4789
            $courses = self::processHotCourseItem($courses, $codeList);
4790
        }
4791
4792
        return $courses;
4793
    }
4794
4795
    /**
4796
     * @param array $courses
4797
     * @param array $codeList
4798
     *
4799
     * @return mixed
4800
     */
4801
    public static function processHotCourseItem($courses, $codeList = [])
4802
    {
4803
        $hotCourses = [];
4804
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
4805
        $stok = Security::get_existing_token();
4806
        $user_id = api_get_user_id();
4807
4808
        foreach ($courses as $courseId) {
4809
            $course_info = api_get_course_info_by_id($courseId['c_id']);
4810
            $courseCode = $course_info['code'];
4811
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
4812
            $my_course = $course_info;
4813
            $my_course['go_to_course_button'] = '';
4814
            $my_course['register_button'] = '';
4815
4816
            $access_link = self::get_access_link_by_user(
4817
                $user_id,
4818
                $course_info,
4819
                $codeList
4820
            );
4821
4822
            $userRegisteredInCourse = self::is_user_subscribed_in_course($user_id, $course_info['code']);
4823
            $userRegisteredInCourseAsTeacher = self::isCourseTeacher($user_id, $courseId['c_id']);
4824
            $userRegistered = $userRegisteredInCourse && $userRegisteredInCourseAsTeacher;
4825
            $my_course['is_course_student'] = $userRegisteredInCourse;
4826
            $my_course['is_course_teacher'] = $userRegisteredInCourseAsTeacher;
4827
            $my_course['is_registered'] = $userRegistered;
4828
            $my_course['title_cut'] = cut($course_info['title'], 45);
4829
4830
            // Course visibility
4831
            if ($access_link && in_array('register', $access_link)) {
4832
                $my_course['register_button'] = Display::url(
4833
                    get_lang('Subscribe').' '.
4834
                    Display::getMdiIcon('login'),
4835
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].
4836
                     '/index.php?action=subscribe&sec_token='.$stok,
4837
                    [
4838
                        'class' => 'btn btn--success btn-sm',
4839
                        'title' => get_lang('Subscribe'),
4840
                        'aria-label' => get_lang('Subscribe'),
4841
                    ]
4842
                );
4843
            }
4844
4845
            if ($access_link && in_array('enter', $access_link) ||
4846
                Course::OPEN_WORLD == $course_info['visibility']
4847
            ) {
4848
                $my_course['go_to_course_button'] = Display::url(
4849
                    get_lang('Go to the course').' '.
4850
                    Display::getMdiIcon('share'),
4851
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php',
4852
                    [
4853
                        'class' => 'btn btn--plain btn-sm',
4854
                        'title' => get_lang('Go to the course'),
4855
                        'aria-label' => get_lang('Go to the course'),
4856
                    ]
4857
                );
4858
            }
4859
4860
            if ($access_link && in_array('unsubscribe', $access_link)) {
4861
                $my_course['unsubscribe_button'] = Display::url(
4862
                    get_lang('Unsubscribe').' '.
4863
                    Display::getMdiIcon('logout'),
4864
                    api_get_path(WEB_CODE_PATH).'auth/courses.php?action=unsubscribe&unsubscribe='.$courseCode
4865
                    .'&sec_token='.$stok.'&category_code='.$categoryCode,
4866
                    [
4867
                        'class' => 'btn btn--danger btn-sm',
4868
                        'title' => get_lang('Unsubscribe'),
4869
                        'aria-label' => get_lang('Unsubscribe'),
4870
                    ]
4871
                );
4872
            }
4873
4874
            // start buycourse validation
4875
            // display the course price and buy button if the buycourses plugin is enabled and this course is configured
4876
            $plugin = BuyCoursesPlugin::create();
4877
            $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
4878
                $course_info['real_id'],
4879
                BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4880
            );
4881
            if ($isThisCourseInSale) {
4882
                // set the price label
4883
                $my_course['price'] = $isThisCourseInSale['html'];
4884
                // set the Buy button instead register.
4885
                if ($isThisCourseInSale['verificator'] && !empty($my_course['register_button'])) {
4886
                    $my_course['register_button'] = $plugin->returnBuyCourseButton(
4887
                        $course_info['real_id'],
4888
                        BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4889
                    );
4890
                }
4891
            }
4892
            // end buycourse validation
4893
4894
            // Description
4895
            $my_course['description_button'] = self::returnDescriptionButton($course_info);
4896
            $my_course['teachers'] = self::getTeachersFromCourse($course_info['real_id'], true);
4897
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
4898
            $my_course['rating_html'] = '';
4899
            if (('false' === api_get_setting('course.hide_course_rating'))) {
4900
                $my_course['rating_html'] = Display::return_rating_system(
4901
                    'star_'.$course_info['real_id'],
4902
                    $ajax_url.'&course_id='.$course_info['real_id'],
4903
                    $point_info
4904
                );
4905
            }
4906
            $hotCourses[] = $my_course;
4907
        }
4908
4909
        return $hotCourses;
4910
    }
4911
4912
    public function totalSubscribedUsersInCourses($urlId)
4913
    {
4914
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4915
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4916
        $courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4917
4918
        $urlId = (int) $urlId;
4919
4920
        $sql = "SELECT count(cu.user_id) count
4921
                FROM $courseUsers cu
4922
                INNER JOIN $table_course_rel_access_url u
4923
                ON cu.c_id = u.c_id
4924
                WHERE
4925
                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
4926
                    u.access_url_id = $urlId AND
4927
                    visibility <> ".Course::CLOSED." AND
4928
                    visibility <> ".Course::HIDDEN."
4929
                     ";
4930
4931
        $res = Database::query($sql);
4932
        $row = Database::fetch_array($res);
4933
4934
        return $row['count'];
4935
    }
4936
4937
    /**
4938
     * Get courses count.
4939
     *
4940
     * @param int $access_url_id Access URL ID (optional)
4941
     * @param int $visibility
4942
     *
4943
     * @return int Number of courses
4944
     */
4945
    public static function count_courses($access_url_id = null, $visibility = null)
4946
    {
4947
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4948
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4949
        $sql = "SELECT count(c.id) FROM $table_course c";
4950
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
4951
            $sql .= ", $table_course_rel_access_url u
4952
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
4953
            if (!empty($visibility)) {
4954
                $visibility = intval($visibility);
4955
                $sql .= " AND visibility = $visibility ";
4956
            }
4957
        } else {
4958
            if (!empty($visibility)) {
4959
                $visibility = intval($visibility);
4960
                $sql .= " WHERE visibility = $visibility ";
4961
            }
4962
        }
4963
4964
        $res = Database::query($sql);
4965
        $row = Database::fetch_row($res);
4966
4967
        return $row[0];
4968
    }
4969
4970
    /**
4971
     * Get active courses count.
4972
     * Active = all courses except the ones with hidden visibility.
4973
     *
4974
     * @param int $urlId Access URL ID (optional)
4975
     *
4976
     * @return int Number of courses
4977
     */
4978
    public static function countActiveCourses($urlId = null)
4979
    {
4980
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4981
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4982
        $sql = "SELECT count(c.id) FROM $table_course c";
4983
        if (!empty($urlId)) {
4984
            $urlId = (int) $urlId;
4985
            $sql .= ", $table_course_rel_access_url u
4986
                    WHERE
4987
                        c.id = u.c_id AND
4988
                        u.access_url_id = $urlId AND
4989
                        visibility <> ".Course::HIDDEN;
4990
        } else {
4991
            $sql .= " WHERE visibility <> ".Course::HIDDEN;
4992
        }
4993
        $res = Database::query($sql);
4994
        $row = Database::fetch_row($res);
4995
4996
        return $row[0];
4997
    }
4998
4999
    /**
5000
     * Returns the SQL conditions to filter course only visible by the user in the catalogue.
5001
     *
5002
     * @param string $courseTableAlias Alias of the course table
5003
     * @param bool   $hideClosed       Whether to hide closed and hidden courses
5004
     * @param bool   $checkHidePrivate
5005
     *
5006
     * @return string SQL conditions
5007
     */
5008
    public static function getCourseVisibilitySQLCondition($courseTableAlias, $hideClosed = false, $checkHidePrivate = true)
5009
    {
5010
        $visibilityCondition = '';
5011
        if ($checkHidePrivate) {
5012
            $hidePrivateSetting = api_get_setting('course_catalog_hide_private');
5013
            if ('true' === $hidePrivateSetting) {
5014
                $visibilityCondition .= " AND $courseTableAlias.visibility <> ".Course::REGISTERED;
5015
            }
5016
        }
5017
        if ($hideClosed) {
5018
            $visibilityCondition .= " AND $courseTableAlias.visibility NOT IN (".Course::CLOSED.','.Course::HIDDEN.')';
5019
        }
5020
5021
        // Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
5022
        $currentUserId = api_get_user_id();
5023
        $restrictedCourses = self::getCatalogCourseList(true);
5024
        $allowedCoursesToCurrentUser = self::getCatalogCourseList(true, $currentUserId);
5025
        if (!empty($restrictedCourses)) {
5026
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5027
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("'.implode('","', $allowedCoursesToCurrentUser).'"))';
5028
        }
5029
5030
        // Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
5031
        $restrictedCourses = self::getCatalogCourseList(false);
5032
        $notAllowedCoursesToCurrentUser = self::getCatalogCourseList(false, $currentUserId);
5033
        if (!empty($restrictedCourses)) {
5034
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5035
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("'.implode('","', $notAllowedCoursesToCurrentUser).'"))';
5036
        }
5037
5038
        return $visibilityCondition;
5039
    }
5040
5041
    /**
5042
     * Return a link to go to the course, validating the visibility of the
5043
     * course and the user status.
5044
     *
5045
     * @param int $uid User ID
5046
     * @param array Course details array
5047
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
5048
     *
5049
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
5050
     */
5051
    public static function get_access_link_by_user($uid, $course, $user_courses = [])
5052
    {
5053
        if (empty($uid) || empty($course)) {
5054
            return false;
5055
        }
5056
5057
        if (empty($user_courses)) {
5058
            // get the array of courses to which the user is subscribed
5059
            $user_courses = self::get_courses_list_by_user_id($uid);
5060
            foreach ($user_courses as $k => $v) {
5061
                $user_courses[$k] = $v['real_id'];
5062
            }
5063
        }
5064
5065
        if (!isset($course['real_id']) && empty($course['real_id'])) {
5066
            $course = api_get_course_info($course['code']);
5067
        }
5068
5069
        if (Course::HIDDEN == $course['visibility']) {
5070
            return [];
5071
        }
5072
5073
        $is_admin = api_is_platform_admin_by_id($uid);
5074
        $options = [];
5075
        // Register button
5076
        if (!api_is_anonymous($uid) &&
5077
            (
5078
            (Course::OPEN_WORLD == $course['visibility'] || Course::OPEN_PLATFORM == $course['visibility'])
5079
                //$course['visibility'] == Course::REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
5080
            ) &&
5081
            SUBSCRIBE_ALLOWED == $course['subscribe'] &&
5082
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
5083
        ) {
5084
            $options[] = 'register';
5085
        }
5086
5087
        $isLogin = !api_is_anonymous();
5088
5089
        // Go To Course button (only if admin, if course public or if student already subscribed)
5090
        if ($is_admin ||
5091
            Course::OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5092
            ($isLogin && Course::OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5093
            (in_array($course['real_id'], $user_courses) && Course::CLOSED != $course['visibility'])
5094
        ) {
5095
            $options[] = 'enter';
5096
        }
5097
5098
        if ($is_admin ||
5099
            Course::OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5100
            ($isLogin && Course::OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5101
            (in_array($course['real_id'], $user_courses) && Course::CLOSED != $course['visibility'])
5102
        ) {
5103
            $options[] = 'enter';
5104
        }
5105
5106
        if (Course::HIDDEN != $course['visibility'] &&
5107
            empty($course['registration_code']) &&
5108
            UNSUBSCRIBE_ALLOWED == $course['unsubscribe'] &&
5109
            $isLogin &&
5110
            in_array($course['real_id'], $user_courses)
5111
        ) {
5112
            $options[] = 'unsubscribe';
5113
        }
5114
5115
        return $options;
5116
    }
5117
5118
    /**
5119
     * @param array          $courseInfo
5120
     * @param array          $teachers
5121
     * @param bool           $deleteTeachersNotInList
5122
     * @param bool           $editTeacherInSessions
5123
     * @param bool           $deleteSessionTeacherNotInList
5124
     * @param array          $teacherBackup
5125
     * @param Monolog\Logger $logger
5126
     *
5127
     * @return false|null
5128
     */
5129
    public static function updateTeachers(
5130
        $courseInfo,
5131
        $teachers,
5132
        $deleteTeachersNotInList = true,
5133
        $editTeacherInSessions = false,
5134
        $deleteSessionTeacherNotInList = false,
5135
        $teacherBackup = [],
5136
        $logger = null
5137
    ) {
5138
        if (!is_array($teachers)) {
5139
            $teachers = [$teachers];
5140
        }
5141
5142
        if (empty($courseInfo) || !isset($courseInfo['real_id'])) {
5143
            return false;
5144
        }
5145
5146
        $teachers = array_filter($teachers);
5147
        $courseId = $courseInfo['real_id'];
5148
        $course_code = $courseInfo['code'];
5149
5150
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5151
        $alreadyAddedTeachers = self::get_teacher_list_from_course_code($course_code);
5152
5153
        if ($deleteTeachersNotInList) {
5154
            // Delete only teacher relations that doesn't match the selected teachers
5155
            $cond = null;
5156
            if (count($teachers) > 0) {
5157
                foreach ($teachers as $key) {
5158
                    $key = Database::escape_string($key);
5159
                    $cond .= " AND user_id <> '".$key."'";
5160
                }
5161
            }
5162
5163
            // Recover user categories
5164
            $sql = "SELECT * FROM $course_user_table
5165
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5166
            $result = Database::query($sql);
5167
            if (Database::num_rows($result)) {
5168
                $teachersToDelete = Database::store_result($result, 'ASSOC');
5169
                foreach ($teachersToDelete as $data) {
5170
                    $userId = $data['user_id'];
5171
                    $teacherBackup[$userId][$course_code] = $data;
5172
                }
5173
            }
5174
5175
            $sql = "DELETE FROM $course_user_table
5176
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5177
5178
            Database::query($sql);
5179
        }
5180
5181
        if (count($teachers) > 0) {
5182
            foreach ($teachers as $userId) {
5183
                $userId = intval($userId);
5184
                // We check if the teacher is already subscribed in this course
5185
                $sql = "SELECT 1 FROM $course_user_table
5186
                        WHERE user_id = $userId AND c_id = $courseId";
5187
                $result = Database::query($sql);
5188
                if (Database::num_rows($result)) {
5189
                    $sql = "UPDATE $course_user_table
5190
                            SET status = 1
5191
                            WHERE c_id = $courseId AND user_id = $userId ";
5192
                } else {
5193
                    $userCourseCategory = '0';
5194
                    if (isset($teacherBackup[$userId]) &&
5195
                        isset($teacherBackup[$userId][$course_code])
5196
                    ) {
5197
                        $courseUserData = $teacherBackup[$userId][$course_code];
5198
                        $userCourseCategory = $courseUserData['user_course_cat'];
5199
                        if ($logger) {
5200
                            $logger->debug("Recovering user_course_cat: $userCourseCategory");
5201
                        }
5202
                    }
5203
5204
                    $sql = "INSERT INTO $course_user_table SET
5205
                            c_id = $courseId,
5206
                            user_id = $userId,
5207
                            status = 1,
5208
                            is_tutor = 0,
5209
                            sort = 0,
5210
                            relation_type = 0,
5211
                            user_course_cat = $userCourseCategory,
5212
                            progress = 0
5213
                    ";
5214
                }
5215
                Database::query($sql);
5216
            }
5217
        }
5218
5219
        if ($editTeacherInSessions) {
5220
            $sessions = SessionManager::get_session_by_course($courseId);
5221
            if (!empty($sessions)) {
5222
                if ($logger) {
5223
                    $logger->debug("Edit teachers in sessions");
5224
                }
5225
                foreach ($sessions as $session) {
5226
                    $sessionId = $session['id'];
5227
                    // Remove old and add new
5228
                    if ($deleteSessionTeacherNotInList) {
5229
                        foreach ($teachers as $userId) {
5230
                            if ($logger) {
5231
                                $logger->debug("Set coach #$userId in session #$sessionId of course #$courseId ");
5232
                            }
5233
                            SessionManager::set_coach_to_course_session(
5234
                                $userId,
5235
                                $sessionId,
5236
                                $courseId
5237
                            );
5238
                        }
5239
5240
                        $teachersToDelete = [];
5241
                        if (!empty($alreadyAddedTeachers)) {
5242
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
5243
                        }
5244
5245
                        if (!empty($teachersToDelete)) {
5246
                            foreach ($teachersToDelete as $userId) {
5247
                                if ($logger) {
5248
                                    $logger->debug("Delete coach #$userId in session #$sessionId of course #$courseId ");
5249
                                }
5250
                                SessionManager::set_coach_to_course_session(
5251
                                    $userId,
5252
                                    $sessionId,
5253
                                    $courseId,
5254
                                    true
5255
                                );
5256
                            }
5257
                        }
5258
                    } else {
5259
                        // Add new teachers only
5260
                        foreach ($teachers as $userId) {
5261
                            if ($logger) {
5262
                                $logger->debug("Add coach #$userId in session #$sessionId of course #$courseId ");
5263
                            }
5264
                            SessionManager::set_coach_to_course_session(
5265
                                $userId,
5266
                                $sessionId,
5267
                                $courseId
5268
                            );
5269
                        }
5270
                    }
5271
                }
5272
            }
5273
        }
5274
    }
5275
5276
    /**
5277
     * Course available settings variables see c_course_setting table.
5278
     *
5279
     * @return array
5280
     */
5281
    public static function getCourseSettingVariables(AppPlugin $appPlugin = null)
5282
    {
5283
        $pluginCourseSettings = [];
5284
        if ($appPlugin) {
5285
            $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
5286
        }
5287
        $courseSettings = [
5288
            // Get allow_learning_path_theme from table
5289
            'allow_learning_path_theme',
5290
            // Get allow_open_chat_window from table
5291
            'allow_open_chat_window',
5292
            'allow_public_certificates',
5293
            // Get allow_user_edit_agenda from table
5294
            'allow_user_edit_agenda',
5295
            // Get allow_user_edit_announcement from table
5296
            'allow_user_edit_announcement',
5297
            // Get allow_user_image_forum from table
5298
            'allow_user_image_forum',
5299
            //Get allow show user list
5300
            'allow_user_view_user_list',
5301
            // Get course_theme from table
5302
            'course_theme',
5303
            //Get allow show user list
5304
            'display_info_advance_inside_homecourse',
5305
            'documents_default_visibility',
5306
            // Get send_mail_setting (work)from table
5307
            'email_alert_manager_on_new_doc',
5308
            // Get send_mail_setting (work)from table
5309
            'email_alert_manager_on_new_quiz',
5310
            // Get send_mail_setting (dropbox) from table
5311
            'email_alert_on_new_doc_dropbox',
5312
            'email_alert_students_on_new_homework',
5313
            // Get send_mail_setting (auth)from table
5314
            'email_alert_to_teacher_on_new_user_in_course',
5315
            'enable_lp_auto_launch',
5316
            'enable_exercise_auto_launch',
5317
            'enable_document_auto_launch',
5318
            'pdf_export_watermark_text',
5319
            'show_system_folders',
5320
            'exercise_invisible_in_session',
5321
            'enable_forum_auto_launch',
5322
            'show_course_in_user_language',
5323
            'email_to_teachers_on_new_work_feedback',
5324
            'student_delete_own_publication',
5325
            'hide_forum_notifications',
5326
            'quiz_question_limit_per_day',
5327
            'subscribe_users_to_forum_notifications',
5328
        ];
5329
5330
        $courseModels = ExerciseLib::getScoreModels();
5331
        if (!empty($courseModels)) {
5332
            $courseSettings[] = 'score_model_id';
5333
        }
5334
5335
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5336
        if ('true' === $allowLPReturnLink) {
5337
            $courseSettings[] = 'lp_return_link';
5338
        }
5339
5340
        if (!empty($pluginCourseSettings)) {
5341
            $courseSettings = array_merge(
5342
                $courseSettings,
5343
                $pluginCourseSettings
5344
            );
5345
        }
5346
5347
        return $courseSettings;
5348
    }
5349
5350
    /**
5351
     * @param string       $variable
5352
     * @param string|array $value
5353
     * @param int          $courseId
5354
     *
5355
     * @return bool
5356
     */
5357
    public static function saveCourseConfigurationSetting($variable, $value, $courseId, AppPlugin $appPlugin = null)
5358
    {
5359
        $settingList = self::getCourseSettingVariables($appPlugin);
5360
5361
        if (!in_array($variable, $settingList)) {
5362
            return false;
5363
        }
5364
5365
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5366
5367
        if (is_array($value)) {
5368
            $value = implode(',', $value);
5369
        }
5370
5371
        $settingFromDatabase = self::getCourseSetting($variable, $courseId);
5372
5373
        if (!empty($settingFromDatabase)) {
5374
            // Update
5375
            Database::update(
5376
                $courseSettingTable,
5377
                ['value' => $value],
5378
                ['variable = ? AND c_id = ?' => [$variable, $courseId]]
5379
            );
5380
5381
            /*if ($settingFromDatabase['value'] != $value) {
5382
                Event::addEvent(
5383
                    LOG_COURSE_SETTINGS_CHANGED,
5384
                    $variable,
5385
                    $settingFromDatabase['value']." -> $value"
5386
                );
5387
            }*/
5388
        } else {
5389
            // Create
5390
            Database::insert(
5391
                $courseSettingTable,
5392
                [
5393
                    'title' => $variable,
5394
                    'value' => $value,
5395
                    'c_id' => $courseId,
5396
                    'variable' => $variable,
5397
                ]
5398
            );
5399
5400
            /*Event::addEvent(
5401
                LOG_COURSE_SETTINGS_CHANGED,
5402
                $variable,
5403
                $value
5404
            );*/
5405
        }
5406
5407
        return true;
5408
    }
5409
5410
    /**
5411
     * Get course setting.
5412
     *
5413
     * @param string $variable
5414
     * @param int    $courseId
5415
     *
5416
     * @return array
5417
     */
5418
    public static function getCourseSetting($variable, $courseId)
5419
    {
5420
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5421
        $courseId = (int) $courseId;
5422
        $variable = Database::escape_string($variable);
5423
        $sql = "SELECT variable, value FROM $courseSetting
5424
                WHERE c_id = $courseId AND variable = '$variable'";
5425
        $result = Database::query($sql);
5426
5427
        return Database::fetch_array($result);
5428
    }
5429
5430
    public static function saveSettingChanges($courseInfo, $params)
5431
    {
5432
        if (empty($courseInfo) || empty($params)) {
5433
            return false;
5434
        }
5435
5436
        $userId = api_get_user_id();
5437
        $now = api_get_utc_datetime();
5438
5439
        foreach ($params as $name => $value) {
5440
            $emptyValue = ' - ';
5441
            if (isset($courseInfo[$name]) && $courseInfo[$name] != $value) {
5442
                if ('' !== $courseInfo[$name]) {
5443
                    $emptyValue = $courseInfo[$name];
5444
                }
5445
5446
                $changedTo = $emptyValue.' -> '.$value;
5447
5448
                Event::addEvent(
5449
                    LOG_COURSE_SETTINGS_CHANGED,
5450
                    $name,
5451
                    $changedTo,
5452
                    $now,
5453
                    $userId,
5454
                    $courseInfo['real_id']
5455
                );
5456
            }
5457
        }
5458
5459
        return true;
5460
    }
5461
5462
    /**
5463
     * Get information from the track_e_course_access table.
5464
     *
5465
     * @param int    $courseId
5466
     * @param int    $sessionId
5467
     * @param string $startDate
5468
     * @param string $endDate
5469
     *
5470
     * @return array
5471
     */
5472
    public static function getCourseAccessPerCourseAndSession(
5473
        $courseId,
5474
        $sessionId,
5475
        $startDate,
5476
        $endDate
5477
    ) {
5478
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5479
        $courseId = (int) $courseId;
5480
        $sessionId = (int) $sessionId;
5481
        $startDate = Database::escape_string($startDate);
5482
        $endDate = Database::escape_string($endDate);
5483
5484
        $sql = "SELECT * FROM $table
5485
                WHERE
5486
                    c_id = $courseId AND
5487
                    session_id = $sessionId AND
5488
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5489
                ";
5490
5491
        $result = Database::query($sql);
5492
5493
        return Database::store_result($result);
5494
    }
5495
5496
    /**
5497
     * Get login information from the track_e_course_access table, for any
5498
     * course in the given session.
5499
     *
5500
     * @param int $sessionId
5501
     * @param int $userId
5502
     *
5503
     * @return array
5504
     */
5505
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5506
    {
5507
        $sessionId = (int) $sessionId;
5508
        $userId = (int) $userId;
5509
5510
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5511
        $sql = "SELECT * FROM $table
5512
                WHERE session_id = $sessionId AND user_id = $userId
5513
                ORDER BY login_course_date ASC
5514
                LIMIT 1";
5515
5516
        $result = Database::query($sql);
5517
        $courseAccess = [];
5518
        if (Database::num_rows($result)) {
5519
            $courseAccess = Database::fetch_array($result, 'ASSOC');
5520
        }
5521
5522
        return $courseAccess;
5523
    }
5524
5525
    /**
5526
     * @param int  $courseId
5527
     * @param int  $sessionId
5528
     * @param bool $getAllSessions
5529
     *
5530
     * @return mixed
5531
     */
5532
    public static function getCountForum(
5533
        $courseId,
5534
        $sessionId = 0,
5535
        $getAllSessions = false
5536
    ) {
5537
        $forum = Database::get_course_table(TABLE_FORUM);
5538
        if ($getAllSessions) {
5539
            $sql = "SELECT count(*) as count
5540
                    FROM $forum f
5541
                    WHERE f.c_id = %s";
5542
        } else {
5543
            $sql = "SELECT count(*) as count
5544
                    FROM $forum f
5545
                    WHERE f.c_id = %s and f.session_id = %s";
5546
        }
5547
5548
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5549
        $result = Database::query($sql);
5550
        $row = Database::fetch_array($result);
5551
5552
        return $row['count'];
5553
    }
5554
5555
    /**
5556
     * @param int $userId
5557
     * @param int $courseId
5558
     * @param int $sessionId
5559
     *
5560
     * @return mixed
5561
     */
5562
    public static function getCountPostInForumPerUser(
5563
        $userId,
5564
        $courseId,
5565
        $sessionId = 0
5566
    ) {
5567
        $forum = Database::get_course_table(TABLE_FORUM);
5568
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5569
5570
        $sql = "SELECT count(distinct post_id) as count
5571
                FROM $forum_post p
5572
                INNER JOIN $forum f
5573
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5574
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5575
5576
        $sql = sprintf(
5577
            $sql,
5578
            intval($userId),
5579
            intval($sessionId),
5580
            intval($courseId)
5581
        );
5582
5583
        $result = Database::query($sql);
5584
        $row = Database::fetch_array($result);
5585
5586
        return $row['count'];
5587
    }
5588
5589
    /**
5590
     * @param int $userId
5591
     * @param int $courseId
5592
     * @param int $sessionId
5593
     *
5594
     * @return mixed
5595
     */
5596
    public static function getCountForumPerUser(
5597
        $userId,
5598
        $courseId,
5599
        $sessionId = 0
5600
    ) {
5601
        $forum = Database::get_course_table(TABLE_FORUM);
5602
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5603
5604
        $sql = "SELECT count(distinct f.forum_id) as count
5605
                FROM $forum_post p
5606
                INNER JOIN $forum f
5607
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5608
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5609
5610
        $sql = sprintf(
5611
            $sql,
5612
            intval($userId),
5613
            intval($sessionId),
5614
            intval($courseId)
5615
        );
5616
5617
        $result = Database::query($sql);
5618
        $row = Database::fetch_array($result);
5619
5620
        return $row['count'];
5621
    }
5622
5623
    /**
5624
     * Returns the course name from a given code.
5625
     *
5626
     * @param string $code
5627
     *
5628
     * @return string
5629
     */
5630
    public static function getCourseNameFromCode($code)
5631
    {
5632
        $tbl_main_categories = Database::get_main_table(TABLE_MAIN_COURSE);
5633
        $code = Database::escape_string($code);
5634
        $sql = "SELECT title
5635
                FROM $tbl_main_categories
5636
                WHERE code = '$code'";
5637
        $result = Database::query($sql);
5638
        if ($col = Database::fetch_array($result)) {
5639
            return $col['title'];
5640
        }
5641
    }
5642
5643
    /**
5644
     * Generates a course code from a course title.
5645
     *
5646
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
5647
     * @todo the function might be upgraded for avoiding code duplications (currently,
5648
     * it might suggest a code that is already in use)
5649
     *
5650
     * @param string $title A course title
5651
     *
5652
     * @return string A proposed course code
5653
     *                +
5654
     * @assert (null,null) === false
5655
     * @assert ('ABC_DEF', null) === 'ABCDEF'
5656
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
5657
     */
5658
    public static function generate_course_code($title)
5659
    {
5660
        return substr(
5661
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
5662
            0,
5663
            self::MAX_COURSE_LENGTH_CODE
5664
        );
5665
    }
5666
5667
    /**
5668
     * this function gets all the users of the course,
5669
     * including users from linked courses.
5670
     *
5671
     * @param $filterByActive
5672
     *
5673
     * @return array
5674
     */
5675
    public static function getCourseUsers($filterByActive = null)
5676
    {
5677
        // This would return only the users from real courses:
5678
        return self::get_user_list_from_course_code(
5679
            api_get_course_id(),
5680
            api_get_session_id(),
5681
            null,
5682
            null,
5683
            null,
5684
            null,
5685
            false,
5686
            false,
5687
            [],
5688
            [],
5689
            [],
5690
            $filterByActive
5691
        );
5692
    }
5693
5694
    /**
5695
     * this function gets all the groups of the course,
5696
     * not including linked courses.
5697
     *
5698
     * @return CGroup[]
5699
     */
5700
    public static function getCourseGroups()
5701
    {
5702
        $sessionId = api_get_session_id();
5703
        $courseCode = api_get_course_id();
5704
        if (0 != $sessionId) {
5705
            $groupList = self::get_group_list_of_course(
5706
                $courseCode,
5707
                $sessionId,
5708
                1
5709
            );
5710
        } else {
5711
            $groupList = self::get_group_list_of_course(
5712
                $courseCode,
5713
                0,
5714
                1
5715
            );
5716
        }
5717
5718
        return $groupList;
5719
    }
5720
5721
    /**
5722
     * @param FormValidator $form
5723
     * @param array         $alreadySelected
5724
     *
5725
     * @return HTML_QuickForm_element
5726
     */
5727
    public static function addUserGroupMultiSelect(&$form, $alreadySelected, $addShortCut = false)
5728
    {
5729
        $userList = self::getCourseUsers(true);
5730
        $groupList = self::getCourseGroups();
5731
5732
        $array = self::buildSelectOptions(
5733
            $groupList,
5734
            $userList,
5735
            $alreadySelected
5736
        );
5737
5738
        $result = [];
5739
        foreach ($array as $content) {
5740
            $result[$content['value']] = $content['content'];
5741
        }
5742
5743
        $multiple = $form->addMultiSelect(
5744
            'users',
5745
            get_lang('Users'),
5746
            $result,
5747
            ['select_all_checkbox' => true, 'id' => 'users']
5748
        );
5749
5750
        $sessionId = api_get_session_id();
5751
        if ($addShortCut && empty($sessionId)) {
5752
            $addStudents = [];
5753
            foreach ($userList as $user) {
5754
                if (STUDENT == $user['status_rel']) {
5755
                    $addStudents[] = $user['user_id'];
5756
                }
5757
            }
5758
            if (!empty($addStudents)) {
5759
                $form->addHtml(
5760
                    '<script>
5761
                    $(function() {
5762
                        $("#add_students").on("click", function() {
5763
                            var addStudents = '.json_encode($addStudents).';
5764
                            $.each(addStudents, function( index, value ) {
5765
                                var option = $("#users option[value=\'USER:"+value+"\']");
5766
                                if (option.val()) {
5767
                                    $("#users_to").append(new Option(option.text(), option.val()))
5768
                                    option.remove();
5769
                                }
5770
                            });
5771
5772
                            return false;
5773
                        });
5774
                    });
5775
                    </script>'
5776
                );
5777
5778
                $form->addLabel(
5779
                    '',
5780
                    Display::url(get_lang('Add learners'), '#', ['id' => 'add_students', 'class' => 'btn btn--primary'])
5781
                );
5782
            }
5783
        }
5784
5785
        return $multiple;
5786
    }
5787
5788
    /**
5789
     * This function separates the users from the groups
5790
     * users have a value USER:XXX (with XXX the groups id have a value
5791
     *  GROUP:YYY (with YYY the group id).
5792
     *
5793
     * @param array $to Array of strings that define the type and id of each destination
5794
     *
5795
     * @return array Array of groups and users (each an array of IDs)
5796
     */
5797
    public static function separateUsersGroups($to)
5798
    {
5799
        $groupList = [];
5800
        $userList = [];
5801
5802
        foreach ($to as $to_item) {
5803
            if (!empty($to_item)) {
5804
                $parts = explode(':', $to_item);
5805
                $type = isset($parts[0]) ? $parts[0] : '';
5806
                $id = isset($parts[1]) ? $parts[1] : '';
5807
5808
                switch ($type) {
5809
                    case 'GROUP':
5810
                        $groupList[] = (int) $id;
5811
                        break;
5812
                    case 'USER':
5813
                        $userList[] = (int) $id;
5814
                        break;
5815
                }
5816
            }
5817
        }
5818
5819
        $send_to['groups'] = $groupList;
5820
        $send_to['users'] = $userList;
5821
5822
        return $send_to;
5823
    }
5824
5825
    /**
5826
     * Shows the form for sending a message to a specific group or user.
5827
     *
5828
     * @return HTML_QuickForm_element
5829
     */
5830
    public static function addGroupMultiSelect(FormValidator $form, CGroup $group, $to = [])
5831
    {
5832
        $groupUsers = GroupManager::get_subscribed_users($group);
5833
        $array = self::buildSelectOptions([$group], $groupUsers, $to);
5834
5835
        $result = [];
5836
        foreach ($array as $content) {
5837
            $result[$content['value']] = $content['content'];
5838
        }
5839
5840
        return $form->addMultiSelect('users', get_lang('Users'), $result);
5841
    }
5842
5843
    /**
5844
     * this function shows the form for sending a message to a specific group or user.
5845
     *
5846
     * @param CGroup[] $groupList
5847
     * @param array    $userList
5848
     * @param array    $alreadySelected
5849
     *
5850
     * @return array
5851
     */
5852
    public static function buildSelectOptions($groupList = [], $userList = [], $alreadySelected = [])
5853
    {
5854
        if (empty($alreadySelected)) {
5855
            $alreadySelected = [];
5856
        }
5857
5858
        $result = [];
5859
        // adding the groups to the select form
5860
        if ($groupList) {
5861
            foreach ($groupList as $thisGroup) {
5862
                $groupId = $thisGroup->getIid();
5863
                if (is_array($alreadySelected)) {
5864
                    if (!in_array(
5865
                        "GROUP:".$groupId,
5866
                        $alreadySelected
5867
                    )
5868
                    ) {
5869
                        $userCount = $thisGroup->getMembers()->count();
5870
5871
                        // $alreadySelected is the array containing the groups (and users) that are already selected
5872
                        $userLabel = ($userCount > 0) ? get_lang('Users') : get_lang('user');
5873
                        $userDisabled = ($userCount > 0) ? "" : "disabled=disabled";
5874
                        $result[] = [
5875
                            'disabled' => $userDisabled,
5876
                            'value' => "GROUP:".$groupId,
5877
                            // The space before "G" is needed in order to advmultiselect.php js puts groups first
5878
                            'content' => " G: ".$thisGroup->getTitle()." - ".$userCount." ".$userLabel,
5879
                        ];
5880
                    }
5881
                }
5882
            }
5883
        }
5884
5885
        // adding the individual users to the select form
5886
        if ($userList) {
5887
            foreach ($userList as $user) {
5888
                if (is_array($alreadySelected)) {
5889
                    if (!in_array(
5890
                        "USER:".$user['user_id'],
5891
                        $alreadySelected
5892
                    )
5893
                    ) {
5894
                        // $alreadySelected is the array containing the users (and groups) that are already selected
5895
                        $result[] = [
5896
                            'value' => "USER:".$user['user_id'],
5897
                            'content' => api_get_person_name($user['firstname'], $user['lastname']),
5898
                        ];
5899
                    }
5900
                }
5901
            }
5902
        }
5903
5904
        return $result;
5905
    }
5906
5907
    /**
5908
     * @return array a list (array) of all courses
5909
     */
5910
    public static function get_course_list()
5911
    {
5912
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
5913
5914
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
5915
    }
5916
5917
    /**
5918
     * Returns course code from a given gradebook category's id.
5919
     *
5920
     * @param int $category_id Category ID
5921
     *
5922
     * @return ?int Course ID
5923
     * @throws Exception
5924
     */
5925
    public static function get_course_by_category(int $category_id): ?int
5926
    {
5927
        $category_id = (int) $category_id;
5928
        $sql = 'SELECT c_id FROM '.Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY).'
5929
                WHERE id='.$category_id;
5930
        $info = Database::fetch_array(Database::query($sql));
5931
5932
        return $info ? $info['c_id'] : null;
5933
    }
5934
5935
    /**
5936
     * This function gets all the courses that are not in a session.
5937
     *
5938
     * @param date Start date
5939
     * @param date End date
5940
     * @param bool $includeClosed Whether to include closed and hidden courses
5941
     *
5942
     * @return array Not-in-session courses
5943
     */
5944
    public static function getCoursesWithoutSession(
5945
        $startDate = null,
5946
        $endDate = null,
5947
        $includeClosed = false
5948
    ) {
5949
        $dateConditional = ($startDate && $endDate) ?
5950
            " WHERE session_id IN (SELECT id FROM ".Database::get_main_table(TABLE_MAIN_SESSION).
5951
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" : null;
5952
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
5953
5954
        $sql = "SELECT id, code, title
5955
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
5956
                WHERE $visibility code NOT IN (
5957
                    SELECT DISTINCT course_code
5958
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE).$dateConditional."
5959
                )
5960
                ORDER BY id";
5961
5962
        $result = Database::query($sql);
5963
        $courses = [];
5964
        while ($row = Database::fetch_array($result)) {
5965
            $courses[] = $row;
5966
        }
5967
5968
        return $courses;
5969
    }
5970
5971
    /**
5972
     * Get list of courses based on users of a group for a group admin.
5973
     *
5974
     * @param int $userId The user id
5975
     *
5976
     * @return array
5977
     */
5978
    public static function getCoursesFollowedByGroupAdmin($userId)
5979
    {
5980
        $coursesList = [];
5981
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5982
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5983
        $userGroup = new UserGroupModel();
5984
        $userIdList = $userGroup->getGroupUsersByUser($userId);
5985
5986
        if (empty($userIdList)) {
5987
            return [];
5988
        }
5989
5990
        $sql = "SELECT DISTINCT(c.id), c.title
5991
                FROM $courseTable c
5992
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
5993
                WHERE (
5994
                    cru.user_id IN (".implode(', ', $userIdList).")
5995
                    AND cru.relation_type = 0
5996
                )";
5997
5998
        if (api_is_multiple_url_enabled()) {
5999
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6000
            $accessUrlId = api_get_current_access_url_id();
6001
6002
            if (-1 != $accessUrlId) {
6003
                $sql = "SELECT DISTINCT(c.id), c.title
6004
                        FROM $courseTable c
6005
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6006
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
6007
                        WHERE crau.access_url_id = $accessUrlId
6008
                            AND (
6009
                            cru.id_user IN (".implode(', ', $userIdList).") AND
6010
                            cru.relation_type = 0
6011
                        )";
6012
            }
6013
        }
6014
6015
        $result = Database::query($sql);
6016
        while ($row = Database::fetch_assoc($result)) {
6017
            $coursesList[] = $row;
6018
        }
6019
6020
        return $coursesList;
6021
    }
6022
6023
    /**
6024
     * Direct course link see #5299.
6025
     *
6026
     * You can send to your students an URL like this
6027
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
6028
     * Where "c" is the course code and "e" is the exercise Id, after a successful
6029
     * registration the user will be sent to the course or exercise
6030
     *
6031
     * @param array $form_data
6032
     *
6033
     * @return array
6034
     */
6035
    public static function redirectToCourse($form_data)
6036
    {
6037
        $course_code_redirect = Session::read('course_redirect');
6038
        $_user = api_get_user_info();
6039
        $userId = api_get_user_id();
6040
6041
        if (!empty($course_code_redirect)) {
6042
            $course_info = api_get_course_info($course_code_redirect);
6043
            if (!empty($course_info)) {
6044
                if (in_array(
6045
                    $course_info['visibility'],
6046
                    [Course::OPEN_PLATFORM, Course::OPEN_WORLD]
6047
                )
6048
                ) {
6049
                    if (self::is_user_subscribed_in_course($userId, $course_info['code'])) {
6050
                        $form_data['action'] = $course_info['course_public_url'];
6051
                        $form_data['message'] = sprintf(get_lang('You have been registered to course %s'), $course_info['title']);
6052
                        $form_data['button'] = Display::button(
6053
                            'next',
6054
                            get_lang('Go to the course', null, $_user['language']),
6055
                            ['class' => 'btn btn--primary btn-large']
6056
                        );
6057
6058
                        $exercise_redirect = (int) Session::read('exercise_redirect');
6059
                        // Specify the course id as the current context does not
6060
                        // hold a global $_course array
6061
                        $objExercise = new Exercise($course_info['real_id']);
6062
                        $result = $objExercise->read($exercise_redirect);
6063
6064
                        if (!empty($exercise_redirect) && !empty($result)) {
6065
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).
6066
                                'exercise/overview.php?exerciseId='.$exercise_redirect.'&cid='.$course_info['real_id'];
6067
                            $form_data['message'] .= '<br />'.get_lang('Go to the test');
6068
                            $form_data['button'] = Display::button(
6069
                                'next',
6070
                                get_lang('Go', null, $_user['language']),
6071
                                ['class' => 'btn btn--primary btn-large']
6072
                            );
6073
                        }
6074
6075
                        if (!empty($form_data['action'])) {
6076
                            header('Location: '.$form_data['action']);
6077
                            exit;
6078
                        }
6079
                    }
6080
                }
6081
            }
6082
        }
6083
6084
        return $form_data;
6085
    }
6086
6087
    /**
6088
     * Return tab of params to display a course title in the My Courses tab
6089
     * Check visibility, right, and notification icons, and load_dirs option
6090
     * get html course params.
6091
     *
6092
     * @param $courseId
6093
     * @param bool $loadDirs
6094
     *
6095
     * @return array with keys ['right_actions'] ['teachers'] ['notifications']
6096
     */
6097
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
6098
    {
6099
        $userId = api_get_user_id();
6100
        $courseId = intval($courseId);
6101
        // Table definitions
6102
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
6103
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6104
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6105
        $current_url_id = api_get_current_access_url_id();
6106
6107
        // Get course list auto-register
6108
        $special_course_list = self::get_special_course_list();
6109
6110
        $without_special_courses = '';
6111
        if (!empty($special_course_list)) {
6112
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
6113
        }
6114
6115
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
6116
        $sql = "SELECT
6117
                    course.id,
6118
                    course.title,
6119
                    course.code,
6120
                    course.subscribe subscr,
6121
                    course.unsubscribe unsubscr,
6122
                    course_rel_user.status status,
6123
                    course_rel_user.sort sort,
6124
                    course_rel_user.user_course_cat user_course_cat
6125
                FROM
6126
                $TABLECOURS course
6127
                INNER JOIN $TABLECOURSUSER course_rel_user
6128
                ON (course.id = course_rel_user.c_id)
6129
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
6130
                ON (url.c_id = course.id)
6131
                WHERE
6132
                    course.id = $courseId AND
6133
                    course_rel_user.user_id = $userId
6134
                    $without_special_courses
6135
                ";
6136
6137
        // If multiple URL access mode is enabled, only fetch courses
6138
        // corresponding to the current URL.
6139
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
6140
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id";
6141
        }
6142
        // Use user's classification for courses (if any).
6143
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
6144
6145
        $result = Database::query($sql);
6146
6147
        // Browse through all courses. We can only have one course because
6148
        // of the  course.id=".intval($courseId) in sql query
6149
        $course = Database::fetch_array($result);
6150
        $course_info = api_get_course_info_by_id($courseId);
6151
        if (empty($course_info)) {
6152
            return '';
6153
        }
6154
6155
        //$course['id_session'] = null;
6156
        $course_info['id_session'] = null;
6157
        $course_info['status'] = $course['status'];
6158
6159
        // New code displaying the user's status in respect to this course.
6160
        $status_icon = Display::getMdiIcon(
6161
            'account-key',
6162
            'ch-tool-icon',
6163
            null,
6164
            ICON_SIZE_LARGE,
6165
            $course_info['title']
6166
        );
6167
6168
        $params = [];
6169
        $params['right_actions'] = '';
6170
6171
        if (api_is_platform_admin()) {
6172
            if ($loadDirs) {
6173
                $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.Display::getMdiIcon(ObjectIcon::FOLDER, 'ch-tool-icon', 'align: absmiddle;', ICON_SIZE_SMALL, get_lang('Documents')).'</a>';
6174
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6175
                    Display::getMdiIcon(ActionIcon::EDIT, 'ch-tool-icon', 'align: absmiddle;', ICON_SIZE_SMALL, get_lang('Edit')).
6176
                    '</a>';
6177
                $params['right_actions'] .= Display::div(
6178
                    '',
6179
                    [
6180
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
6181
                        'class' => 'document_preview_container',
6182
                    ]
6183
                );
6184
            } else {
6185
                $params['right_actions'] .=
6186
                    '<a class="btn btn--plain btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6187
                    Display::getMdiIcon('pencil').'</a>';
6188
            }
6189
        } else {
6190
            if (Course::CLOSED != $course_info['visibility']) {
6191
                if ($loadDirs) {
6192
                    $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.
6193
                        Display::getMdiIcon(ObjectIcon::FOLDER, 'ch-tool-icon', 'align: absmiddle;', ICON_SIZE_SMALL, get_lang('Documents')).'</a>';
6194
                    $params['right_actions'] .= Display::div(
6195
                        '',
6196
                        [
6197
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
6198
                            'class' => 'document_preview_container',
6199
                        ]
6200
                    );
6201
                } else {
6202
                    if (COURSEMANAGER == $course_info['status']) {
6203
                        $params['right_actions'] .= '<a
6204
                            class="btn btn--plain btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6205
                            Display::getMdiIcon('pencil').'</a>';
6206
                    }
6207
                }
6208
            }
6209
        }
6210
6211
        $course_title_url = '';
6212
        if (Course::CLOSED != $course_info['visibility'] || COURSEMANAGER == $course['status']) {
6213
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
6214
            $course_title = Display::url($course_info['title'], $course_title_url);
6215
        } else {
6216
            $course_title = $course_info['title'].' '.Display::tag(
6217
                'span',
6218
                get_lang('(the course is currently closed)'),
6219
                ['class' => 'item_closed']
6220
            );
6221
        }
6222
6223
        // Start displaying the course block itself
6224
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
6225
            $course_title .= ' ('.$course_info['visual_code'].') ';
6226
        }
6227
        $teachers = '';
6228
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
6229
            $teachers = self::getTeacherListFromCourseCodeToString(
6230
                $course['code'],
6231
                self::USER_SEPARATOR,
6232
                true
6233
            );
6234
        }
6235
        $params['link'] = $course_title_url;
6236
        $params['icon'] = $status_icon;
6237
        $params['title'] = $course_title;
6238
        $params['teachers'] = $teachers;
6239
6240
        return $params;
6241
    }
6242
6243
    /**
6244
     * Get the course id based on the original id and field name in the extra fields.
6245
     * Returns 0 if course was not found.
6246
     *
6247
     * @param string $original_course_id_value Original course id
6248
     * @param string $original_course_id_name  Original field name
6249
     *
6250
     * @return int Course id
6251
     */
6252
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
6253
    {
6254
        $extraFieldValue = new ExtraFieldValue('course');
6255
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
6256
            $original_course_id_name,
6257
            $original_course_id_value
6258
        );
6259
6260
        if ($value) {
6261
            return $value['item_id'];
6262
        }
6263
6264
        return 0;
6265
    }
6266
6267
    /**
6268
     * Helper function to create a default gradebook (if necessary) upon course creation.
6269
     *
6270
     * @param int $modelId  The gradebook model ID
6271
     * @param int $courseId Course ID
6272
     * @return void
6273
     * @throws Exception
6274
     */
6275
    public static function createDefaultGradebook(int $modelId, int $courseId): void
6276
    {
6277
        if ('true' === api_get_setting('gradebook_enable_grade_model')) {
6278
            //Create gradebook_category for the new course and add
6279
            // a gradebook model for the course
6280
            if ('-1' != $modelId) {
6281
                GradebookUtils::create_default_course_gradebook(
6282
                    $courseId,
6283
                    $modelId
6284
                );
6285
            }
6286
        }
6287
    }
6288
6289
    /**
6290
     * Helper function to check if there is a course template and, if so, to
6291
     * copy the template as basis for the new course.
6292
     *
6293
     * @param string $courseCode     Course code
6294
     * @param int    $courseTemplate 0 if no course template is defined
6295
     */
6296
    public static function useTemplateAsBasisIfRequired($courseCode, $courseTemplate)
6297
    {
6298
        $template = api_get_setting('course_creation_use_template');
6299
        $teacherCanSelectCourseTemplate = 'true' === api_get_setting('teacher_can_select_course_template');
6300
        $courseTemplate = isset($courseTemplate) ? intval($courseTemplate) : 0;
6301
6302
        $useTemplate = false;
6303
6304
        if ($teacherCanSelectCourseTemplate && $courseTemplate) {
6305
            $useTemplate = true;
6306
            $originCourse = api_get_course_info_by_id($courseTemplate);
6307
        } elseif (!empty($template)) {
6308
            $useTemplate = true;
6309
            $originCourse = api_get_course_info_by_id($template);
6310
        }
6311
6312
        if ($useTemplate) {
6313
            // Include the necessary libraries to generate a course copy
6314
            // Call the course copy object
6315
            $originCourse['official_code'] = $originCourse['code'];
6316
            $cb = new CourseBuilder(null, $originCourse);
6317
            $course = $cb->build(null, $originCourse['code']);
6318
            $cr = new CourseRestorer($course);
6319
            $cr->set_file_option();
6320
            $cr->restore($courseCode);
6321
        }
6322
    }
6323
6324
    /**
6325
     * Helper method to get the number of users defined with a specific course extra field.
6326
     *
6327
     * @param string $name                 Field title
6328
     * @param string $tableExtraFields     The extra fields table name
6329
     * @param string $tableUserFieldValues The user extra field value table name
6330
     *
6331
     * @return int The number of users with this extra field with a specific value
6332
     */
6333
    public static function getCountRegisteredUsersWithCourseExtraField(
6334
        $name,
6335
        $tableExtraFields = '',
6336
        $tableUserFieldValues = ''
6337
    ) {
6338
        if (empty($tableExtraFields)) {
6339
            $tableExtraFields = Database::get_main_table(TABLE_EXTRA_FIELD);
6340
        }
6341
        if (empty($tableUserFieldValues)) {
6342
            $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6343
        }
6344
6345
        $registered_users_with_extra_field = 0;
6346
        if (!empty($name) && '-' != $name) {
6347
            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
6348
            $name = Database::escape_string($name);
6349
            $sql = "SELECT count(v.item_id) as count
6350
                    FROM $tableUserFieldValues v
6351
                    INNER JOIN $tableExtraFields f
6352
                    ON (f.id = v.field_id)
6353
                    WHERE value = '$name' AND item_type = $extraFieldType";
6354
            $result_count = Database::query($sql);
6355
            if (Database::num_rows($result_count)) {
6356
                $row_count = Database::fetch_array($result_count);
6357
                $registered_users_with_extra_field = $row_count['count'];
6358
            }
6359
        }
6360
6361
        return $registered_users_with_extra_field;
6362
    }
6363
6364
    /**
6365
     * Get the course categories form a course list.
6366
     *
6367
     * @return array
6368
     */
6369
    public static function getCourseCategoriesFromCourseList(array $courseList)
6370
    {
6371
        $allCategories = array_column($courseList, 'category');
6372
        $categories = array_unique($allCategories);
6373
6374
        sort($categories);
6375
6376
        return $categories;
6377
    }
6378
6379
    /**
6380
     * Display the description button of a course in the course catalog.
6381
     *
6382
     * @param array  $course
6383
     * @param string $url
6384
     *
6385
     * @return string HTML string
6386
     */
6387
    public static function returnDescriptionButton($course, $url = '')
6388
    {
6389
        if (empty($course)) {
6390
            return '';
6391
        }
6392
6393
        $class = '';
6394
        if ('true' === api_get_setting('show_courses_descriptions_in_catalog')) {
6395
            $title = $course['title'];
6396
            if (empty($url)) {
6397
                $class = 'ajax';
6398
                $url = api_get_path(WEB_CODE_PATH).
6399
                    'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
6400
            } else {
6401
                if (false !== strpos($url, 'ajax')) {
6402
                    $class = 'ajax';
6403
                }
6404
            }
6405
6406
            return Display::url(
6407
                Display::getMdiIcon('information'),
6408
                $url,
6409
                [
6410
                    'class' => "$class btn btn--plain btn-sm",
6411
                    'data-title' => $title,
6412
                    'title' => get_lang('Description'),
6413
                    'aria-label' => get_lang('Description'),
6414
                    'data-size' => 'lg',
6415
                ]
6416
            );
6417
        }
6418
6419
        return '';
6420
    }
6421
6422
    /**
6423
     * @return int
6424
     */
6425
    public static function getCountOpenCourses()
6426
    {
6427
        $visibility = [
6428
            Course::REGISTERED,
6429
            Course::OPEN_PLATFORM,
6430
            Course::OPEN_WORLD,
6431
        ];
6432
6433
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6434
        $sql = "SELECT count(id) count
6435
                FROM $table
6436
                WHERE visibility IN (".implode(',', $visibility).")";
6437
        $result = Database::query($sql);
6438
        $row = Database::fetch_array($result);
6439
6440
        return (int) $row['count'];
6441
    }
6442
6443
    /**
6444
     * @return int
6445
     */
6446
    public static function getCountExercisesFromOpenCourse()
6447
    {
6448
        $visibility = [
6449
            Course::REGISTERED,
6450
            Course::OPEN_PLATFORM,
6451
            Course::OPEN_WORLD,
6452
        ];
6453
6454
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6455
        $tableExercise = Database::get_course_table(TABLE_QUIZ_TEST);
6456
        $sql = "SELECT count(e.iid) count
6457
                FROM $table c
6458
                INNER JOIN $tableExercise e
6459
                ON (c.id = e.c_id)
6460
                WHERE e.active <> -1 AND visibility IN (".implode(',', $visibility).")";
6461
        $result = Database::query($sql);
6462
        $row = Database::fetch_array($result);
6463
6464
        return (int) $row['count'];
6465
    }
6466
6467
    /**
6468
     * retrieves all the courses that the user has already subscribed to.
6469
     *
6470
     * @param int $user_id
6471
     *
6472
     * @return array an array containing all the information of the courses of the given user
6473
     */
6474
    public static function getCoursesByUserCourseCategory($user_id)
6475
    {
6476
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
6477
        $courseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6478
        $avoidCoursesCondition = CoursesAndSessionsCatalog::getAvoidCourseCondition();
6479
        $visibilityCondition = self::getCourseVisibilitySQLCondition('course', true);
6480
6481
        // Secondly we select the courses that are in a category (user_course_cat<>0) and
6482
        // sort these according to the sort of the category
6483
        $user_id = (int) $user_id;
6484
        $sql = "SELECT
6485
                    course.code k,
6486
                    course.visual_code vc,
6487
                    course.subscribe subscr,
6488
                    course.unsubscribe unsubscr,
6489
                    course.title i,
6490
                    course.tutor_name t,
6491
                    course.category_code cat,
6492
                    course.directory dir,
6493
                    course_rel_user.status status,
6494
                    course_rel_user.sort sort,
6495
                    course_rel_user.user_course_cat user_course_cat
6496
                FROM $course course, $courseRelUser course_rel_user
6497
                WHERE
6498
                    course.id = course_rel_user.c_id AND
6499
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
6500
                    course_rel_user.user_id = '".$user_id."'
6501
                    $avoidCoursesCondition
6502
                    $visibilityCondition
6503
                ORDER BY course_rel_user.sort ASC";
6504
6505
        $result = Database::query($sql);
6506
        $courses = [];
6507
        while ($row = Database::fetch_array($result, 'ASOC')) {
6508
            $courses[] = [
6509
                'code' => $row['k'],
6510
                'visual_code' => $row['vc'],
6511
                'title' => $row['i'],
6512
                'directory' => $row['dir'],
6513
                'status' => $row['status'],
6514
                'tutor' => $row['t'],
6515
                'subscribe' => $row['subscr'],
6516
                'category' => $row['cat'],
6517
                'unsubscribe' => $row['unsubscr'],
6518
                'sort' => $row['sort'],
6519
                'user_course_category' => $row['user_course_cat'],
6520
            ];
6521
        }
6522
6523
        return $courses;
6524
    }
6525
6526
    /**
6527
     * @param string $listType
6528
     *
6529
     * @return string
6530
     */
6531
    public static function getCourseListTabs($listType)
6532
    {
6533
        $tabs = [
6534
            [
6535
                'content' => get_lang('Standard list'),
6536
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list.php',
6537
            ],
6538
            [
6539
                'content' => get_lang('Management List'),
6540
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list_admin.php',
6541
            ],
6542
        ];
6543
6544
        $default = 1;
6545
        switch ($listType) {
6546
            case 'simple':
6547
                $default = 1;
6548
                break;
6549
            case 'admin':
6550
                $default = 2;
6551
                break;
6552
        }
6553
6554
        return Display::tabsOnlyLink($tabs, $default);
6555
    }
6556
6557
    public static function getUrlMarker($courseId)
6558
    {
6559
        if (UrlManager::getCountAccessUrlFromCourse($courseId) > 1) {
6560
            return '&nbsp;'.Display::getMdiIcon(
6561
                'link',
6562
                null,
6563
                null,
6564
                null,
6565
                get_lang('CourseUsedInOtherURL')
6566
            );
6567
        }
6568
6569
        return '';
6570
    }
6571
6572
    /**
6573
     * @throws \Doctrine\ORM\ORMException
6574
     * @throws \Doctrine\ORM\OptimisticLockException
6575
     */
6576
    public static function insertUserInCourse(User $user, Course $course, array $relationInfo = []): ?int
6577
    {
6578
        $relationInfo = array_merge(
6579
            ['relation_type' => 0, 'status' => STUDENT, 'sort' => 0, 'user_course_cat' => 0],
6580
            $relationInfo
6581
        );
6582
6583
        $courseRelUser = (new CourseRelUser())
6584
            ->setCourse($course)
6585
            ->setUser($user)
6586
            ->setStatus($relationInfo['status'])
6587
            ->setSort($relationInfo['sort'])
6588
            ->setUserCourseCat($relationInfo['user_course_cat']);
6589
6590
        $course->addSubscription($courseRelUser);
6591
6592
        $em = Database::getManager();
6593
        $em->persist($course);
6594
        $em->flush();
6595
6596
        $insertId = $courseRelUser->getId();
6597
6598
        Event::logSubscribedUserInCourse($user, $course);
6599
6600
        return $insertId;
6601
    }
6602
6603
    public static function addVisibilityOptions(FormValidator $form): void
6604
    {
6605
        $group = [];
6606
        $group[] = $form->createElement(
6607
            'radio',
6608
            'visibility',
6609
            get_lang('Course access'),
6610
            get_lang('Public - access allowed for the whole world'),
6611
            Course::OPEN_WORLD
6612
        );
6613
        $group[] = $form->createElement(
6614
            'radio',
6615
            'visibility',
6616
            null,
6617
            get_lang(' Open - access allowed for users registered on the platform'),
6618
            Course::OPEN_PLATFORM
6619
        );
6620
        $group[] = $form->createElement(
6621
            'radio',
6622
            'visibility',
6623
            null,
6624
            get_lang('Private access (access authorized to group members only)'),
6625
            Course::REGISTERED
6626
        );
6627
        $group[] = $form->createElement(
6628
            'radio',
6629
            'visibility',
6630
            null,
6631
            get_lang('Closed - the course is only accessible to the teachers'),
6632
            Course::CLOSED
6633
        );
6634
        // The "hidden" visibility is only available to portal admins
6635
        if (api_is_platform_admin()) {
6636
            $group[] = $form->createElement(
6637
                'radio',
6638
                'visibility',
6639
                null,
6640
                get_lang('Hidden - Completely hidden to all users except the administrators'),
6641
                Course::HIDDEN
6642
            );
6643
        }
6644
        $form->addGroup($group, '', get_lang('Course access'));
6645
    }
6646
6647
    /**
6648
     * Check if a specific access-url-related setting is a problem or not.
6649
     *
6650
     * @param array  $_configuration The $_configuration array
6651
     * @param int    $accessUrlId    The access URL ID
6652
     * @param string $param
6653
     * @param string $msgLabel
6654
     *
6655
     * @return bool|string
6656
     */
6657
    private static function checkCreateCourseAccessUrlParam($_configuration, $accessUrlId, $param, $msgLabel)
6658
    {
6659
        if (isset($_configuration[$accessUrlId][$param]) && $_configuration[$accessUrlId][$param] > 0) {
6660
            $num = null;
6661
            switch ($param) {
6662
                case 'hosting_limit_courses':
6663
            $num = self::count_courses($accessUrlId);
6664
                    break;
6665
                case 'hosting_limit_active_courses':
6666
                    $num = self::countActiveCourses($accessUrlId);
6667
                    break;
6668
            }
6669
6670
            if ($num && $num >= $_configuration[$accessUrlId][$param]) {
6671
                api_warn_hosting_contact($param);
6672
6673
                Display::addFlash(
6674
                    Display::return_message($msgLabel)
6675
                );
6676
6677
                return true;
6678
            }
6679
        }
6680
6681
        return false;
6682
    }
6683
6684
    /**
6685
     * Fill course with all necessary items.
6686
     * @param Course $course
6687
     * @param array $params Parameters from the course creation form
6688
     * @param ?int   $authorId
6689
     * @throws Exception
6690
     */
6691
    private static function fillCourse(Course $course, array $params, ?int $authorId = 0)
6692
    {
6693
        $authorId = empty($authorId) ? api_get_user_id() : $authorId;
6694
6695
        AddCourse::fillCourse(
6696
            $course,
6697
            $params['exemplary_content'],
6698
            $authorId
6699
        );
6700
6701
        if (isset($params['gradebook_model_id'])) {
6702
            self::createDefaultGradebook(
6703
                $params['gradebook_model_id'],
6704
                $course->getId()
6705
            );
6706
        }
6707
6708
        // If parameter defined, copy the contents from a specific
6709
        // template course into this new course
6710
        if (isset($params['course_template'])) {
6711
            self::useTemplateAsBasisIfRequired(
6712
                $course->getCode(),
6713
                $params['course_template']
6714
            );
6715
        }
6716
        $params['course_code'] = $course->getCode();
6717
        $params['item_id'] = $course->getId();
6718
6719
        $courseFieldValue = new ExtraFieldValue('course');
6720
        //$courseFieldValue->saveFieldValues($params);
6721
    }
6722
}
6723