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

CourseManager::getCoursesFollowedByUser()   F

Complexity

Conditions 14
Paths 480

Size

Total Lines 107
Code Lines 64

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 64
nc 480
nop 10
dl 0
loc 107
rs 2.8222
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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