Completed
Push — master ( 3b3f82...8690b8 )
by Julito
10:13
created

get_details_course_description_html()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 43
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

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