Completed
Push — master ( eedd1b...b75c6e )
by Julito
10:22
created

CourseManager::get_courses_followed_by_drh()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 17
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

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