Passed
Push — master ( 323135...9f183a )
by Julito
13:17
created

CourseManager::getCountForumPerUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 25
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 13
nc 1
nop 3
dl 0
loc 25
rs 9.8333
c 0
b 0
f 0
1
<?php
2
/* For licensing terms, see /license.txt*/
3
4
use Chamilo\CoreBundle\Entity\Course;
5
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
6
use Chamilo\CoreBundle\Framework\Container;
7
use Chamilo\CoreBundle\Hook\HookCreateCourse;
8
use Chamilo\CoreBundle\Repository\CourseRepository;
9
use Chamilo\CoreBundle\ToolChain;
10
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
11
use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
12
use Chamilo\CourseBundle\Manager\SettingsManager;
13
use ChamiloSession as Session;
14
use Doctrine\ORM\EntityManager;
15
16
/**
17
 * Class CourseManager.
18
 *
19
 * This is the course library for Chamilo.
20
 *
21
 * All main course functions should be placed here.
22
 *
23
 * There are probably some places left with the wrong code.
24
 */
25
class CourseManager
26
{
27
    public const MAX_COURSE_LENGTH_CODE = 40;
28
    /** This constant is used to show separate user names in the course
29
     * list (userportal), footer, etc */
30
    public const USER_SEPARATOR = ' |';
31
    public $columns = [];
32
    public static $em;
33
    public static $toolList;
34
    public static $courseSettingsManager;
35
    private static $manager;
36
37
    /**
38
     * @param EntityManager
39
     */
40
    public static function setEntityManager($em)
41
    {
42
        self::$em = $em;
43
    }
44
45
    /**
46
     * @return EntityManager
47
     */
48
    public static function getEntityManager()
49
    {
50
        return self::$em;
51
    }
52
53
    /**
54
     * @return SettingsManager
55
     */
56
    public static function getCourseSettingsManager()
57
    {
58
        return self::$courseSettingsManager;
59
    }
60
61
    /**
62
     * @param SettingsManager $courseSettingsManager
63
     */
64
    public static function setCourseSettingsManager($courseSettingsManager)
65
    {
66
        self::$courseSettingsManager = $courseSettingsManager;
67
    }
68
69
    /**
70
     * @deprecated
71
     *
72
     * @return CourseRepository
73
     */
74
    public static function getManager()
75
    {
76
        return Container::getCourseRepository();
77
    }
78
79
    /**
80
     * Creates a course.
81
     *
82
     * @param array $params      Columns in the main.course table.
83
     * @param int   $authorId    Optional.
84
     * @param int   $accessUrlId Optional.
85
     *
86
     * @return mixed false if the course was not created, array with the course info
87
     */
88
    public static function create_course($params, $authorId = 0, $accessUrlId = 0)
89
    {
90
        global $_configuration;
91
92
        $hook = Container::instantiateHook(HookCreateCourse::class);
93
94
        // Check portal limits
95
        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : api_get_current_access_url_id();
96
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
97
98
        if (isset($_configuration[$accessUrlId]) && is_array($_configuration[$accessUrlId])) {
99
            $return = self::checkCreateCourseAccessUrlParam(
100
                $_configuration,
101
                $accessUrlId,
102
                'hosting_limit_courses',
103
                'PortalCoursesLimitReached'
104
            );
105
            if ($return != false) {
106
                return $return;
107
            }
108
            $return = self::checkCreateCourseAccessUrlParam(
109
                $_configuration,
110
                $accessUrlId,
111
                'hosting_limit_active_courses',
112
                'PortalActiveCoursesLimitReached'
113
            );
114
            if ($return != false) {
115
                return $return;
116
            }
117
        }
118
119
        if (empty($params['title'])) {
120
            return false;
121
        }
122
123
        if (empty($params['wanted_code'])) {
124
            $params['wanted_code'] = $params['title'];
125
            // Check whether the requested course code has already been occupied.
126
            $substring = api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE);
127
            if ($substring === false || empty($substring)) {
128
                return false;
129
            } else {
130
                $params['wanted_code'] = self::generate_course_code($substring);
131
            }
132
        }
133
134
        // Create the course keys
135
        $keys = AddCourse::define_course_keys($params['wanted_code']);
136
        $params['exemplary_content'] = isset($params['exemplary_content']) ? $params['exemplary_content'] : false;
137
138
        if (count($keys)) {
139
            $params['code'] = $keys['currentCourseCode'];
140
            $params['visual_code'] = $keys['currentCourseId'];
141
            $params['directory'] = $keys['currentCourseRepository'];
142
            $courseInfo = api_get_course_info($params['code']);
143
            if (empty($courseInfo)) {
144
                $courseId = AddCourse::register_course($params, $accessUrlId);
145
                $courseInfo = api_get_course_info_by_id($courseId);
146
147
                if ($hook) {
148
                    $hook->setEventData(['course_info' => $courseInfo]);
149
                    $hook->notifyCreateCourse(HOOK_EVENT_TYPE_POST);
150
                }
151
152
                if (!empty($courseInfo)) {
153
                    self::fillCourse($courseInfo, $params, $authorId);
154
155
                    return $courseInfo;
156
                }
157
            }
158
        }
159
160
        return false;
161
    }
162
163
    /**
164
     * Returns all the information of a given course code.
165
     *
166
     * @param string $course_code , the course code
167
     *
168
     * @return array with all the fields of the course table
169
     *
170
     * @deprecated Use api_get_course_info() instead
171
     *
172
     * @author Patrick Cool <[email protected]>, Ghent University
173
     * @assert ('') === false
174
     */
175
    public static function get_course_information($course_code)
176
    {
177
        return Database::fetch_array(
178
            Database::query(
179
                "SELECT *, id as real_id FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
180
                WHERE code = '".Database::escape_string($course_code)."'"
181
            ),
182
            'ASSOC'
183
        );
184
    }
185
186
    /**
187
     * Returns a list of courses. Should work with quickform syntax.
188
     *
189
     * @param int    $from               Offset (from the 7th = '6'). Optional.
190
     * @param int    $howmany            Number of results we want. Optional.
191
     * @param int    $orderby            The column we want to order it by. Optional, defaults to first column.
192
     * @param string $orderdirection     The direction of the order (ASC or DESC). Optional, defaults to ASC.
193
     * @param int    $visibility         the visibility of the course, or all by default
194
     * @param string $startwith          If defined, only return results for which the course *title* begins with this string
195
     * @param string $urlId              The Access URL ID, if using multiple URLs
196
     * @param bool   $alsoSearchCode     An extension option to indicate that we also want to search for course codes (not *only* titles)
197
     * @param array  $conditionsLike
198
     * @param array  $onlyThisCourseList
199
     *
200
     * @return array
201
     */
202
    public static function get_courses_list(
203
        $from = 0,
204
        $howmany = 0,
205
        $orderby = 1,
206
        $orderdirection = 'ASC',
207
        $visibility = -1,
208
        $startwith = '',
209
        $urlId = null,
210
        $alsoSearchCode = false,
211
        $conditionsLike = [],
212
        $onlyThisCourseList = []
213
    ) {
214
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
215
        $sql = "SELECT course.*, course.id as real_id 
216
                FROM $courseTable course ";
217
218
        if (!empty($urlId)) {
219
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
220
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
221
        }
222
223
        $visibility = (int) $visibility;
224
225
        if (!empty($startwith)) {
226
            $sql .= "WHERE (title LIKE '".Database::escape_string($startwith)."%' ";
227
            if ($alsoSearchCode) {
228
                $sql .= "OR code LIKE '".Database::escape_string($startwith)."%' ";
229
            }
230
            $sql .= ') ';
231
            if ($visibility !== -1) {
232
                $sql .= " AND visibility = $visibility ";
233
            }
234
        } else {
235
            $sql .= 'WHERE 1 ';
236
            if ($visibility !== -1) {
237
                $sql .= " AND visibility = $visibility ";
238
            }
239
        }
240
241
        if (!empty($urlId)) {
242
            $urlId = (int) $urlId;
243
            $sql .= " AND access_url_id = $urlId";
244
        }
245
246
        if (!empty($onlyThisCourseList)) {
247
            $onlyThisCourseList = array_map('intval', $onlyThisCourseList);
248
            $onlyThisCourseList = implode("','", $onlyThisCourseList);
249
            $sql .= " AND course.id IN ('$onlyThisCourseList') ";
250
        }
251
252
        $allowedFields = [
253
            'title',
254
            'code',
255
        ];
256
257
        if (count($conditionsLike) > 0) {
258
            $sql .= ' AND ';
259
            $temp_conditions = [];
260
            foreach ($conditionsLike as $field => $value) {
261
                if (!in_array($field, $allowedFields)) {
262
                    continue;
263
                }
264
                $field = Database::escape_string($field);
265
                $value = Database::escape_string($value);
266
                $simple_like = false;
267
                if ($simple_like) {
268
                    $temp_conditions[] = $field." LIKE '$value%'";
269
                } else {
270
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
271
                }
272
            }
273
            $condition = ' AND ';
274
            if (!empty($temp_conditions)) {
275
                $sql .= implode(' '.$condition.' ', $temp_conditions);
276
            }
277
        }
278
279
        if (!empty($orderby)) {
280
            $sql .= " ORDER BY ".Database::escape_string($orderby)." ";
281
        } else {
282
            $sql .= ' ORDER BY 1 ';
283
        }
284
285
        if (!in_array($orderdirection, ['ASC', 'DESC'])) {
286
            $sql .= 'ASC';
287
        } else {
288
            $sql .= ($orderdirection == 'ASC' ? 'ASC' : 'DESC');
289
        }
290
291
        if (!empty($howmany) && is_int($howmany) and $howmany > 0) {
292
            $sql .= ' LIMIT '.Database::escape_string($howmany);
293
        } else {
294
            $sql .= ' LIMIT 1000000'; //virtually no limit
295
        }
296
        if (!empty($from)) {
297
            $from = intval($from);
298
            $sql .= ' OFFSET '.intval($from);
299
        } else {
300
            $sql .= ' OFFSET 0';
301
        }
302
303
        $data = [];
304
        $res = Database::query($sql);
305
        if (Database::num_rows($res) > 0) {
306
            while ($row = Database::fetch_array($res, 'ASSOC')) {
307
                $data[] = $row;
308
            }
309
        }
310
311
        return $data;
312
    }
313
314
    /**
315
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
316
     *
317
     * @param int $userId
318
     * @param int $courseId
319
     *
320
     * @return int|bool the status of the user in that course (or false if the user is not in that course)
321
     */
322
    public static function getUserInCourseStatus($userId, $courseId)
323
    {
324
        $courseId = (int) $courseId;
325
        $userId = (int) $userId;
326
        if (empty($courseId)) {
327
            return false;
328
        }
329
330
        $result = Database::fetch_array(
331
            Database::query(
332
                "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
333
                WHERE
334
                    c_id  = $courseId AND
335
                    user_id = $userId"
336
            )
337
        );
338
339
        return $result['status'];
340
    }
341
342
    /**
343
     * @param int $userId
344
     * @param int $courseId
345
     *
346
     * @return mixed
347
     */
348
    public static function getUserCourseInfo($userId, $courseId)
349
    {
350
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
351
                WHERE
352
                    c_id  = ".intval($courseId)." AND
353
                    user_id = ".intval($userId);
354
        $result = Database::fetch_array(Database::query($sql));
355
356
        return $result;
357
    }
358
359
    /**
360
     * @param int  $userId
361
     * @param int  $courseId
362
     * @param bool $isTutor
363
     *
364
     * @return bool
365
     */
366
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
367
    {
368
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
369
370
        $courseId = intval($courseId);
371
        $isTutor = intval($isTutor);
372
373
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
374
			    WHERE
375
				    user_id = ".$userId." AND
376
				    c_id = ".$courseId;
377
378
        $result = Database::query($sql);
379
380
        if (Database::affected_rows($result) > 0) {
381
            return true;
382
        } else {
383
            return false;
384
        }
385
    }
386
387
    /**
388
     * @param int $userId
389
     * @param int $courseId
390
     *
391
     * @return mixed
392
     */
393
    public static function get_tutor_in_course_status($userId, $courseId)
394
    {
395
        $userId = intval($userId);
396
        $courseId = intval($courseId);
397
        $result = Database::fetch_array(
398
            Database::query(
399
                "SELECT is_tutor
400
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
401
                WHERE
402
                    c_id = $courseId AND
403
                    user_id = $userId"
404
            )
405
        );
406
407
        return $result['is_tutor'];
408
    }
409
410
    /**
411
     * Unsubscribe one or more users from a course.
412
     *
413
     * @param   mixed   user_id or an array with user ids
414
     * @param   string  course code
415
     * @param   int     session id
416
     *
417
     * @return bool
418
     *
419
     * @assert ('', '') === false
420
     */
421
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
422
    {
423
        if (empty($user_id)) {
424
            return false;
425
        }
426
        if (!is_array($user_id)) {
427
            $user_id = [$user_id];
428
        }
429
430
        if (count($user_id) == 0) {
431
            return false;
432
        }
433
434
        if (!empty($session_id)) {
435
            $session_id = (int) $session_id;
436
        } else {
437
            $session_id = api_get_session_id();
438
        }
439
440
        if (empty($course_code)) {
441
            return false;
442
        }
443
444
        $userList = [];
445
        // Cleaning the $user_id variable
446
        if (is_array($user_id)) {
447
            $new_user_id_list = [];
448
            foreach ($user_id as $my_user_id) {
449
                $new_user_id_list[] = (int) $my_user_id;
450
            }
451
            $new_user_id_list = array_filter($new_user_id_list);
452
            $userList = $new_user_id_list;
453
            $user_ids = implode(',', $new_user_id_list);
454
        } else {
455
            $user_ids = (int) $user_id;
456
            $userList[] = $user_id;
457
        }
458
459
        $course_info = api_get_course_info($course_code);
460
        $course_id = $course_info['real_id'];
461
462
        // Unsubscribe user from all groups in the course.
463
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_USER)."
464
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
465
        Database::query($sql);
466
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
467
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
468
        Database::query($sql);
469
470
        // Erase user student publications (works) in the course - by André Boivin
471
        if (!empty($userList)) {
472
            require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
473
            foreach ($userList as $userId) {
474
                // Getting all work from user
475
                $workList = getWorkPerUser($userId);
476
                if (!empty($workList)) {
477
                    foreach ($workList as $work) {
478
                        $work = $work['work'];
479
                        // Getting user results
480
                        if (!empty($work->user_results)) {
481
                            foreach ($work->user_results as $workSent) {
482
                                deleteWorkItem($workSent['id'], $course_info);
483
                            }
484
                        }
485
                    }
486
                }
487
            }
488
        }
489
490
        // Unsubscribe user from all blogs in the course.
491
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_REL_USER)." 
492
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
493
        Database::query($sql);
494
495
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER)." 
496
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
497
        Database::query($sql);
498
499
        // Deleting users in forum_notification and mailqueue course tables
500
        $sql = "DELETE FROM  ".Database::get_course_table(TABLE_FORUM_NOTIFICATION)."
501
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
502
        Database::query($sql);
503
504
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_FORUM_MAIL_QUEUE)."
505
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
506
        Database::query($sql);
507
508
        // Unsubscribe user from the course.
509
        if (!empty($session_id)) {
510
            foreach ($userList as $uid) {
511
                SessionManager::unSubscribeUserFromCourseSession($uid, $course_id, $session_id);
512
513
                // check if a user is register in the session with other course
514
                $sql = "SELECT user_id FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
515
                        WHERE session_id = $session_id AND user_id = $uid";
516
                $rs = Database::query($sql);
517
518
                if (Database::num_rows($rs) == 0) {
519
                    SessionManager::unsubscribe_user_from_session($uid, $session_id);
520
                }
521
            }
522
523
            Event::addEvent(
524
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
525
                LOG_COURSE_CODE,
526
                $course_code,
527
                api_get_utc_datetime(),
528
                $user_id,
529
                $course_id,
530
                $session_id
531
            );
532
        } else {
533
            $sql = "DELETE FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
534
                    WHERE
535
                        user_id IN ($user_ids) AND
536
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
537
                        c_id = $course_id";
538
            Database::query($sql);
539
540
            // add event to system log
541
            $user_id = api_get_user_id();
542
543
            Event::addEvent(
544
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
545
                LOG_COURSE_CODE,
546
                $course_code,
547
                api_get_utc_datetime(),
548
                $user_id,
549
                $course_id
550
            );
551
552
            foreach ($userList as $userId) {
553
                $userInfo = api_get_user_info($userId);
554
                Event::addEvent(
555
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
556
                    LOG_USER_OBJECT,
557
                    $userInfo,
558
                    api_get_utc_datetime(),
559
                    $user_id,
560
                    $course_id
561
                );
562
            }
563
        }
564
    }
565
566
    /**
567
     * @param string $courseCode
568
     * @param int    $status
569
     *
570
     * @return bool
571
     */
572
    public static function autoSubscribeToCourse($courseCode, $status = STUDENT)
573
    {
574
        $courseInfo = api_get_course_info($courseCode);
575
576
        if (empty($courseInfo)) {
577
            return false;
578
        }
579
580
        if (api_is_anonymous()) {
581
            return false;
582
        }
583
584
        if (in_array(
585
            $courseInfo['visibility'],
586
            [
587
                COURSE_VISIBILITY_CLOSED,
588
                COURSE_VISIBILITY_REGISTERED,
589
                COURSE_VISIBILITY_HIDDEN,
590
            ]
591
        )
592
        ) {
593
            Display::addFlash(
594
                Display::return_message(
595
                    get_lang('Subscribing not allowed'),
596
                    'warning'
597
                )
598
            );
599
600
            return false;
601
        }
602
603
        return self::subscribeUser(api_get_user_id(), $courseInfo['code'], $status);
604
    }
605
606
    /**
607
     * Subscribe a user to a course. No checks are performed here to see if
608
     * course subscription is allowed.
609
     *
610
     * @param int    $userId
611
     * @param string $courseCode
612
     * @param int    $status                 (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
613
     * @param int    $sessionId
614
     * @param int    $userCourseCategoryId
615
     * @param bool   $checkTeacherPermission
616
     *
617
     * @return bool True on success, false on failure
618
     *
619
     * @assert ('', '') === false
620
     */
621
    public static function subscribeUser(
622
        $userId,
623
        $courseCode,
624
        $status = STUDENT,
625
        $sessionId = 0,
626
        $userCourseCategoryId = 0,
627
        $checkTeacherPermission = true
628
    ) {
629
        $userId = (int) $userId;
630
        $status = (int) $status;
631
632
        if (empty($userId) || empty($courseCode)) {
633
            return false;
634
        }
635
636
        $courseInfo = api_get_course_info($courseCode);
637
638
        if (empty($courseInfo)) {
639
            Display::addFlash(Display::return_message(get_lang('This course doesn\'t exist'), 'warning'));
640
641
            return false;
642
        }
643
644
        $userInfo = api_get_user_info($userId);
645
646
        if (empty($userInfo)) {
647
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
648
649
            return false;
650
        }
651
652
        $courseId = $courseInfo['real_id'];
653
        $courseCode = $courseInfo['code'];
654
        $userCourseCategoryId = (int) $userCourseCategoryId;
655
656
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
657
        $status = $status === STUDENT || $status === COURSEMANAGER ? $status : STUDENT;
658
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
659
660
        if (!empty($sessionId)) {
661
            SessionManager::subscribe_users_to_session_course(
662
                [$userId],
663
                $sessionId,
664
                $courseCode
665
            );
666
667
            // Add event to the system log
668
            Event::addEvent(
669
                LOG_SUBSCRIBE_USER_TO_COURSE,
670
                LOG_COURSE_CODE,
671
                $courseCode,
672
                api_get_utc_datetime(),
673
                api_get_user_id(),
674
                $courseId,
675
                $sessionId
676
            );
677
            Event::addEvent(
678
                LOG_SUBSCRIBE_USER_TO_COURSE,
679
                LOG_USER_OBJECT,
680
                $userInfo,
681
                api_get_utc_datetime(),
682
                api_get_user_id(),
683
                $courseId,
684
                $sessionId
685
            );
686
687
            return true;
688
        } else {
689
            // Check whether the user has not been already subscribed to the course.
690
            $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."                    
691
                    WHERE 
692
                        user_id = $userId AND 
693
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND 
694
                        c_id = $courseId
695
                    ";
696
            if (Database::num_rows(Database::query($sql)) > 0) {
697
                Display::addFlash(Display::return_message(get_lang('Already registered in course'), 'warning'));
698
699
                return false;
700
            }
701
702
            if ($checkTeacherPermission && !api_is_course_admin()) {
703
                // Check in advance whether subscription is allowed or not for this course.
704
                if ((int) $courseInfo['subscribe'] === SUBSCRIBE_NOT_ALLOWED) {
705
                    Display::addFlash(Display::return_message(get_lang('SubscriptionNotAllowed'), 'warning'));
706
707
                    return false;
708
                }
709
            }
710
711
            if ($status === STUDENT) {
712
                // Check if max students per course extra field is set
713
                $extraFieldValue = new ExtraFieldValue('course');
714
                $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'max_subscribed_students');
715
                if (!empty($value) && isset($value['value'])) {
716
                    $maxStudents = $value['value'];
717
                    if ($maxStudents !== '') {
718
                        $maxStudents = (int) $maxStudents;
719
                        $count = self::get_user_list_from_course_code(
720
                            $courseCode,
721
                            0,
722
                            null,
723
                            null,
724
                            STUDENT,
725
                            true,
726
                            false
727
                        );
728
729
                        if ($count >= $maxStudents) {
730
                            Display::addFlash(Display::return_message(get_lang('The maximum number of student has already been reached, it is not possible to subscribe more student.'), 'warning'));
731
732
                            return false;
733
                        }
734
                    }
735
                }
736
            }
737
738
            $maxSort = api_max_sort_value('0', $userId);
739
            $params = [
740
                'c_id' => $courseId,
741
                'user_id' => $userId,
742
                'status' => $status,
743
                'sort' => $maxSort + 1,
744
                'relation_type' => 0,
745
                'user_course_cat' => (int) $userCourseCategoryId,
746
            ];
747
            $insertId = Database::insert($courseUserTable, $params);
748
749
            if ($insertId) {
750
                Display::addFlash(
751
                    Display::return_message(
752
                        sprintf(
753
                            get_lang('User %s has been registered to course %s'),
754
                            $userInfo['complete_name_with_username'],
755
                            $courseInfo['title']
756
                        )
757
                    )
758
                );
759
760
                $send = api_get_course_setting('email_alert_to_teacher_on_new_user_in_course', $courseInfo);
761
762
                if ($send == 1) {
763
                    self::email_to_tutor(
764
                        $userId,
765
                        $courseInfo['real_id'],
766
                        false
767
                    );
768
                } elseif ($send == 2) {
769
                    self::email_to_tutor(
770
                        $userId,
771
                        $courseInfo['real_id'],
772
                        true
773
                    );
774
                }
775
776
                $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications', $courseInfo);
777
                if ($subscribe === 1) {
778
                    require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
779
                    $forums = get_forums(0, $courseCode, true, $sessionId);
780
                    foreach ($forums as $forum) {
781
                        $forumId = $forum['iid'];
782
                        set_notification('forum', $forumId, false, $userInfo, $courseInfo);
783
                    }
784
                }
785
786
                // Add event to the system log
787
                Event::addEvent(
788
                    LOG_SUBSCRIBE_USER_TO_COURSE,
789
                    LOG_COURSE_CODE,
790
                    $courseCode,
791
                    api_get_utc_datetime(),
792
                    api_get_user_id(),
793
                    $courseId
794
                );
795
796
                Event::addEvent(
797
                    LOG_SUBSCRIBE_USER_TO_COURSE,
798
                    LOG_USER_OBJECT,
799
                    $userInfo,
800
                    api_get_utc_datetime(),
801
                    api_get_user_id(),
802
                    $courseId
803
                );
804
805
                return true;
806
            }
807
808
            return false;
809
        }
810
    }
811
812
    /**
813
     * Get the course id based on the original id and field name in the
814
     * extra fields. Returns 0 if course was not found.
815
     *
816
     * @param string $original_course_id_value
817
     * @param string $original_course_id_name
818
     *
819
     * @return int Course id
820
     *
821
     * @assert ('', '') === false
822
     */
823
    public static function get_course_code_from_original_id(
824
        $original_course_id_value,
825
        $original_course_id_name
826
    ) {
827
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
828
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
829
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
830
        $original_course_id_value = Database::escape_string($original_course_id_value);
831
        $original_course_id_name = Database::escape_string($original_course_id_name);
832
833
        $sql = "SELECT item_id
834
                FROM $table_field cf
835
                INNER JOIN $t_cfv cfv
836
                ON cfv.field_id=cf.id
837
                WHERE
838
                    variable = '$original_course_id_name' AND
839
                    value = '$original_course_id_value' AND
840
                    cf.extra_field_type = $extraFieldType
841
                ";
842
        $res = Database::query($sql);
843
        $row = Database::fetch_object($res);
844
        if ($row) {
845
            return $row->item_id;
846
        } else {
847
            return 0;
848
        }
849
    }
850
851
    /**
852
     * Gets the course code from the course id. Returns null if course id was not found.
853
     *
854
     * @param int $id Course id
855
     *
856
     * @return string Course code
857
     * @assert ('') === false
858
     */
859
    public static function get_course_code_from_course_id($id)
860
    {
861
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
862
        $id = intval($id);
863
        $sql = "SELECT code FROM $table WHERE id = $id ";
864
        $res = Database::query($sql);
865
        $row = Database::fetch_object($res);
866
        if ($row) {
867
            return $row->code;
868
        } else {
869
            return null;
870
        }
871
    }
872
873
    /**
874
     * Add the user $userId visibility to the course $courseCode in the catalogue.
875
     *
876
     * @author David Nos (https://github.com/dnos)
877
     *
878
     * @param int    $userId     the id of the user
879
     * @param string $courseCode the course code
880
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
881
     *
882
     * @return bool true if added succesfully, false otherwise
883
     */
884
    public static function addUserVisibilityToCourseInCatalogue(
885
        $userId,
886
        $courseCode,
887
        $visible = 1
888
    ) {
889
        $debug = false;
890
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
891
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
892
        $visible = (int) $visible;
893
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
894
            return false;
895
        }
896
897
        $courseCode = Database::escape_string($courseCode);
898
        $courseInfo = api_get_course_info($courseCode);
899
        $courseId = $courseInfo['real_id'];
900
901
        // Check in advance whether the user has already been registered on the platform.
902
        $sql = "SELECT status FROM ".$userTable." WHERE user_id = $userId ";
903
        if (Database::num_rows(Database::query($sql)) == 0) {
904
            if ($debug) {
905
                error_log('The user has not been registered to the platform');
906
            }
907
908
            return false; // The user has not been registered to the platform.
909
        }
910
911
        // Check whether the user has already been registered to the course visibility in the catalogue.
912
        $sql = "SELECT * FROM $courseUserTable
913
                WHERE
914
                    user_id = $userId AND
915
                    visible = $visible AND
916
                    c_id = $courseId";
917
        if (Database::num_rows(Database::query($sql)) > 0) {
918
            if ($debug) {
919
                error_log('The user has been already registered to the course visibility in the catalogue');
920
            }
921
922
            return true; // The visibility of the user to the course in the catalogue does already exist.
923
        }
924
925
        // Register the user visibility to course in catalogue.
926
        $params = [
927
            'user_id' => $userId,
928
            'c_id' => $courseId,
929
            'visible' => $visible,
930
        ];
931
        $insertId = Database::insert($courseUserTable, $params);
932
933
        return $insertId;
934
    }
935
936
    /**
937
     * Remove the user $userId visibility to the course $courseCode in the catalogue.
938
     *
939
     * @author David Nos (https://github.com/dnos)
940
     *
941
     * @param int    $userId     the id of the user
942
     * @param string $courseCode the course code
943
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
944
     *
945
     * @return bool true if removed succesfully or register not found, false otherwise
946
     */
947
    public static function removeUserVisibilityToCourseInCatalogue(
948
        $userId,
949
        $courseCode,
950
        $visible = 1
951
    ) {
952
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
953
954
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
955
            return false;
956
        }
957
958
        $courseCode = Database::escape_string($courseCode);
959
        $courseInfo = api_get_course_info($courseCode);
960
        $courseId = $courseInfo['real_id'];
961
962
        // Check whether the user has already been registered to the course visibility in the catalogue.
963
        $sql = "SELECT * FROM $courseUserTable
964
                WHERE
965
                    user_id = $userId AND
966
                    visible = $visible AND
967
                    c_id = $courseId";
968
        if (Database::num_rows(Database::query($sql)) > 0) {
969
            $cond = [
970
                'user_id = ? AND c_id = ? AND visible = ? ' => [
971
                    $userId,
972
                    $courseId,
973
                    $visible,
974
                ],
975
            ];
976
977
            return Database::delete($courseUserTable, $cond);
978
        } else {
979
            return true; // Register does not exist
980
        }
981
    }
982
983
    /**
984
     * @param string $code
985
     *
986
     * @return bool if there already are one or more courses
987
     *              with the same code OR visual_code (visualcode), false otherwise
988
     */
989
    public static function course_code_exists($code)
990
    {
991
        $code = Database::escape_string($code);
992
        $sql = "SELECT COUNT(*) as number
993
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
994
                WHERE code = '$code' OR visual_code = '$code'";
995
        $result = Database::fetch_array(Database::query($sql));
996
997
        return $result['number'] > 0;
998
    }
999
1000
    /**
1001
     * @param int    $user_id
1002
     * @param string $startsWith Optional
1003
     *
1004
     * @return array an array with the course info of all the courses (real and virtual)
1005
     *               of which the current user is course admin
1006
     */
1007
    public static function get_course_list_of_user_as_course_admin($user_id, $startsWith = '')
1008
    {
1009
        if ($user_id != strval(intval($user_id))) {
1010
            return [];
1011
        }
1012
1013
        // Definitions database tables and variables
1014
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1015
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1016
        $user_id = intval($user_id);
1017
        $data = [];
1018
1019
        $sql = "SELECT
1020
                    course.code,
1021
                    course.title,
1022
                    course.id,
1023
                    course.id as real_id,
1024
                    course.category_code
1025
                FROM $tbl_course_user as course_rel_user
1026
                INNER JOIN $tbl_course as course
1027
                ON course.id = course_rel_user.c_id
1028
                WHERE
1029
                    course_rel_user.user_id = $user_id AND
1030
                    course_rel_user.status = 1
1031
        ";
1032
1033
        if (api_get_multiple_access_url()) {
1034
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
1035
            $access_url_id = api_get_current_access_url_id();
1036
            if ($access_url_id != -1) {
1037
                $sql = "
1038
                    SELECT
1039
                        course.code,
1040
                        course.title,
1041
                        course.id,
1042
                        course.id as real_id
1043
                    FROM $tbl_course_user as course_rel_user
1044
                    INNER JOIN $tbl_course as course
1045
                    ON course.id = course_rel_user.c_id
1046
                    INNER JOIN $tbl_course_rel_access_url course_rel_url
1047
                    ON (course_rel_url.c_id = course.id)
1048
                    WHERE
1049
                        access_url_id = $access_url_id  AND
1050
                        course_rel_user.user_id = $user_id AND
1051
                        course_rel_user.status = 1
1052
                ";
1053
            }
1054
        }
1055
1056
        if (!empty($startsWith)) {
1057
            $startsWith = Database::escape_string($startsWith);
1058
1059
            $sql .= " AND (course.title LIKE '$startsWith%' OR course.code LIKE '$startsWith%')";
1060
        }
1061
1062
        $sql .= ' ORDER BY course.title';
1063
1064
        $result_nb_cours = Database::query($sql);
1065
        if (Database::num_rows($result_nb_cours) > 0) {
1066
            while ($row = Database::fetch_array($result_nb_cours, 'ASSOC')) {
1067
                $data[$row['id']] = $row;
1068
            }
1069
        }
1070
1071
        return $data;
1072
    }
1073
1074
    /**
1075
     * @param int   $userId
1076
     * @param array $courseInfo
1077
     *
1078
     * @return bool|null
1079
     */
1080
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
1081
    {
1082
        $userId = intval($userId);
1083
1084
        if (!api_is_drh()) {
1085
            return false;
1086
        }
1087
1088
        if (empty($courseInfo) || empty($userId)) {
1089
            return false;
1090
        }
1091
1092
        $courseId = intval($courseInfo['real_id']);
1093
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1094
1095
        $sql = "SELECT * FROM $table
1096
                WHERE
1097
                    user_id = $userId AND
1098
                    relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
1099
                    c_id = $courseId";
1100
1101
        $result = Database::fetch_array(Database::query($sql));
1102
1103
        if (!empty($result)) {
1104
            // The user has been registered in this course.
1105
            return true;
1106
        }
1107
    }
1108
1109
    /**
1110
     * Check if user is subscribed inside a course.
1111
     *
1112
     * @param int    $user_id
1113
     * @param string $course_code  , if this parameter is null, it'll check for all courses
1114
     * @param bool   $in_a_session True for checking inside sessions too, by default is not checked
1115
     * @param int    $session_id
1116
     *
1117
     * @return bool $session_id true if the user is registered in the course, false otherwise
1118
     */
1119
    public static function is_user_subscribed_in_course(
1120
        $user_id,
1121
        $course_code = null,
1122
        $in_a_session = false,
1123
        $session_id = 0
1124
    ) {
1125
        $user_id = (int) $user_id;
1126
        $session_id = (int) $session_id;
1127
1128
        if (empty($session_id)) {
1129
            $session_id = api_get_session_id();
1130
        }
1131
1132
        $condition_course = '';
1133
        if (isset($course_code)) {
1134
            $courseInfo = api_get_course_info($course_code);
1135
            if (empty($courseInfo)) {
1136
                return false;
1137
            }
1138
            $courseId = $courseInfo['real_id'];
1139
            $condition_course = " AND c_id = $courseId";
1140
        }
1141
1142
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1143
                WHERE
1144
                    user_id = $user_id AND
1145
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1146
                    $condition_course ";
1147
1148
        $result = Database::fetch_array(Database::query($sql));
1149
1150
        if (!empty($result)) {
1151
            // The user has been registered in this course.
1152
            return true;
1153
        }
1154
1155
        if (!$in_a_session) {
1156
            // The user has not been registered in this course.
1157
            return false;
1158
        }
1159
1160
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1161
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1162
                WHERE user_id = $user_id AND session_id = $session_id $condition_course";
1163
1164
        if (Database::num_rows(Database::query($sql)) > 0) {
1165
            return true;
1166
        }
1167
1168
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1169
                WHERE user_id = $user_id AND session_id = $session_id AND status = 2 $condition_course";
1170
1171
        if (Database::num_rows(Database::query($sql)) > 0) {
1172
            return true;
1173
        }
1174
1175
        $sql = 'SELECT 1 FROM '.Database::get_main_table(TABLE_MAIN_SESSION).
1176
              " WHERE id = $session_id AND id_coach = $user_id";
1177
1178
        if (Database::num_rows(Database::query($sql)) > 0) {
1179
            return true;
1180
        }
1181
1182
        return false;
1183
    }
1184
1185
    /**
1186
     * Is the user a teacher in the given course?
1187
     *
1188
     * @param int    $user_id     , the id (int) of the user
1189
     * @param string $course_code , the course code
1190
     *
1191
     * @return bool if the user is a teacher in the course, false otherwise
1192
     */
1193
    public static function is_course_teacher($user_id, $course_code)
1194
    {
1195
        if ($user_id != strval(intval($user_id))) {
1196
            return false;
1197
        }
1198
1199
        $courseInfo = api_get_course_info($course_code);
1200
        if (empty($courseInfo)) {
1201
            return false;
1202
        }
1203
        $courseId = $courseInfo['real_id'];
1204
        $sql = "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1205
                WHERE c_id = $courseId AND user_id = $user_id ";
1206
        $result = Database::query($sql);
1207
1208
        if (Database::num_rows($result) > 0) {
1209
            return Database::result($result, 0, 'status') == 1;
1210
        }
1211
1212
        return false;
1213
    }
1214
1215
    /**
1216
     *    Is the user subscribed in the real course or linked courses?
1217
     *
1218
     * @param int the id of the user
1219
     * @param int $courseId
1220
     *
1221
     * @deprecated linked_courses definition doesn't exists
1222
     *
1223
     * @return bool if the user is registered in the real course or linked courses, false otherwise
1224
     */
1225
    public static function is_user_subscribed_in_real_or_linked_course($user_id, $courseId, $session_id = 0)
1226
    {
1227
        if ($user_id != strval(intval($user_id))) {
1228
            return false;
1229
        }
1230
1231
        $courseId = intval($courseId);
1232
        $session_id = intval($session_id);
1233
1234
        if (empty($session_id)) {
1235
            $result = Database::fetch_array(
1236
                Database::query(
1237
                    "SELECT *
1238
                    FROM ".Database::get_main_table(TABLE_MAIN_COURSE)." course
1239
                    LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." course_user
1240
                    ON course.id = course_user.c_id
1241
                    WHERE
1242
                        course_user.user_id = $user_id AND
1243
                        course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
1244
                        ( course.id = $courseId)"
1245
                )
1246
            );
1247
1248
            return !empty($result);
1249
        }
1250
1251
        // From here we trust session id.
1252
        // Is he/she subscribed to the session's course?
1253
        // A user?
1254
        if (Database::num_rows(Database::query("SELECT user_id
1255
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
1256
                WHERE session_id = $session_id
1257
                AND user_id = $user_id"))
1258
        ) {
1259
            return true;
1260
        }
1261
1262
        // A course coach?
1263
        if (Database::num_rows(Database::query("SELECT user_id
1264
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
1265
                WHERE session_id = $session_id
1266
                AND user_id = $user_id AND status = 2
1267
                AND c_id = $courseId"))
1268
        ) {
1269
            return true;
1270
        }
1271
1272
        // A session coach?
1273
        if (Database::num_rows(Database::query("SELECT id_coach
1274
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION)." AS session
1275
                WHERE session.id = $session_id
1276
                AND id_coach = $user_id"))
1277
        ) {
1278
            return true;
1279
        }
1280
1281
        return false;
1282
    }
1283
1284
    /**
1285
     * Return user info array of all users registered in a course
1286
     * This only returns the users that are registered in this actual course, not linked courses.
1287
     *
1288
     * @param string    $course_code
1289
     * @param int       $session_id
1290
     * @param string    $limit
1291
     * @param string    $order_by         the field to order the users by.
1292
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email', 'official_code' OR a part of a SQL statement
1293
     *                                    that starts with ORDER BY ...
1294
     * @param int|null  $filter_by_status if using the session_id: 0 or 2 (student, coach),
1295
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1296
     * @param bool|null $return_count
1297
     * @param bool      $add_reports
1298
     * @param bool      $resumed_report
1299
     * @param array     $extra_field
1300
     * @param array     $courseCodeList
1301
     * @param array     $userIdList
1302
     * @param string    $filterByActive
1303
     * @param array     $sessionIdList
1304
     * @param string    $searchByKeyword
1305
     *
1306
     * @return array|int
1307
     */
1308
    public static function get_user_list_from_course_code(
1309
        $course_code = null,
1310
        $session_id = 0,
1311
        $limit = null,
1312
        $order_by = null,
1313
        $filter_by_status = null,
1314
        $return_count = null,
1315
        $add_reports = false,
1316
        $resumed_report = false,
1317
        $extra_field = [],
1318
        $courseCodeList = [],
1319
        $userIdList = [],
1320
        $filterByActive = null,
1321
        $sessionIdList = [],
1322
        $searchByKeyword = ''
1323
    ) {
1324
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1325
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1326
1327
        $session_id = (int) $session_id;
1328
        $course_code = Database::escape_string($course_code);
1329
        $courseInfo = api_get_course_info($course_code);
1330
        $courseId = 0;
1331
        if (!empty($courseInfo)) {
1332
            $courseId = $courseInfo['real_id'];
1333
        }
1334
1335
        $where = [];
1336
        if (empty($order_by)) {
1337
            $order_by = 'user.lastname, user.firstname';
1338
            if (api_is_western_name_order()) {
1339
                $order_by = 'user.firstname, user.lastname';
1340
            }
1341
        }
1342
1343
        // if the $order_by does not contain 'ORDER BY'
1344
        // we have to check if it is a valid field that can be sorted on
1345
        if (!strstr($order_by, 'ORDER BY')) {
1346
            if (!empty($order_by)) {
1347
                $order_by = "ORDER BY $order_by";
1348
            } else {
1349
                $order_by = '';
1350
            }
1351
        }
1352
1353
        $filter_by_status_condition = null;
1354
1355
        if (!empty($session_id) || !empty($sessionIdList)) {
1356
            $sql = 'SELECT DISTINCT
1357
                        user.user_id,
1358
                        user.email,
1359
                        session_course_user.status as status_session,
1360
                        session_id,
1361
                        user.*,
1362
                        course.*,
1363
                        course.id AS c_id,
1364
                        session.name as session_name
1365
                    ';
1366
            if ($return_count) {
1367
                $sql = " SELECT COUNT(user.user_id) as count";
1368
            }
1369
1370
            $sessionCondition = " session_course_user.session_id = $session_id";
1371
            if (!empty($sessionIdList)) {
1372
                $sessionIdListTostring = implode("','", array_map('intval', $sessionIdList));
1373
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListTostring') ";
1374
            }
1375
1376
            $courseCondition = " course.id = $courseId";
1377
            if (!empty($courseCodeList)) {
1378
                $courseCodeListForSession = array_map(['Database', 'escape_string'], $courseCodeList);
1379
                $courseCodeListForSession = implode('","', $courseCodeListForSession);
1380
                $courseCondition = " course.code IN ('$courseCodeListForSession')  ";
1381
            }
1382
1383
            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
1384
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." as session_course_user
1385
                      ON
1386
                        user.id = session_course_user.user_id AND
1387
                        $sessionCondition
1388
                        INNER JOIN $course_table course 
1389
                        ON session_course_user.c_id = course.id AND
1390
                        $courseCondition
1391
                        INNER JOIN $sessionTable session 
1392
                        ON session_course_user.session_id = session.id
1393
                   ";
1394
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1395
1396
            // 2 = coach
1397
            // 0 = student
1398
            if (isset($filter_by_status)) {
1399
                $filter_by_status = intval($filter_by_status);
1400
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1401
            }
1402
        } else {
1403
            if ($return_count) {
1404
                $sql = " SELECT COUNT(*) as count";
1405
            } else {
1406
                if (empty($course_code)) {
1407
                    $sql = 'SELECT DISTINCT
1408
                                course.title,
1409
                                course.code,
1410
                                course.id AS c_id,
1411
                                course_rel_user.status as status_rel,
1412
                                user.id as user_id,
1413
                                user.email,
1414
                                course_rel_user.is_tutor,
1415
                                user.*  ';
1416
                } else {
1417
                    $sql = 'SELECT DISTINCT
1418
                                course_rel_user.status as status_rel,
1419
                                user.id as user_id,
1420
                                user.email,
1421
                                course_rel_user.is_tutor,
1422
                                user.*  ';
1423
                }
1424
            }
1425
1426
            $sql .= " FROM ".Database::get_main_table(TABLE_MAIN_USER)." as user 
1427
                      LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." as course_rel_user
1428
                      ON 
1429
                        user.id = course_rel_user.user_id AND
1430
                        course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1431
                       INNER JOIN $course_table course 
1432
                       ON course_rel_user.c_id = course.id ";
1433
1434
            if (!empty($course_code)) {
1435
                $sql .= " AND course_rel_user.c_id = $courseId";
1436
            }
1437
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1438
1439
            if (isset($filter_by_status) && is_numeric($filter_by_status)) {
1440
                $filter_by_status = (int) $filter_by_status;
1441
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1442
            }
1443
        }
1444
1445
        $multiple_access_url = api_get_multiple_access_url();
1446
        if ($multiple_access_url) {
1447
            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au
1448
                      ON (au.user_id = user.id) ';
1449
        }
1450
1451
        $extraFieldWasAdded = false;
1452
        if ($return_count && $resumed_report) {
1453
            foreach ($extra_field as $extraField) {
1454
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1455
                if (!empty($extraFieldInfo)) {
1456
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1457
                    $sql .= " LEFT JOIN $fieldValuesTable as ufv
1458
                            ON (
1459
                                user.id = ufv.item_id AND
1460
                                (field_id = ".$extraFieldInfo['id']." OR field_id IS NULL)
1461
                            )";
1462
                    $extraFieldWasAdded = true;
1463
                }
1464
            }
1465
        }
1466
1467
        $sql .= " WHERE $filter_by_status_condition ".implode(' OR ', $where);
1468
1469
        if ($multiple_access_url) {
1470
            $current_access_url_id = api_get_current_access_url_id();
1471
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1472
        }
1473
1474
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1475
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1476
        }
1477
1478
        if (!empty($courseCodeList)) {
1479
            $courseCodeList = array_map(['Database', 'escape_string'], $courseCodeList);
1480
            $courseCodeList = implode('","', $courseCodeList);
1481
            if (empty($sessionIdList)) {
1482
                $sql .= ' AND course.code IN ("'.$courseCodeList.'")';
1483
            }
1484
        }
1485
1486
        if (!empty($userIdList)) {
1487
            $userIdList = array_map('intval', $userIdList);
1488
            $userIdList = implode('","', $userIdList);
1489
            $sql .= ' AND user.id IN ("'.$userIdList.'")';
1490
        }
1491
1492
        if (isset($filterByActive)) {
1493
            $filterByActive = (int) $filterByActive;
1494
            $sql .= " AND user.active = $filterByActive";
1495
        }
1496
1497
        if (!empty($searchByKeyword)) {
1498
            $searchByKeyword = Database::escape_string($searchByKeyword);
1499
            $sql .= " AND (
1500
                        user.firstname LIKE '$searchByKeyword' OR 
1501
                        user.username LIKE '$searchByKeyword' OR 
1502
                        user.lastname LIKE '$searchByKeyword'
1503
                    ) ";
1504
        }
1505
1506
        $sql .= " $order_by $limit";
1507
1508
        $rs = Database::query($sql);
1509
        $users = [];
1510
1511
        $extra_fields = UserManager::get_extra_fields(
1512
            0,
1513
            100,
1514
            null,
1515
            null,
1516
            true,
1517
            true
1518
        );
1519
1520
        $counter = 1;
1521
        $count_rows = Database::num_rows($rs);
1522
1523
        if ($return_count && $resumed_report) {
1524
            return $count_rows;
1525
        }
1526
1527
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1528
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1529
        if ($count_rows) {
1530
            while ($user = Database::fetch_array($rs)) {
1531
                if ($return_count) {
1532
                    return $user['count'];
1533
                }
1534
                $report_info = [];
1535
                $user_info = $user;
1536
                $user_info['status'] = $user['status'];
1537
                if (isset($user['is_tutor'])) {
1538
                    $user_info['is_tutor'] = $user['is_tutor'];
1539
                }
1540
                if (!empty($session_id)) {
1541
                    $user_info['status_session'] = $user['status_session'];
1542
                }
1543
1544
                $sessionId = isset($user['session_id']) ? $user['session_id'] : 0;
1545
                $course_code = isset($user['code']) ? $user['code'] : null;
1546
1547
                if ($add_reports) {
1548
                    if ($resumed_report) {
1549
                        $extra = [];
1550
1551
                        if (!empty($extra_fields)) {
1552
                            foreach ($extra_fields as $extra) {
1553
                                if (in_array($extra['1'], $extra_field)) {
1554
                                    $user_data = UserManager::get_extra_user_data_by_field(
1555
                                        $user['user_id'],
1556
                                        $extra['1']
1557
                                    );
1558
                                    break;
1559
                                }
1560
                            }
1561
                        }
1562
1563
                        $row_key = '-1';
1564
                        $name = '-';
1565
1566
                        if (!empty($extra)) {
1567
                            if (!empty($user_data[$extra['1']])) {
1568
                                $row_key = $user_data[$extra['1']];
1569
                                $name = $user_data[$extra['1']];
1570
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1571
                            }
1572
                        }
1573
1574
                        if (empty($users[$row_key])) {
1575
                            $users[$row_key] = [];
1576
                        }
1577
1578
                        if (!array_key_exists('training_hours', $users[$row_key])) {
1579
                            $users[$row_key]['training_hours'] = 0;
1580
                        }
1581
1582
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1583
                            $user['user_id'],
1584
                            $courseId,
1585
                            $sessionId
1586
                        );
1587
1588
                        if (!array_key_exists('count_users', $users[$row_key])) {
1589
                            $users[$row_key]['count_users'] = 0;
1590
                        }
1591
1592
                        $users[$row_key]['count_users'] += $counter;
1593
1594
                        $registered_users_with_extra_field = self::getCountRegisteredUsersWithCourseExtraField(
1595
                            $name,
1596
                            $tableExtraField,
1597
                            $table_user_field_value
1598
                        );
1599
1600
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1601
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1602
1603
                        $category = Category:: load(
1604
                            null,
1605
                            null,
1606
                            $course_code,
1607
                            null,
1608
                            null,
1609
                            $sessionId
1610
                        );
1611
1612
                        if (!isset($users[$row_key]['count_certificates'])) {
1613
                            $users[$row_key]['count_certificates'] = 0;
1614
                        }
1615
1616
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1617
                            $users[$row_key]['count_certificates']++;
1618
                        }
1619
1620
                        foreach ($extra_fields as $extra) {
1621
                            if ($extra['1'] == 'ruc') {
1622
                                continue;
1623
                            }
1624
1625
                            if (!isset($users[$row_key][$extra['1']])) {
1626
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1627
                                if (!empty($user_data[$extra['1']])) {
1628
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1629
                                }
1630
                            }
1631
                        }
1632
                    } else {
1633
                        $sessionName = !empty($sessionId) ? ' - '.$user['session_name'] : '';
1634
                        $report_info['course'] = $user['title'].$sessionName;
1635
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1636
                        $report_info['email'] = $user['email'];
1637
                        $report_info['time'] = api_time_to_hms(
1638
                            Tracking::get_time_spent_on_the_course(
1639
                                $user['user_id'],
1640
                                empty($user['c_id']) ? $courseId : $user['c_id'],
1641
                                $sessionId
1642
                            )
1643
                        );
1644
1645
                        $category = Category:: load(
1646
                            null,
1647
                            null,
1648
                            $course_code,
1649
                            null,
1650
                            null,
1651
                            $sessionId
1652
                        );
1653
1654
                        $report_info['certificate'] = Display::label(get_lang('No'));
1655
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1656
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1657
                        }
1658
1659
                        $progress = intval(
1660
                            Tracking::get_avg_student_progress(
1661
                                $user['user_id'],
1662
                                $course_code,
1663
                                [],
1664
                                $sessionId
1665
                            )
1666
                        );
1667
1668
                        $report_info['progress_100'] = $progress == 100 ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1669
                        $report_info['progress'] = $progress."%";
1670
1671
                        foreach ($extra_fields as $extra) {
1672
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1673
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1674
                        }
1675
                        $report_info['user_id'] = $user['user_id'];
1676
                        $users[] = $report_info;
1677
                    }
1678
                } else {
1679
                    $users[$user['user_id']] = $user_info;
1680
                }
1681
            }
1682
        }
1683
1684
        return $users;
1685
    }
1686
1687
    /**
1688
     * @param bool  $resumed_report
1689
     * @param array $extra_field
1690
     * @param array $courseCodeList
1691
     * @param array $userIdList
1692
     * @param array $sessionIdList
1693
     *
1694
     * @return array|int
1695
     */
1696
    public static function get_count_user_list_from_course_code(
1697
        $resumed_report = false,
1698
        $extra_field = [],
1699
        $courseCodeList = [],
1700
        $userIdList = [],
1701
        $sessionIdList = []
1702
    ) {
1703
        return self::get_user_list_from_course_code(
1704
            null,
1705
            0,
1706
            null,
1707
            null,
1708
            null,
1709
            true,
1710
            false,
1711
            $resumed_report,
1712
            $extra_field,
1713
            $courseCodeList,
1714
            $userIdList,
1715
            null,
1716
            $sessionIdList
1717
        );
1718
    }
1719
1720
    /**
1721
     * Gets subscribed users in a course or in a course/session.
1722
     *
1723
     * @param string $course_code
1724
     * @param int    $session_id
1725
     *
1726
     * @return int
1727
     */
1728
    public static function get_users_count_in_course(
1729
        $course_code,
1730
        $session_id = 0,
1731
        $status = null
1732
    ) {
1733
        // variable initialisation
1734
        $session_id = (int) $session_id;
1735
        $course_code = Database::escape_string($course_code);
1736
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
1737
        $tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1738
        $tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1739
        $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1740
1741
        $courseInfo = api_get_course_info($course_code);
1742
        $courseId = $courseInfo['real_id'];
1743
1744
        $sql = "
1745
            SELECT DISTINCT count(user.id) as count  
1746
            FROM $tblUser as user
1747
        ";
1748
        $where = [];
1749
        if (!empty($session_id)) {
1750
            $sql .= "
1751
                LEFT JOIN $tblSessionCourseUser as session_course_user
1752
                    ON user.user_id = session_course_user.user_id
1753
                    AND session_course_user.c_id = $courseId
1754
                    AND session_course_user.session_id = $session_id
1755
            ";
1756
1757
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1758
        } else {
1759
            $sql .= "
1760
                LEFT JOIN $tblCourseUser as course_rel_user
1761
                    ON user.user_id = course_rel_user.user_id
1762
                    AND course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1763
                    AND course_rel_user.c_id = $courseId
1764
            ";
1765
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1766
        }
1767
1768
        $multiple_access_url = api_get_multiple_access_url();
1769
        if ($multiple_access_url) {
1770
            $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.user_id) ";
1771
        }
1772
1773
        $sql .= ' WHERE '.implode(' OR ', $where);
1774
1775
        if ($multiple_access_url) {
1776
            $current_access_url_id = api_get_current_access_url_id();
1777
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1778
        }
1779
        $rs = Database::query($sql);
1780
        $count = 0;
1781
        if (Database::num_rows($rs)) {
1782
            $user = Database::fetch_array($rs);
1783
            $count = $user['count'];
1784
        }
1785
1786
        return $count;
1787
    }
1788
1789
    /**
1790
     * Get a list of coaches of a course and a session.
1791
     *
1792
     * @param string $course_code
1793
     * @param int    $session_id
1794
     * @param bool   $addGeneralCoach
1795
     *
1796
     * @return array List of users
1797
     */
1798
    public static function get_coach_list_from_course_code(
1799
        $course_code,
1800
        $session_id,
1801
        $addGeneralCoach = true
1802
    ) {
1803
        if (empty($course_code) || empty($session_id)) {
1804
            return [];
1805
        }
1806
1807
        $course_code = Database::escape_string($course_code);
1808
        $courseInfo = api_get_course_info($course_code);
1809
        $courseId = $courseInfo['real_id'];
1810
        $session_id = (int) $session_id;
1811
        $users = [];
1812
1813
        // We get the coach for the given course in a given session.
1814
        $sql = 'SELECT user_id FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).
1815
               " WHERE session_id = $session_id AND c_id = $courseId AND status = 2";
1816
        $rs = Database::query($sql);
1817
        while ($user = Database::fetch_array($rs)) {
1818
            $userInfo = api_get_user_info($user['user_id']);
1819
            if ($userInfo) {
1820
                $users[$user['user_id']] = $userInfo;
1821
            }
1822
        }
1823
1824
        if ($addGeneralCoach) {
1825
            $table = Database::get_main_table(TABLE_MAIN_SESSION);
1826
            // We get the session coach.
1827
            $sql = "SELECT id_coach FROM $table WHERE id = $session_id";
1828
            $rs = Database::query($sql);
1829
            $session_id_coach = Database::result($rs, 0, 'id_coach');
1830
            if (is_int($session_id_coach)) {
1831
                $userInfo = api_get_user_info($session_id_coach);
1832
                if ($userInfo) {
1833
                    $users[$session_id_coach] = $userInfo;
1834
                }
1835
            }
1836
        }
1837
1838
        return $users;
1839
    }
1840
1841
    /**
1842
     *  Return user info array of all users registered in a course
1843
     *  This only returns the users that are registered in this actual course, not linked courses.
1844
     *
1845
     * @param string $course_code
1846
     * @param bool   $with_session
1847
     * @param int    $session_id
1848
     * @param string $date_from
1849
     * @param string $date_to
1850
     * @param bool   $includeInvitedUsers Whether include the invited users
1851
     * @param int    $groupId
1852
     *
1853
     * @return array with user id
1854
     */
1855
    public static function get_student_list_from_course_code(
1856
        $course_code,
1857
        $with_session = false,
1858
        $session_id = 0,
1859
        $date_from = null,
1860
        $date_to = null,
1861
        $includeInvitedUsers = true,
1862
        $groupId = 0
1863
    ) {
1864
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1865
        $session_id = (int) $session_id;
1866
        $courseInfo = api_get_course_info($course_code);
1867
        if (empty($courseInfo)) {
1868
            return [];
1869
        }
1870
        $courseId = $courseInfo['real_id'];
1871
        $students = [];
1872
1873
        if ($session_id == 0) {
1874
            if (empty($groupId)) {
1875
                // students directly subscribed to the course
1876
                $sql = "SELECT *
1877
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1878
                        INNER JOIN $userTable u
1879
                        ON cu.user_id = u.user_id
1880
                        WHERE c_id = $courseId AND cu.status = ".STUDENT;
1881
1882
                if (!$includeInvitedUsers) {
1883
                    $sql .= " AND u.status != ".INVITEE;
1884
                }
1885
                $rs = Database::query($sql);
1886
                while ($student = Database::fetch_array($rs)) {
1887
                    $students[$student['user_id']] = $student;
1888
                }
1889
            } else {
1890
                $students = GroupManager::get_users(
1891
                    $groupId,
1892
                    false,
1893
                    null,
1894
                    null,
1895
                    false,
1896
                    $courseInfo['real_id']
1897
                );
1898
                $students = array_flip($students);
1899
            }
1900
        }
1901
1902
        // students subscribed to the course through a session
1903
        if ($with_session) {
1904
            $joinSession = '';
1905
            //Session creation date
1906
            if (!empty($date_from) && !empty($date_to)) {
1907
                $joinSession = "INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s";
1908
            }
1909
1910
            $sql_query = "SELECT *
1911
                          FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
1912
                          $joinSession
1913
                          INNER JOIN $userTable u ON scu.user_id = u.user_id
1914
                          WHERE scu.c_id = $courseId AND scu.status <> 2";
1915
1916
            if (!empty($date_from) && !empty($date_to)) {
1917
                $date_from = Database::escape_string($date_from);
1918
                $date_to = Database::escape_string($date_to);
1919
                $sql_query .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
1920
            }
1921
1922
            if ($session_id != 0) {
1923
                $sql_query .= " AND scu.session_id = $session_id";
1924
            }
1925
1926
            if (!$includeInvitedUsers) {
1927
                $sql_query .= " AND u.status != ".INVITEE;
1928
            }
1929
1930
            $rs = Database::query($sql_query);
1931
            while ($student = Database::fetch_array($rs)) {
1932
                $students[$student['user_id']] = $student;
1933
            }
1934
        }
1935
1936
        return $students;
1937
    }
1938
1939
    /**
1940
     * Return user info array of all teacher-users registered in a course
1941
     * This only returns the users that are registered in this actual course, not linked courses.
1942
     *
1943
     * @param string $course_code
1944
     *
1945
     * @return array with user id
1946
     */
1947
    public static function get_teacher_list_from_course_code($course_code)
1948
    {
1949
        $courseInfo = api_get_course_info($course_code);
1950
        $courseId = $courseInfo['real_id'];
1951
        if (empty($courseId)) {
1952
            return false;
1953
        }
1954
1955
        $sql = "SELECT DISTINCT
1956
                    u.id as user_id,
1957
                    u.lastname,
1958
                    u.firstname,
1959
                    u.email,
1960
                    u.username,
1961
                    u.status
1962
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1963
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
1964
                ON (cu.user_id = u.id)
1965
                WHERE
1966
                    cu.c_id = $courseId AND
1967
                    cu.status = 1 ";
1968
        $rs = Database::query($sql);
1969
        $teachers = [];
1970
        while ($teacher = Database::fetch_array($rs)) {
1971
            $teachers[$teacher['user_id']] = $teacher;
1972
        }
1973
1974
        return $teachers;
1975
    }
1976
1977
    /**
1978
     * Return user info array of all teacher-users registered in a course
1979
     * This only returns the users that are registered in this actual course, not linked courses.
1980
     *
1981
     * @param int  $courseId
1982
     * @param bool $loadAvatars
1983
     *
1984
     * @return array with user id
1985
     */
1986
    public static function getTeachersFromCourse($courseId, $loadAvatars = true)
1987
    {
1988
        $courseId = (int) $courseId;
1989
1990
        if (empty($courseId)) {
1991
            return false;
1992
        }
1993
1994
        $sql = "SELECT DISTINCT
1995
                    u.id as user_id,
1996
                    u.lastname,
1997
                    u.firstname,
1998
                    u.email,
1999
                    u.username,
2000
                    u.status
2001
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2002
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2003
                ON (cu.user_id = u.id)
2004
                WHERE
2005
                    cu.c_id = $courseId AND
2006
                    cu.status = 1 ";
2007
        $rs = Database::query($sql);
2008
        $listTeachers = [];
2009
        $teachers = [];
2010
        $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&course_id='.$courseId;
2011
        while ($teacher = Database::fetch_array($rs)) {
2012
            $teachers['id'] = $teacher['user_id'];
2013
            $teachers['lastname'] = $teacher['lastname'];
2014
            $teachers['firstname'] = $teacher['firstname'];
2015
            $teachers['email'] = $teacher['email'];
2016
            $teachers['username'] = $teacher['username'];
2017
            $teachers['status'] = $teacher['status'];
2018
            $teachers['fullname'] = api_get_person_name($teacher['firstname'], $teacher['lastname']);
2019
            $teachers['avatar'] = '';
2020
            if ($loadAvatars) {
2021
                $userPicture = UserManager::getUserPicture($teacher['user_id'], USER_IMAGE_SIZE_SMALL);
2022
                $teachers['avatar'] = $userPicture;
2023
            }
2024
            $teachers['url'] = $url.'&user_id='.$teacher['user_id'];
2025
            $listTeachers[] = $teachers;
2026
        }
2027
2028
        return $listTeachers;
2029
    }
2030
2031
    /**
2032
     * Returns a string list of teachers assigned to the given course.
2033
     *
2034
     * @param string $course_code
2035
     * @param string $separator           between teachers names
2036
     * @param bool   $add_link_to_profile Whether to add a link to the teacher's profile
2037
     * @param bool   $orderList
2038
     *
2039
     * @return string List of teachers teaching the course
2040
     */
2041
    public static function getTeacherListFromCourseCodeToString(
2042
        $course_code,
2043
        $separator = self::USER_SEPARATOR,
2044
        $add_link_to_profile = false,
2045
        $orderList = false
2046
    ) {
2047
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
2048
        $html = '';
2049
        $list = [];
2050
        if (!empty($teacher_list)) {
2051
            foreach ($teacher_list as $teacher) {
2052
                $teacher_name = api_get_person_name(
2053
                    $teacher['firstname'],
2054
                    $teacher['lastname']
2055
                );
2056
                if ($add_link_to_profile) {
2057
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$teacher['user_id'];
2058
                    $teacher_name = Display::url(
2059
                        $teacher_name,
2060
                        $url,
2061
                        [
2062
                            'class' => 'ajax',
2063
                            'data-title' => $teacher_name,
2064
                        ]
2065
                    );
2066
                }
2067
                $list[] = $teacher_name;
2068
            }
2069
2070
            if (!empty($list)) {
2071
                if ($orderList === true) {
2072
                    $html .= '<ul class="user-teacher">';
2073
                    foreach ($list as $teacher) {
2074
                        $html .= '<li>';
2075
                        $html .= Display::return_icon('teacher.png', '', null, ICON_SIZE_TINY);
2076
                        $html .= ' '.$teacher;
2077
                        $html .= '</li>';
2078
                    }
2079
                    $html .= '</ul>';
2080
                } else {
2081
                    $html .= array_to_string($list, $separator);
2082
                }
2083
            }
2084
        }
2085
2086
        return $html;
2087
    }
2088
2089
    /**
2090
     * This function returns information about coachs from a course in session.
2091
     *
2092
     * @param int $session_id
2093
     * @param int $courseId
2094
     *
2095
     * @return array containing user_id, lastname, firstname, username
2096
     */
2097
    public static function get_coachs_from_course($session_id = 0, $courseId = 0)
2098
    {
2099
        if (!empty($session_id)) {
2100
            $session_id = intval($session_id);
2101
        } else {
2102
            $session_id = api_get_session_id();
2103
        }
2104
2105
        if (!empty($courseId)) {
2106
            $courseId = intval($courseId);
2107
        } else {
2108
            $courseId = api_get_course_int_id();
2109
        }
2110
2111
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2112
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2113
2114
        $sql = "SELECT DISTINCT 
2115
                    u.user_id,
2116
                    u.lastname,
2117
                    u.firstname,
2118
                    u.username
2119
                FROM $tbl_user u 
2120
                INNER JOIN $tbl_session_course_user scu
2121
                ON (u.user_id = scu.user_id)
2122
                WHERE
2123
                    scu.session_id = $session_id AND
2124
                    scu.c_id = $courseId AND
2125
                    scu.status = 2";
2126
        $rs = Database::query($sql);
2127
2128
        $coaches = [];
2129
        if (Database::num_rows($rs) > 0) {
2130
            while ($row = Database::fetch_array($rs)) {
2131
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
2132
                $coaches[] = $row + ['full_name' => $completeName];
2133
            }
2134
        }
2135
2136
        return $coaches;
2137
    }
2138
2139
    /**
2140
     * @param int    $session_id
2141
     * @param int    $courseId
2142
     * @param string $separator
2143
     * @param bool   $add_link_to_profile
2144
     * @param bool   $orderList
2145
     *
2146
     * @return string
2147
     */
2148
    public static function get_coachs_from_course_to_string(
2149
        $session_id = 0,
2150
        $courseId = 0,
2151
        $separator = self::USER_SEPARATOR,
2152
        $add_link_to_profile = false,
2153
        $orderList = false
2154
    ) {
2155
        $coachList = self::get_coachs_from_course($session_id, $courseId);
2156
        $course_coachs = [];
2157
        if (!empty($coachList)) {
2158
            foreach ($coachList as $coach_course) {
2159
                $coach_name = $coach_course['full_name'];
2160
                if ($add_link_to_profile) {
2161
                    $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;
2162
                    $coach_name = Display::url(
2163
                        $coach_name,
2164
                        $url,
2165
                        [
2166
                            'class' => 'ajax',
2167
                            'data-title' => $coach_name,
2168
                        ]
2169
                    );
2170
                }
2171
                $course_coachs[] = $coach_name;
2172
            }
2173
        }
2174
2175
        $html = '';
2176
        if (!empty($course_coachs)) {
2177
            if ($orderList === true) {
2178
                $html .= '<ul class="user-coachs">';
2179
                foreach ($course_coachs as $coachs) {
2180
                    $html .= Display::tag(
2181
                        'li',
2182
                        Display::return_icon(
2183
                            'teacher.png',
2184
                            get_lang('Coach'),
2185
                            null,
2186
                            ICON_SIZE_TINY
2187
                        ).' '.$coachs
2188
                    );
2189
                }
2190
                $html .= '</ul>';
2191
            } else {
2192
                $html = array_to_string($course_coachs, $separator);
2193
            }
2194
        }
2195
2196
        return $html;
2197
    }
2198
2199
    /**
2200
     * Get the list of groups from the course.
2201
     *
2202
     * @param string $course_code
2203
     * @param int    $session_id         Session ID (optional)
2204
     * @param int    $in_get_empty_group get empty groups (optional)
2205
     *
2206
     * @return array List of groups info
2207
     */
2208
    public static function get_group_list_of_course(
2209
        $course_code,
2210
        $session_id = 0,
2211
        $in_get_empty_group = 0
2212
    ) {
2213
        $course_info = api_get_course_info($course_code);
2214
2215
        if (empty($course_info)) {
2216
            return [];
2217
        }
2218
        $course_id = $course_info['real_id'];
2219
2220
        if (empty($course_id)) {
2221
            return [];
2222
        }
2223
2224
        $session_id != 0 ? $session_condition = ' WHERE g.session_id IN(1,'.intval($session_id).')' : $session_condition = ' WHERE g.session_id = 0';
2225
        if ($in_get_empty_group == 0) {
2226
            // get only groups that are not empty
2227
            $sql = "SELECT DISTINCT g.id, g.iid, g.name
2228
                    FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2229
                    INNER JOIN ".Database::get_course_table(TABLE_GROUP_USER)." gu
2230
                    ON (g.id = gu.group_id AND g.c_id = $course_id AND gu.c_id = $course_id)
2231
                    $session_condition
2232
                    ORDER BY g.name";
2233
        } else {
2234
            // get all groups even if they are empty
2235
            $sql = "SELECT g.id, g.name, g.iid 
2236
                    FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2237
                    $session_condition
2238
                    AND c_id = $course_id";
2239
        }
2240
2241
        $result = Database::query($sql);
2242
        $groupList = [];
2243
        while ($groupData = Database::fetch_array($result)) {
2244
            $groupData['userNb'] = GroupManager::number_of_students($groupData['id'], $course_id);
2245
            $groupList[$groupData['iid']] = $groupData;
2246
        }
2247
2248
        return $groupList;
2249
    }
2250
2251
    /**
2252
     * Delete a course
2253
     * This function deletes a whole course-area from the platform. When the
2254
     * given course is a virtual course, the database and directory will not be
2255
     * deleted.
2256
     * When the given course is a real course, also all virtual courses refering
2257
     * to the given course will be deleted.
2258
     * Considering the fact that we remove all traces of the course in the main
2259
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2260
     * so that a new course created with this code would not use the remains of an older
2261
     * course.
2262
     *
2263
     * @param string $code The code of the course to delete
2264
     *
2265
     * @todo When deleting a virtual course: unsubscribe users from that virtual
2266
     * course from the groups in the real course if they are not subscribed in
2267
     * that real course.
2268
     */
2269
    public static function delete_course($code)
2270
    {
2271
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2272
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2273
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2274
        $table_course_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
2275
        $table_course_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
2276
        $table_course_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
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'];
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
            // Cleaning group categories
2318
            $groupCategories = GroupManager::get_categories($course['code']);
2319
            if (!empty($groupCategories)) {
2320
                foreach ($groupCategories as $category) {
2321
                    GroupManager::delete_category($category['id'], $course['code']);
2322
                }
2323
            }
2324
2325
            // Cleaning groups
2326
            $groups = GroupManager::get_groups($courseId);
2327
            if (!empty($groups)) {
2328
                foreach ($groups as $group) {
2329
                    GroupManager::deleteGroup($group, $course['code']);
2330
                }
2331
            }
2332
2333
            $course_tables = AddCourse::get_course_tables();
2334
            // Cleaning c_x tables
2335
            if (!empty($courseId)) {
2336
                foreach ($course_tables as $table) {
2337
                    if ($table === 'document') {
2338
                        // Table document will be deleted by Doctrine.
2339
                        continue;
2340
                    }
2341
                    $table = Database::get_course_table($table);
2342
                    $sql = "DELETE FROM $table WHERE c_id = $courseId ";
2343
                    Database::query($sql);
2344
                }
2345
            }
2346
2347
            /*$course_dir = api_get_path(SYS_COURSE_PATH).$course['directory'];
2348
            $archive_dir = api_get_path(SYS_ARCHIVE_PATH).$course['directory'].'_'.time();
2349
            if (is_dir($course_dir)) {
2350
                rename($course_dir, $archive_dir);
2351
            }*/
2352
2353
            Category::deleteFromCourse($courseEntity);
2354
2355
            // Unsubscribe all users from the course
2356
            $sql = "DELETE FROM $table_course_user WHERE c_id = $courseId";
2357
            Database::query($sql);
2358
            // Delete the course from the sessions tables
2359
            $sql = "DELETE FROM $table_session_course WHERE c_id = $courseId";
2360
            Database::query($sql);
2361
            $sql = "DELETE FROM $table_session_course_user WHERE c_id = $courseId";
2362
            Database::query($sql);
2363
2364
            // Delete from Course - URL
2365
            // Already deleted because of entities.
2366
            //$sql = "DELETE FROM $table_course_rel_url WHERE c_id = $courseId";
2367
            //Database::query($sql);
2368
2369
            $sql = "SELECT survey_id FROM $table_course_survey WHERE course_code = '$codeFiltered'";
2370
            $result_surveys = Database::query($sql);
2371
            while ($surveys = Database::fetch_array($result_surveys)) {
2372
                $survey_id = $surveys[0]; //int
2373
                $sql = "DELETE FROM $table_course_survey_question WHERE survey_id = $survey_id";
2374
                Database::query($sql);
2375
                $sql = "DELETE FROM $table_course_survey_question_option WHERE survey_id = $survey_id";
2376
                Database::query($sql);
2377
                $sql = "DELETE FROM $table_course_survey WHERE survey_id = $survey_id";
2378
                Database::query($sql);
2379
            }
2380
2381
            // Delete the course from the stats tables
2382
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2383
            Database::query($sql);
2384
            $sql = "DELETE FROM $table_stats_attempt WHERE c_id = $courseId";
2385
            Database::query($sql);
2386
            $sql = "DELETE FROM $table_stats_exercises WHERE c_id = $courseId";
2387
            Database::query($sql);
2388
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2389
            Database::query($sql);
2390
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2391
            Database::query($sql);
2392
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2393
            Database::query($sql);
2394
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2395
            Database::query($sql);
2396
            // Do not delete rows from track_e_default as these include course
2397
            // creation and other important things that do not take much space
2398
            // but give information on the course history
2399
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2400
            //Database::query($sql);
2401
            $sql = "DELETE FROM $table_stats_downloads WHERE c_id = $courseId";
2402
            Database::query($sql);
2403
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2404
            Database::query($sql);
2405
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2406
            Database::query($sql);
2407
2408
            // Update ticket
2409
            $table = Database::get_main_table(TABLE_TICKET_TICKET);
2410
            $sql = "UPDATE $table SET course_id = NULL WHERE course_id = $courseId";
2411
            Database::query($sql);
2412
2413
            // Class
2414
            $table = Database::get_main_table(TABLE_USERGROUP_REL_COURSE);
2415
            $sql = "DELETE FROM $table
2416
                    WHERE course_id = $courseId";
2417
            Database::query($sql);
2418
2419
            // Skills
2420
            $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
2421
            $argumentation = Database::escape_string(sprintf(get_lang('This skill was obtained through course %s which has been removed since then.'), $course['code']));
2422
            $sql = "UPDATE $table SET course_id = NULL, session_id = NULL, argumentation = '$argumentation' 
2423
                    WHERE course_id = $courseId";
2424
            Database::query($sql);
2425
2426
            $sql = "DELETE FROM skill_rel_course WHERE c_id = $courseId";
2427
            Database::query($sql);
2428
2429
            // Deletes all groups, group-users, group-tutors information
2430
            // To prevent fK mix up on some tables
2431
            GroupManager::deleteAllGroupsFromCourse($courseId);
2432
2433
            $appPlugin = new AppPlugin();
2434
            $appPlugin->performActionsWhenDeletingItem('course', $courseId);
2435
2436
            // Delete the course from the database
2437
            $repo = Container::getCourseRepository();
2438
            $repo->deleteCourse($courseEntity);
2439
2440
            // delete extra course fields
2441
            $extraFieldValues = new ExtraFieldValue('course');
2442
            $extraFieldValues->deleteValuesByItem($courseId);
2443
2444
            // Add event to system log
2445
            Event::addEvent(
2446
                LOG_COURSE_DELETE,
2447
                LOG_COURSE_CODE,
2448
                $code,
2449
                api_get_utc_datetime(),
2450
                api_get_user_id(),
2451
                $courseId
2452
            );
2453
        }
2454
    }
2455
2456
    /**
2457
     * Creates a file called mysql_dump.sql in the course folder.
2458
     *
2459
     * @param string $course_code The code of the course
2460
     *
2461
     * @todo Implementation for single database
2462
     */
2463
    public static function create_database_dump($course_code)
2464
    {
2465
        $sql_dump = '';
2466
        $course_code = Database::escape_string($course_code);
2467
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
2468
        $sql = "SELECT * FROM $table_course WHERE code = '$course_code'";
2469
        $res = Database::query($sql);
2470
        $course = Database::fetch_array($res);
2471
2472
        $course_tables = AddCourse::get_course_tables();
2473
2474
        if (!empty($course['id'])) {
2475
            //Cleaning c_x tables
2476
            foreach ($course_tables as $table) {
2477
                $table = Database::get_course_table($table);
2478
                $sql = "SELECT * FROM $table WHERE c_id = {$course['id']} ";
2479
                $res_table = Database::query($sql);
2480
2481
                while ($row = Database::fetch_array($res_table, 'ASSOC')) {
2482
                    $row_to_save = [];
2483
                    foreach ($row as $key => $value) {
2484
                        $row_to_save[$key] = $key."='".Database::escape_string($row[$key])."'";
2485
                    }
2486
                    $sql_dump .= "\nINSERT INTO $table SET ".implode(', ', $row_to_save).';';
2487
                }
2488
            }
2489
        }
2490
2491
        if (is_dir(api_get_path(SYS_COURSE_PATH).$course['directory'])) {
2492
            $file_name = api_get_path(SYS_COURSE_PATH).$course['directory'].'/mysql_dump.sql';
2493
            $handle = fopen($file_name, 'a+');
2494
            if ($handle !== false) {
2495
                fwrite($handle, $sql_dump);
2496
                fclose($handle);
2497
            } else {
2498
                //TODO trigger exception in a try-catch
2499
            }
2500
        }
2501
    }
2502
2503
    /**
2504
     * Sort courses for a specific user ??
2505
     *
2506
     * @param int    $user_id     User ID
2507
     * @param string $course_code Course code
2508
     *
2509
     * @return int Minimum course order
2510
     *
2511
     * @todo Review documentation
2512
     */
2513
    public static function userCourseSort($user_id, $course_code)
2514
    {
2515
        if ($user_id != strval(intval($user_id))) {
2516
            return false;
2517
        }
2518
2519
        $course_code = Database::escape_string($course_code);
2520
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2521
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2522
2523
        $course_title = Database::result(
2524
            Database::query(
2525
                "SELECT title FROM $TABLECOURSE WHERE code = '$course_code'"
2526
            ),
2527
            0,
2528
            0
2529
        );
2530
        if ($course_title === false) {
2531
            $course_title = '';
2532
        }
2533
2534
        $sql = "SELECT course.code as code, course.title as title, cu.sort as sort
2535
                FROM $TABLECOURSUSER as cu, $TABLECOURSE as course
2536
                WHERE   course.id = cu.c_id AND user_id = $user_id AND
2537
                        cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2538
                        user_course_cat = 0
2539
                ORDER BY cu.sort";
2540
        $result = Database::query($sql);
2541
2542
        $course_title_precedent = '';
2543
        $counter = 0;
2544
        $course_found = false;
2545
        $course_sort = 1;
2546
2547
        if (Database::num_rows($result) > 0) {
2548
            while ($courses = Database::fetch_array($result)) {
2549
                if ($course_title_precedent == '') {
2550
                    $course_title_precedent = $courses['title'];
2551
                }
2552
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2553
                    $course_found = true;
2554
                    $course_sort = $courses['sort'];
2555
                    if ($counter == 0) {
2556
                        $sql = "UPDATE $TABLECOURSUSER
2557
                                SET sort = sort+1
2558
                                WHERE
2559
                                    user_id= $user_id AND
2560
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2561
                                    AND user_course_cat = 0
2562
                                    AND sort > $course_sort";
2563
                        $course_sort++;
2564
                    } else {
2565
                        $sql = "UPDATE $TABLECOURSUSER SET sort = sort+1
2566
                                WHERE
2567
                                    user_id= $user_id AND
2568
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2569
                                    user_course_cat = 0 AND
2570
                                    sort >= $course_sort";
2571
                    }
2572
                    Database::query($sql);
2573
                    break;
2574
                } else {
2575
                    $course_title_precedent = $courses['title'];
2576
                }
2577
                $counter++;
2578
            }
2579
2580
            // We must register the course in the beginning of the list
2581
            if (!$course_found) {
2582
                $course_sort = Database::result(
2583
                    Database::query(
2584
                        'SELECT min(sort) as min_sort FROM '.$TABLECOURSUSER.' WHERE user_id = "'.$user_id.'" AND user_course_cat="0"'
2585
                    ),
2586
                    0,
2587
                    0
2588
                );
2589
                Database::query("UPDATE $TABLECOURSUSER SET sort = sort+1 WHERE user_id = $user_id AND user_course_cat = 0");
2590
            }
2591
        }
2592
2593
        return $course_sort;
2594
    }
2595
2596
    /**
2597
     * check if course exists.
2598
     *
2599
     * @param string $courseCode
2600
     *
2601
     * @return int if exists, false else
2602
     */
2603
    public static function course_exists($courseCode)
2604
    {
2605
        $courseCode = Database::escape_string($courseCode);
2606
        $sql = "SELECT 1 FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2607
                WHERE code = '$courseCode'";
2608
2609
        return Database::num_rows(Database::query($sql));
2610
    }
2611
2612
    /**
2613
     * Send an email to tutor after the auth-suscription of a student in your course.
2614
     *
2615
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2616
     *
2617
     * @param int    $user_id            the id of the user
2618
     * @param string $courseId           the course code
2619
     * @param bool   $send_to_tutor_also
2620
     *
2621
     * @return false|null we return the message that is displayed when the action is successful
2622
     */
2623
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2624
    {
2625
        $user_id = (int) $user_id;
2626
        $courseId = (int) $courseId;
2627
        $information = api_get_course_info_by_id($courseId);
2628
        $course_code = $information['code'];
2629
        $student = api_get_user_info($user_id);
2630
2631
        $name_course = $information['title'];
2632
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." 
2633
                WHERE c_id = $courseId";
2634
2635
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2636
        //if ($send_to_tutor_also = true)
2637
        // Proposed change:
2638
        if ($send_to_tutor_also) {
2639
            $sql .= ' AND is_tutor = 1';
2640
        } else {
2641
            $sql .= ' AND status = 1';
2642
        }
2643
2644
        $result = Database::query($sql);
2645
        while ($row = Database::fetch_array($result)) {
2646
            $tutor = api_get_user_info($row['user_id']);
2647
            $emailto = $tutor['email'];
2648
            $emailsubject = get_lang('New user in the course').': '.$name_course;
2649
            $emailbody = get_lang('Dear').': '.api_get_person_name($tutor['firstname'], $tutor['lastname'])."\n";
2650
            $emailbody .= get_lang('MessageNew user in the course').': '.$name_course."\n";
2651
            $emailbody .= get_lang('Username').': '.$student['username']."\n";
2652
            if (api_is_western_name_order()) {
2653
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2654
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2655
            } else {
2656
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2657
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2658
            }
2659
            $emailbody .= get_lang('e-mail').': <a href="mailto:'.$student['email'].'">'.$student['email']."</a>\n\n";
2660
            $recipient_name = api_get_person_name(
2661
                $tutor['firstname'],
2662
                $tutor['lastname'],
2663
                null,
2664
                PERSON_NAME_EMAIL_ADDRESS
2665
            );
2666
            $sender_name = api_get_person_name(
2667
                api_get_setting('administratorName'),
2668
                api_get_setting('administratorSurname'),
2669
                null,
2670
                PERSON_NAME_EMAIL_ADDRESS
2671
            );
2672
            $email_admin = api_get_setting('emailAdministrator');
2673
2674
            $additionalParameters = [
2675
                'smsType' => SmsPlugin::NEW_USER_SUBSCRIBED_COURSE,
2676
                'userId' => $tutor['user_id'],
2677
                'userUsername' => $student['username'],
2678
                'courseCode' => $course_code,
2679
            ];
2680
            api_mail_html(
2681
                $recipient_name,
2682
                $emailto,
2683
                $emailsubject,
2684
                $emailbody,
2685
                $sender_name,
2686
                $email_admin,
2687
                null,
2688
                null,
2689
                null,
2690
                $additionalParameters
2691
            );
2692
        }
2693
    }
2694
2695
    /**
2696
     * @return array
2697
     */
2698
    public static function get_special_course_list()
2699
    {
2700
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2701
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
2702
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2703
2704
        //we filter the courses from the URL
2705
        $join_access_url = $where_access_url = '';
2706
        if (api_get_multiple_access_url()) {
2707
            $access_url_id = api_get_current_access_url_id();
2708
            if ($access_url_id != -1) {
2709
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2710
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
2711
                                    ON url_rel_course.c_id = tcfv.item_id ";
2712
                $where_access_url = " AND access_url_id = $access_url_id ";
2713
            }
2714
        }
2715
2716
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2717
2718
        // get course list auto-register
2719
        $sql = "SELECT DISTINCT(c.id)
2720
                FROM $tbl_course_field_value tcfv
2721
                INNER JOIN $tbl_course_field tcf
2722
                ON tcfv.field_id =  tcf.id $join_access_url
2723
                INNER JOIN $courseTable c
2724
                ON (c.id = tcfv.item_id)
2725
                WHERE
2726
                    tcf.extra_field_type = $extraFieldType AND
2727
                    tcf.variable = 'special_course' AND
2728
                    tcfv.value = 1 $where_access_url";
2729
2730
        $result = Database::query($sql);
2731
        $courseList = [];
2732
2733
        if (Database::num_rows($result) > 0) {
2734
            while ($row = Database::fetch_array($result)) {
2735
                $courseList[] = $row['id'];
2736
            }
2737
        }
2738
2739
        return $courseList;
2740
    }
2741
2742
    /**
2743
     * Get the course codes that have been restricted in the catalogue, and if byUserId is set
2744
     * then the courses that the user is allowed or not to see in catalogue.
2745
     *
2746
     * @param bool $allowed  Either if the courses have some users that are or are not allowed to see in catalogue
2747
     * @param int  $byUserId if the courses are or are not allowed to see to the user
2748
     *
2749
     * @return array Course codes allowed or not to see in catalogue by some user or the user
2750
     */
2751
    public static function getCatalogueCourseList($allowed = true, $byUserId = -1)
2752
    {
2753
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2754
        $tblCourseRelUserCatalogue = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
2755
        $visibility = $allowed ? 1 : 0;
2756
2757
        // Restriction by user id
2758
        $currentUserRestriction = '';
2759
        if ($byUserId > 0) {
2760
            $byUserId = (int) $byUserId;
2761
            $currentUserRestriction = " AND tcruc.user_id = $byUserId ";
2762
        }
2763
2764
        //we filter the courses from the URL
2765
        $joinAccessUrl = '';
2766
        $whereAccessUrl = '';
2767
        if (api_get_multiple_access_url()) {
2768
            $accessUrlId = api_get_current_access_url_id();
2769
            if ($accessUrlId != -1) {
2770
                $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2771
                $joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
2772
                                  ON url_rel_course.c_id = c.id ";
2773
                $whereAccessUrl = " AND access_url_id = $accessUrlId ";
2774
            }
2775
        }
2776
2777
        // get course list auto-register
2778
        $sql = "SELECT DISTINCT(c.code)
2779
                FROM $tblCourseRelUserCatalogue tcruc
2780
                INNER JOIN $courseTable c
2781
                ON (c.id = tcruc.c_id) $joinAccessUrl
2782
                WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
2783
2784
        $result = Database::query($sql);
2785
        $courseList = [];
2786
2787
        if (Database::num_rows($result) > 0) {
2788
            while ($resultRow = Database::fetch_array($result)) {
2789
                $courseList[] = $resultRow['code'];
2790
            }
2791
        }
2792
2793
        return $courseList;
2794
    }
2795
2796
    /**
2797
     * Get list of courses for a given user.
2798
     *
2799
     * @param int   $user_id
2800
     * @param bool  $include_sessions                   Whether to include courses from session or not
2801
     * @param bool  $adminGetsAllCourses                If the user is platform admin,
2802
     *                                                  whether he gets all the courses or just his. Note: This does *not* include all sessions
2803
     * @param bool  $loadSpecialCourses
2804
     * @param array $skipCourseList                     List of course ids to skip
2805
     * @param bool  $useUserLanguageFilterIfAvailable
2806
     * @param bool  $showCoursesSessionWithDifferentKey
2807
     *
2808
     * @return array List of codes and db name
2809
     *
2810
     * @author isaac flores paz
2811
     */
2812
    public static function get_courses_list_by_user_id(
2813
        $user_id,
2814
        $include_sessions = false,
2815
        $adminGetsAllCourses = false,
2816
        $loadSpecialCourses = true,
2817
        $skipCourseList = [],
2818
        $useUserLanguageFilterIfAvailable = true,
2819
        $showCoursesSessionWithDifferentKey = false
2820
    ) {
2821
        $user_id = intval($user_id);
2822
        $urlId = api_get_current_access_url_id();
2823
        $course_list = [];
2824
        $codes = [];
2825
2826
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2827
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2828
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
2829
        $tableCourseUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2830
2831
        $languageCondition = '';
2832
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
2833
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
2834
            $userInfo = api_get_user_info(api_get_user_id());
2835
            if (!empty($userInfo['language'])) {
2836
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
2837
            }
2838
        }
2839
2840
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
2841
            // get the whole courses list
2842
            $sql = "SELECT DISTINCT(course.code), course.id as real_id, course.title
2843
                    FROM $tbl_course course 
2844
                    INNER JOIN $tableCourseUrl url 
2845
                    ON (course.id = url.c_id)
2846
                    WHERE 
2847
                        url.access_url_id = $urlId     
2848
                        $languageCondition 
2849
                ";
2850
        } else {
2851
            $withSpecialCourses = $withoutSpecialCourses = '';
2852
2853
            if ($loadSpecialCourses) {
2854
                $specialCourseList = self::get_special_course_list();
2855
2856
                if (!empty($specialCourseList)) {
2857
                    $specialCourseToString = '"'.implode('","', $specialCourseList).'"';
2858
                    $withSpecialCourses = ' AND course.id IN ('.$specialCourseToString.')';
2859
                    $withoutSpecialCourses = ' AND course.id NOT IN ('.$specialCourseToString.')';
2860
                }
2861
2862
                if (!empty($withSpecialCourses)) {
2863
                    $sql = "SELECT DISTINCT (course.code), 
2864
                            course.id as real_id,
2865
                            course.category_code AS category,
2866
                            course.title
2867
                            FROM $tbl_course_user course_rel_user
2868
                            LEFT JOIN $tbl_course course
2869
                            ON course.id = course_rel_user.c_id
2870
                            LEFT JOIN $tbl_user_course_category user_course_category
2871
                            ON course_rel_user.user_course_cat = user_course_category.id
2872
                            INNER JOIN $tableCourseUrl url 
2873
                            ON (course.id = url.c_id)  
2874
                            WHERE url.access_url_id = $urlId 
2875
                            $withSpecialCourses
2876
                            $languageCondition                        
2877
                            GROUP BY course.code
2878
                            ORDER BY user_course_category.sort, course.title, course_rel_user.sort ASC
2879
                    ";
2880
                    $result = Database::query($sql);
2881
                    if (Database::num_rows($result) > 0) {
2882
                        while ($result_row = Database::fetch_array($result, 'ASSOC')) {
2883
                            $result_row['special_course'] = 1;
2884
                            $course_list[] = $result_row;
2885
                            $codes[] = $result_row['real_id'];
2886
                        }
2887
                    }
2888
                }
2889
            }
2890
2891
            // get course list not auto-register. Use Distinct to avoid multiple
2892
            // entries when a course is assigned to a HRD (DRH) as watcher
2893
            $sql = "SELECT 
2894
                        DISTINCT(course.code), 
2895
                        course.id as real_id, 
2896
                        course.category_code AS category,
2897
                        course.title
2898
                    FROM $tbl_course course
2899
                    INNER JOIN $tbl_course_user cru 
2900
                    ON (course.id = cru.c_id)
2901
                    INNER JOIN $tableCourseUrl url 
2902
                    ON (course.id = url.c_id) 
2903
                    WHERE 
2904
                        url.access_url_id = $urlId AND 
2905
                        cru.user_id = $user_id 
2906
                        $withoutSpecialCourses
2907
                        $languageCondition
2908
                    ORDER BY course.title
2909
                    ";
2910
        }
2911
        $result = Database::query($sql);
2912
2913
        if (Database::num_rows($result)) {
2914
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2915
                if (!empty($skipCourseList)) {
2916
                    if (in_array($row['real_id'], $skipCourseList)) {
2917
                        continue;
2918
                    }
2919
                }
2920
                $course_list[] = $row;
2921
                $codes[] = $row['real_id'];
2922
            }
2923
        }
2924
2925
        if ($include_sessions === true) {
2926
            $sql = "SELECT DISTINCT (c.code), 
2927
                        c.id as real_id, 
2928
                        c.category_code AS category,
2929
                        s.id as session_id,
2930
                        s.name as session_name
2931
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu                     
2932
                    INNER JOIN $tbl_course c
2933
                    ON (scu.c_id = c.id)
2934
                    INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s
2935
                    ON (s.id = scu.session_id)
2936
                    WHERE user_id = $user_id ";
2937
            $r = Database::query($sql);
2938
            while ($row = Database::fetch_array($r, 'ASSOC')) {
2939
                if (!empty($skipCourseList)) {
2940
                    if (in_array($row['real_id'], $skipCourseList)) {
2941
                        continue;
2942
                    }
2943
                }
2944
2945
                if ($showCoursesSessionWithDifferentKey) {
2946
                    $course_list[] = $row;
2947
                } else {
2948
                    if (!in_array($row['real_id'], $codes)) {
2949
                        $course_list[] = $row;
2950
                    }
2951
                }
2952
            }
2953
        }
2954
2955
        return $course_list;
2956
    }
2957
2958
    /**
2959
     * Get course ID from a given course directory name.
2960
     *
2961
     * @param string $path Course directory (without any slash)
2962
     *
2963
     * @return string Course code, or false if not found
2964
     */
2965
    public static function getCourseCodeFromDirectory($path)
2966
    {
2967
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
2968
        $res = Database::query("SELECT code FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2969
                WHERE directory LIKE BINARY '$path'");
2970
        if ($res === false) {
2971
            return false;
2972
        }
2973
        if (Database::num_rows($res) != 1) {
2974
            return false;
2975
        }
2976
        $row = Database::fetch_array($res);
2977
2978
        return $row['code'];
2979
    }
2980
2981
    /**
2982
     * Get course code(s) from visual code.
2983
     *
2984
     * @deprecated
2985
     *
2986
     * @param   string  Visual code
2987
     *
2988
     * @return array List of codes for the given visual code
2989
     */
2990
    public static function get_courses_info_from_visual_code($code)
2991
    {
2992
        $result = [];
2993
        $sql_result = Database::query("SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2994
                WHERE visual_code = '".Database::escape_string($code)."'");
2995
        while ($virtual_course = Database::fetch_array($sql_result)) {
2996
            $result[] = $virtual_course;
2997
        }
2998
2999
        return $result;
3000
    }
3001
3002
    /**
3003
     * Creates a new extra field for a given course.
3004
     *
3005
     * @param string $variable    Field's internal variable name
3006
     * @param int    $fieldType   Field's type
3007
     * @param string $displayText Field's language var name
3008
     * @param string $default     Optional. The default value
3009
     *
3010
     * @return int New extra field ID
3011
     */
3012
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default = '')
3013
    {
3014
        $extraField = new ExtraField('course');
3015
        $params = [
3016
            'variable' => $variable,
3017
            'field_type' => $fieldType,
3018
            'display_text' => $displayText,
3019
            'default_value' => $default,
3020
        ];
3021
3022
        return $extraField->save($params);
3023
    }
3024
3025
    /**
3026
     * Update course attributes. Will only update attributes with a non-empty value.
3027
     * Note that you NEED to check that your attributes are valid before using this function.
3028
     *
3029
     * @param int Course id
3030
     * @param array Associative array with field names as keys and field values as values
3031
     *
3032
     * @return Doctrine\DBAL\Driver\Statement|null True if update was successful, false otherwise
3033
     */
3034
    public static function update_attributes($id, $attributes)
3035
    {
3036
        $id = (int) $id;
3037
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3038
        $sql = "UPDATE $table SET ";
3039
        $i = 0;
3040
        foreach ($attributes as $name => $value) {
3041
            if ($value != '') {
3042
                if ($i > 0) {
3043
                    $sql .= ", ";
3044
                }
3045
                $sql .= " $name = '".Database::escape_string($value)."'";
3046
                $i++;
3047
            }
3048
        }
3049
        $sql .= " WHERE id = $id";
3050
3051
        return Database::query($sql);
3052
    }
3053
3054
    /**
3055
     * Update an extra field value for a given course.
3056
     *
3057
     * @param string $course_code Course code
3058
     * @param string $variable    Field variable name
3059
     * @param string $value       Optional. Default field value
3060
     *
3061
     * @return bool|int An integer when register a new extra field. And boolean when update the extrafield
3062
     */
3063
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
3064
    {
3065
        $courseInfo = api_get_course_info($course_code);
3066
        $courseId = $courseInfo['real_id'];
3067
3068
        $extraFieldValues = new ExtraFieldValue('course');
3069
        $params = [
3070
            'item_id' => $courseId,
3071
            'variable' => $variable,
3072
            'value' => $value,
3073
        ];
3074
3075
        return $extraFieldValues->save($params);
3076
    }
3077
3078
    /**
3079
     * @param int $sessionId
3080
     *
3081
     * @return mixed
3082
     */
3083
    public static function get_session_category_id_by_session_id($sessionId)
3084
    {
3085
        if (empty($sessionId)) {
3086
            return [];
3087
        }
3088
        $sessionId = intval($sessionId);
3089
        $sql = 'SELECT sc.id session_category
3090
                FROM '.Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY).' sc
3091
                INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION).' s
3092
                ON sc.id = s.session_category_id 
3093
                WHERE s.id = '.$sessionId;
3094
3095
        return Database::result(
3096
            Database::query($sql),
3097
            0,
3098
            'session_category'
3099
        );
3100
    }
3101
3102
    /**
3103
     * Gets the value of a course extra field. Returns null if it was not found.
3104
     *
3105
     * @param string $variable Name of the extra field
3106
     * @param string $code     Course code
3107
     *
3108
     * @return string Value
3109
     */
3110
    public static function get_course_extra_field_value($variable, $code)
3111
    {
3112
        $courseInfo = api_get_course_info($code);
3113
        $courseId = $courseInfo['real_id'];
3114
3115
        $extraFieldValues = new ExtraFieldValue('course');
3116
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($courseId, $variable);
3117
        if (!empty($result['value'])) {
3118
            return $result['value'];
3119
        }
3120
3121
        return null;
3122
    }
3123
3124
    /**
3125
     * Lists details of the course description.
3126
     *
3127
     * @param array        The course description
3128
     * @param string    The encoding
3129
     * @param bool        If true is displayed if false is hidden
3130
     *
3131
     * @return string The course description in html
3132
     */
3133
    public static function get_details_course_description_html(
3134
        $descriptions,
3135
        $charset,
3136
        $action_show = true
3137
    ) {
3138
        $data = null;
3139
        if (isset($descriptions) && count($descriptions) > 0) {
3140
            foreach ($descriptions as $description) {
3141
                $data .= '<div class="sectiontitle">';
3142
                if (api_is_allowed_to_edit() && $action_show) {
3143
                    //delete
3144
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=delete&description_id='.$description->id.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(
3145
                        get_lang('Please confirm your choice'),
3146
                                ENT_QUOTES,
3147
                        $charset
3148
                    )).'\')) return false;">';
3149
                    $data .= Display::return_icon(
3150
                        'delete.gif',
3151
                        get_lang('Delete'),
3152
                        ['style' => 'vertical-align:middle;float:right;']
3153
                    );
3154
                    $data .= '</a> ';
3155
                    //edit
3156
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&description_id='.$description->id.'">';
3157
                    $data .= Display::return_icon(
3158
                        'edit.png',
3159
                        get_lang('Edit'),
3160
                        ['style' => 'vertical-align:middle;float:right; padding-right:4px;'],
3161
                        ICON_SIZE_SMALL
3162
                    );
3163
                    $data .= '</a> ';
3164
                }
3165
                $data .= $description->title;
3166
                $data .= '</div>';
3167
                $data .= '<div class="sectioncomment">';
3168
                $data .= Security::remove_XSS($description->content);
3169
                $data .= '</div>';
3170
            }
3171
        } else {
3172
            $data .= '<em>'.get_lang('There is no course description so far.').'</em>';
3173
        }
3174
3175
        return $data;
3176
    }
3177
3178
    /**
3179
     * Returns the details of a course category.
3180
     *
3181
     * @param string $code Category code
3182
     *
3183
     * @return array Course category
3184
     */
3185
    public static function get_course_category($code)
3186
    {
3187
        $table = Database::get_main_table(TABLE_MAIN_CATEGORY);
3188
        $code = Database::escape_string($code);
3189
        $sql = "SELECT * FROM $table WHERE code = '$code'";
3190
3191
        return Database::fetch_array(Database::query($sql));
3192
    }
3193
3194
    /**
3195
     * Subscribes courses to human resource manager (Dashboard feature).
3196
     *
3197
     * @param int   $hr_manager_id Human Resource Manager id
3198
     * @param array $courses_list  Courses code
3199
     *
3200
     * @return int
3201
     */
3202
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
3203
    {
3204
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3205
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3206
3207
        $hr_manager_id = intval($hr_manager_id);
3208
        $affected_rows = 0;
3209
3210
        //Deleting assigned courses to hrm_id
3211
        if (api_is_multiple_url_enabled()) {
3212
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
3213
                    INNER JOIN $tbl_course_rel_access_url a
3214
                    ON (a.c_id = s.c_id)
3215
                    WHERE
3216
                        user_id = $hr_manager_id AND
3217
                        relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
3218
                        access_url_id = ".api_get_current_access_url_id();
3219
        } else {
3220
            $sql = "SELECT c_id FROM $tbl_course_rel_user
3221
                    WHERE user_id = $hr_manager_id AND relation_type = ".COURSE_RELATION_TYPE_RRHH;
3222
        }
3223
        $result = Database::query($sql);
3224
        if (Database::num_rows($result) > 0) {
3225
            while ($row = Database::fetch_array($result)) {
3226
                $sql = "DELETE FROM $tbl_course_rel_user
3227
                        WHERE
3228
                            c_id = {$row['c_id']} AND
3229
                            user_id = $hr_manager_id AND
3230
                            relation_type = ".COURSE_RELATION_TYPE_RRHH;
3231
                Database::query($sql);
3232
            }
3233
        }
3234
3235
        // inserting new courses list
3236
        if (is_array($courses_list)) {
3237
            foreach ($courses_list as $course_code) {
3238
                $courseInfo = api_get_course_info($course_code);
3239
                $courseId = $courseInfo['real_id'];
3240
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
3241
                        VALUES($courseId, $hr_manager_id, ".DRH.", ".COURSE_RELATION_TYPE_RRHH.")";
3242
                $result = Database::query($sql);
3243
                if (Database::affected_rows($result)) {
3244
                    $affected_rows++;
3245
                }
3246
            }
3247
        }
3248
3249
        return $affected_rows;
3250
    }
3251
3252
    /**
3253
     * get courses followed by human resources manager.
3254
     *
3255
     * @param int    $user_id
3256
     * @param int    $status
3257
     * @param int    $from
3258
     * @param int    $limit
3259
     * @param string $column
3260
     * @param string $direction
3261
     * @param bool   $getCount
3262
     *
3263
     * @return array courses
3264
     */
3265
    public static function get_courses_followed_by_drh(
3266
        $user_id,
3267
        $status = DRH,
3268
        $from = null,
3269
        $limit = null,
3270
        $column = null,
3271
        $direction = null,
3272
        $getCount = false
3273
    ) {
3274
        return self::getCoursesFollowedByUser(
3275
            $user_id,
3276
            $status,
3277
            $from,
3278
            $limit,
3279
            $column,
3280
            $direction,
3281
            $getCount
3282
        );
3283
    }
3284
3285
    /**
3286
     * get courses followed by user.
3287
     *
3288
     * @param int    $user_id
3289
     * @param int    $status
3290
     * @param int    $from
3291
     * @param int    $limit
3292
     * @param string $column
3293
     * @param string $direction
3294
     * @param bool   $getCount
3295
     * @param string $keyword
3296
     * @param int    $sessionId
3297
     * @param bool   $showAllAssignedCourses
3298
     *
3299
     * @return array courses
3300
     */
3301
    public static function getCoursesFollowedByUser(
3302
        $user_id,
3303
        $status = null,
3304
        $from = null,
3305
        $limit = null,
3306
        $column = null,
3307
        $direction = null,
3308
        $getCount = false,
3309
        $keyword = null,
3310
        $sessionId = 0,
3311
        $showAllAssignedCourses = false
3312
    ) {
3313
        // Database Table Definitions
3314
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3315
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3316
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3317
        $sessionId = (int) $sessionId;
3318
        $user_id = (int) $user_id;
3319
        $select = "SELECT DISTINCT c.*, c.id as real_id ";
3320
3321
        if ($getCount) {
3322
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3323
        }
3324
3325
        $whereConditions = '';
3326
        switch ($status) {
3327
            case COURSEMANAGER:
3328
                $whereConditions .= " AND cru.user_id = $user_id";
3329
                if (!$showAllAssignedCourses) {
3330
                    $whereConditions .= " AND cru.status = ".COURSEMANAGER;
3331
                } else {
3332
                    $whereConditions .= " AND relation_type = ".COURSE_RELATION_TYPE_COURSE_MANAGER;
3333
                }
3334
                break;
3335
            case DRH:
3336
                $whereConditions .= " AND
3337
                    cru.user_id = $user_id AND
3338
                    cru.status = ".DRH." AND
3339
                    relation_type = '".COURSE_RELATION_TYPE_RRHH."'
3340
                ";
3341
                break;
3342
        }
3343
3344
        $keywordCondition = null;
3345
        if (!empty($keyword)) {
3346
            $keyword = Database::escape_string($keyword);
3347
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3348
        }
3349
3350
        $orderBy = null;
3351
        $extraInnerJoin = null;
3352
3353
        if (!empty($sessionId)) {
3354
            if ($status == COURSEMANAGER) {
3355
                // Teacher of course or teacher inside session
3356
                $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = 2) ";
3357
            }
3358
            $courseList = SessionManager::get_course_list_by_session_id($sessionId);
3359
            if (!empty($courseList)) {
3360
                $courseListToString = implode("','", array_keys($courseList));
3361
                $whereConditions .= " AND c.id IN ('".$courseListToString."')";
3362
            }
3363
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3364
            $tableSessionRelCourseRelUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3365
            $orderBy = ' ORDER BY position';
3366
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3367
                                ON (c.id = src.c_id AND src.session_id = $sessionId)
3368
                                INNER JOIN $tableSessionRelCourseRelUser srcru 
3369
                                ON (src.session_id = srcru.session_id AND srcru.c_id = src.c_id)
3370
                            ";
3371
        }
3372
3373
        $whereConditions .= $keywordCondition;
3374
        $sql = "$select
3375
                FROM $tbl_course c
3376
                INNER JOIN $tbl_course_rel_user cru 
3377
                ON (cru.c_id = c.id)
3378
                INNER JOIN $tbl_course_rel_access_url a 
3379
                ON (a.c_id = c.id)
3380
                $extraInnerJoin
3381
                WHERE
3382
                    access_url_id = ".api_get_current_access_url_id()."
3383
                    $whereConditions
3384
                $orderBy
3385
                ";
3386
        if (isset($from) && isset($limit)) {
3387
            $from = intval($from);
3388
            $limit = intval($limit);
3389
            $sql .= " LIMIT $from, $limit";
3390
        }
3391
3392
        $result = Database::query($sql);
3393
3394
        if ($getCount) {
3395
            $row = Database::fetch_array($result);
3396
3397
            return $row['count'];
3398
        }
3399
3400
        $courses = [];
3401
        if (Database::num_rows($result) > 0) {
3402
            while ($row = Database::fetch_array($result)) {
3403
                $courses[$row['code']] = $row;
3404
            }
3405
        }
3406
3407
        return $courses;
3408
    }
3409
3410
    /**
3411
     * check if a course is special (autoregister).
3412
     *
3413
     * @param int $courseId
3414
     *
3415
     * @return bool
3416
     */
3417
    public static function isSpecialCourse($courseId)
3418
    {
3419
        $extraFieldValue = new ExtraFieldValue('course');
3420
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3421
            $courseId,
3422
            'special_course'
3423
        );
3424
3425
        if (!empty($result)) {
3426
            if ($result['value'] == 1) {
3427
                return true;
3428
            }
3429
        }
3430
3431
        return false;
3432
    }
3433
3434
    /**
3435
     * Update course picture.
3436
     *
3437
     * @param array $courseInfo
3438
     * @param   string  File name
3439
     * @param   string  the full system name of the image
3440
     * from which course picture will be created
3441
     * @param string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
3442
     *
3443
     * @return bool Returns the resulting. In case of internal error or negative validation returns FALSE.
3444
     */
3445
    public static function update_course_picture(
3446
        $courseInfo,
3447
        $filename,
3448
        $source_file = null,
3449
        $cropParameters = null
3450
    ) {
3451
        return false;
3452
        if (empty($courseInfo)) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
3453
            return false;
3454
        }
3455
3456
        // course path
3457
        $store_path = api_get_path(SYS_COURSE_PATH).$courseInfo['path'];
3458
        // image name for courses
3459
        $course_image = $store_path.'/course-pic.png';
3460
        $course_medium_image = $store_path.'/course-pic85x85.png';
3461
3462
        if (file_exists($course_image)) {
3463
            unlink($course_image);
3464
        }
3465
        if (file_exists($course_medium_image)) {
3466
            unlink($course_medium_image);
3467
        }
3468
3469
        //Crop the image to adjust 4:3 ratio
3470
        $image = new Image($source_file);
3471
        $image->crop($cropParameters);
3472
3473
        //Resize the images in two formats
3474
        $medium = new Image($source_file);
3475
        $medium->resize(85);
3476
        $medium->send_image($course_medium_image, -1, 'png');
3477
        $normal = new Image($source_file);
3478
        $normal->resize(400);
3479
        $normal->send_image($course_image, -1, 'png');
3480
3481
        $result = $medium && $normal;
3482
3483
        return $result ? $result : false;
3484
    }
3485
3486
    /**
3487
     * Deletes the course picture.
3488
     *
3489
     * @deprecated resource will be used.
3490
     *
3491
     * @param string $courseCode
3492
     */
3493
    public static function deleteCoursePicture($courseCode)
3494
    {
3495
        return false;
3496
        $course_info = api_get_course_info($courseCode);
0 ignored issues
show
Unused Code introduced by
$course_info = api_get_course_info($courseCode) is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
3497
        // course path
3498
        $storePath = api_get_path(SYS_COURSE_PATH).$course_info['path'];
3499
        // image name for courses
3500
        $courseImage = $storePath.'/course-pic.png';
3501
        $courseMediumImage = $storePath.'/course-pic85x85.png';
3502
        $courseSmallImage = $storePath.'/course-pic32.png';
3503
3504
        if (file_exists($courseImage)) {
3505
            unlink($courseImage);
3506
        }
3507
        if (file_exists($courseMediumImage)) {
3508
            unlink($courseMediumImage);
3509
        }
3510
        if (file_exists($courseSmallImage)) {
3511
            unlink($courseSmallImage);
3512
        }
3513
    }
3514
3515
    /**
3516
     * Display special courses (and only these) as several HTML divs of class userportal-course-item.
3517
     *
3518
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3519
     * in the sense that any user clicking them is registered as a student
3520
     *
3521
     * @param int  $user_id                          User id
3522
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3523
     * @param bool $useUserLanguageFilterIfAvailable
3524
     *
3525
     * @return array
3526
     */
3527
    public static function returnSpecialCourses(
3528
        $user_id,
3529
        $load_dirs = false,
3530
        $useUserLanguageFilterIfAvailable = true
3531
    ) {
3532
        $user_id = (int) $user_id;
3533
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3534
        $specialCourseList = self::get_special_course_list();
3535
3536
        if (empty($specialCourseList)) {
3537
            return [];
3538
        }
3539
3540
        // Filter by language
3541
        $languageCondition = '';
3542
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3543
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3544
            $userInfo = api_get_user_info(api_get_user_id());
3545
            if (!empty($userInfo['language'])) {
3546
                $languageCondition = " AND course_language = '".$userInfo['language']."' ";
3547
            }
3548
        }
3549
3550
        $sql = "SELECT
3551
                    id,
3552
                    code,
3553
                    subscribe subscr,
3554
                    unsubscribe unsubscr
3555
                FROM $table                      
3556
                WHERE 
3557
                    id IN ('".implode("','", $specialCourseList)."')
3558
                    $languageCondition
3559
                GROUP BY code";
3560
3561
        $rs_special_course = Database::query($sql);
3562
        $number_of_courses = Database::num_rows($rs_special_course);
3563
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3564
3565
        $courseList = [];
3566
        if ($number_of_courses > 0) {
3567
            while ($course = Database::fetch_array($rs_special_course)) {
3568
                $course_info = api_get_course_info($course['code']);
3569
                $courseId = $course_info['real_id'];
3570
                if ($course_info['visibility'] == COURSE_VISIBILITY_HIDDEN) {
3571
                    continue;
3572
                }
3573
3574
                $params = [];
3575
                //Param (course_code) needed to get the student info in page "My courses"
3576
                $params['course_code'] = $course['code'];
3577
                $params['code'] = $course['code'];
3578
                // Get notifications.
3579
                $course_info['id_session'] = null;
3580
                $courseUserInfo = self::getUserCourseInfo($user_id, $courseId);
3581
3582
                if (empty($courseUserInfo)) {
3583
                    $course_info['status'] = STUDENT;
3584
                } else {
3585
                    $course_info['status'] = $courseUserInfo['status'];
3586
                }
3587
                $show_notification = !api_get_configuration_value('hide_course_notification')
3588
                    ? Display::show_notification($course_info)
3589
                    : '';
3590
                $params['edit_actions'] = '';
3591
                $params['document'] = '';
3592
                if (api_is_platform_admin()) {
3593
                    $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'];
3594
                    if ($load_dirs) {
3595
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3596
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3597
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3598
                    }
3599
                } else {
3600
                    if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED && $load_dirs) {
3601
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3602
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3603
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3604
                    }
3605
                }
3606
3607
                $params['visibility'] = $course_info['visibility'];
3608
                $params['status'] = $course_info['status'];
3609
                $params['category'] = $course_info['categoryName'];
3610
                $params['category_code'] = $course_info['categoryCode'];
3611
                $params['icon'] = Display::return_icon(
3612
                    'drawing-pin.png',
3613
                    null,
3614
                    null,
3615
                    ICON_SIZE_LARGE,
3616
                    null
3617
                );
3618
3619
                if (api_get_setting('display_coursecode_in_courselist') == 'true') {
3620
                    $params['code_course'] = '('.$course_info['visual_code'].')';
3621
                }
3622
3623
                $params['title'] = $course_info['title'];
3624
                $params['title_cut'] = $course_info['title'];
3625
                $params['link'] = $course_info['course_public_url'].'?id_session=0&autoreg=1';
3626
                if (api_get_setting('display_teacher_in_courselist') === 'true') {
3627
                    $params['teachers'] = self::getTeachersFromCourse(
3628
                        $courseId,
3629
                        true
3630
                    );
3631
                }
3632
3633
                if ($showCustomIcon === 'true') {
3634
                    $params['thumbnails'] = $course_info['course_image'];
3635
                    $params['image'] = $course_info['course_image_large'];
3636
                }
3637
3638
                if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3639
                    $params['notifications'] = $show_notification;
3640
                }
3641
3642
                $params['is_special_course'] = true;
3643
                $courseList[] = $params;
3644
            }
3645
        }
3646
3647
        return $courseList;
3648
    }
3649
3650
    /**
3651
     * Display courses (without special courses) as several HTML divs
3652
     * of course categories, as class userportal-catalog-item.
3653
     *
3654
     * @uses \displayCoursesInCategory() to display the courses themselves
3655
     *
3656
     * @param int  $user_id
3657
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3658
     * @param bool $useUserLanguageFilterIfAvailable
3659
     *
3660
     * @return array
3661
     */
3662
    public static function returnCourses(
3663
        $user_id,
3664
        $load_dirs = false,
3665
        $useUserLanguageFilterIfAvailable = true
3666
    ) {
3667
        $user_id = (int) $user_id;
3668
        if (empty($user_id)) {
3669
            $user_id = api_get_user_id();
3670
        }
3671
        // Step 1: We get all the categories of the user
3672
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3673
        $sql = "SELECT * FROM $table
3674
                WHERE user_id = $user_id
3675
                ORDER BY sort ASC";
3676
3677
        $result = Database::query($sql);
3678
        $listItems = [
3679
            'in_category' => [],
3680
            'not_category' => [],
3681
        ];
3682
        $collapsable = api_get_configuration_value('allow_user_course_category_collapsable');
3683
        $stok = Security::get_token();
3684
        while ($row = Database::fetch_array($result)) {
3685
            // We simply display the title of the category.
3686
            $courseInCategory = self::returnCoursesCategories(
3687
                $row['id'],
3688
                $load_dirs,
3689
                $user_id,
3690
                $useUserLanguageFilterIfAvailable
3691
            );
3692
3693
            $collapsed = 0;
3694
            $collapsableLink = '';
3695
            if ($collapsable) {
3696
                $url = api_get_path(WEB_CODE_PATH).
3697
                    'auth/sort_my_courses.php?categoryid='.$row['id'].'&sec_token='.$stok.'&redirect=home';
3698
                $collapsed = isset($row['collapsed']) && $row['collapsed'] ? 1 : 0;
3699
                if ($collapsed === 0) {
3700
                    $collapsableLink = Display::url(
3701
                        '<i class="fa fa-folder-open"></i>',
3702
                        $url.'&action=set_collapsable&option=1'
3703
                    );
3704
                } else {
3705
                    $collapsableLink = Display::url(
3706
                        '<i class="fa fa-folder"></i>',
3707
                        $url.'&action=set_collapsable&option=0'
3708
                    );
3709
                }
3710
            }
3711
3712
            $params = [
3713
                'id_category' => $row['id'],
3714
                'title_category' => $row['title'],
3715
                'collapsed' => $collapsed,
3716
                'collapsable_link' => $collapsableLink,
3717
                'courses' => $courseInCategory,
3718
            ];
3719
            $listItems['in_category'][] = $params;
3720
        }
3721
3722
        // Step 2: We display the course without a user category.
3723
        $coursesNotCategory = self::returnCoursesCategories(
3724
            0,
3725
            $load_dirs,
3726
            $user_id,
3727
            $useUserLanguageFilterIfAvailable
3728
        );
3729
3730
        if ($coursesNotCategory) {
3731
            $listItems['not_category'] = $coursesNotCategory;
3732
        }
3733
3734
        return $listItems;
3735
    }
3736
3737
    /**
3738
     *  Display courses inside a category (without special courses) as HTML dics of
3739
     *  class userportal-course-item.
3740
     *
3741
     * @param int  $user_category_id                 User category id
3742
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3743
     * @param int  $user_id
3744
     * @param bool $useUserLanguageFilterIfAvailable
3745
     *
3746
     * @return array
3747
     */
3748
    public static function returnCoursesCategories(
3749
        $user_category_id,
3750
        $load_dirs = false,
3751
        $user_id = 0,
3752
        $useUserLanguageFilterIfAvailable = true
3753
    ) {
3754
        $user_id = $user_id ? (int) $user_id : api_get_user_id();
3755
        $user_category_id = (int) $user_category_id;
3756
3757
        // Table definitions
3758
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
3759
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3760
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3761
        $current_url_id = api_get_current_access_url_id();
3762
3763
        // Get course list auto-register
3764
        $special_course_list = self::get_special_course_list();
3765
        $without_special_courses = '';
3766
        if (!empty($special_course_list)) {
3767
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
3768
        }
3769
3770
        $userCategoryCondition = " (course_rel_user.user_course_cat = $user_category_id) ";
3771
        if (empty($user_category_id)) {
3772
            $userCategoryCondition = ' (course_rel_user.user_course_cat = 0 OR course_rel_user.user_course_cat IS NULL) ';
3773
        }
3774
3775
        $languageCondition = '';
3776
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3777
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3778
            $userInfo = api_get_user_info(api_get_user_id());
3779
            if (!empty($userInfo['language'])) {
3780
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
3781
            }
3782
        }
3783
3784
        $sql = "SELECT DISTINCT
3785
                    course.id,
3786
                    course_rel_user.status status,
3787
                    course.code as course_code,
3788
                    user_course_cat,
3789
                    course_rel_user.sort
3790
                FROM $TABLECOURS course 
3791
                INNER JOIN $TABLECOURSUSER course_rel_user
3792
                ON (course.id = course_rel_user.c_id)
3793
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
3794
                ON (url.c_id = course.id)
3795
                WHERE
3796
                    course_rel_user.user_id = $user_id AND
3797
                    $userCategoryCondition
3798
                    $without_special_courses
3799
                    $languageCondition
3800
                ";
3801
        // If multiple URL access mode is enabled, only fetch courses
3802
        // corresponding to the current URL.
3803
        if (api_get_multiple_access_url() && $current_url_id != -1) {
3804
            $sql .= " AND access_url_id = $current_url_id";
3805
        }
3806
        // Use user's classification for courses (if any).
3807
        $sql .= ' ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC';
3808
        $result = Database::query($sql);
3809
3810
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3811
        // Browse through all courses.
3812
        $courseAdded = [];
3813
        $courseList = [];
3814
        while ($row = Database::fetch_array($result)) {
3815
            $course_info = api_get_course_info_by_id($row['id']);
3816
            if (empty($course_info)) {
3817
                continue;
3818
            }
3819
3820
            if (isset($course_info['visibility']) &&
3821
                $course_info['visibility'] == COURSE_VISIBILITY_HIDDEN
3822
            ) {
3823
                continue;
3824
            }
3825
3826
            // Skip if already in list
3827
            if (in_array($course_info['real_id'], $courseAdded)) {
3828
                continue;
3829
            }
3830
            $course_info['id_session'] = null;
3831
            $course_info['status'] = $row['status'];
3832
            // For each course, get if there is any notification icon to show
3833
            // (something that would have changed since the user's last visit).
3834
            $showNotification = !api_get_configuration_value('hide_course_notification')
3835
                ? Display::show_notification($course_info)
3836
                : '';
3837
            $iconName = basename($course_info['course_image']);
3838
3839
            $params = [];
3840
            //Param (course_code) needed to get the student process
3841
            $params['course_code'] = $row['course_code'];
3842
            $params['code'] = $row['course_code'];
3843
3844
            if ($showCustomIcon === 'true' && $iconName != 'course.png') {
3845
                $params['thumbnails'] = $course_info['course_image'];
3846
                $params['image'] = $course_info['course_image_large'];
3847
            }
3848
3849
            $thumbnails = null;
3850
            $image = null;
3851
            if ($showCustomIcon === 'true' && $iconName != 'course.png') {
3852
                $thumbnails = $course_info['course_image'];
3853
                $image = $course_info['course_image_large'];
3854
            } else {
3855
                $image = Display::return_icon(
3856
                    'session_default.png',
3857
                    null,
3858
                    null,
3859
                    null,
3860
                    null,
3861
                    true
3862
                );
3863
            }
3864
3865
            $params['course_id'] = $course_info['real_id'];
3866
            $params['edit_actions'] = '';
3867
            $params['document'] = '';
3868
            if (api_is_platform_admin()) {
3869
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
3870
                if ($load_dirs) {
3871
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
3872
                               .Display::returnFontAwesomeIcon('folder-open').'</a>';
3873
                    $params['document'] .= Display::div(
3874
                        '',
3875
                        [
3876
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
3877
                            'class' => 'document_preview_container',
3878
                        ]
3879
                    );
3880
                }
3881
            }
3882
            if ($load_dirs) {
3883
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
3884
                    .Display::returnFontAwesomeIcon('folder-open').'</a>';
3885
                $params['document'] .= Display::div(
3886
                    '',
3887
                    [
3888
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
3889
                        'class' => 'document_preview_container',
3890
                    ]
3891
                );
3892
            }
3893
3894
            $courseUrl = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php?id_session=0';
3895
            $teachers = [];
3896
            if (api_get_setting('display_teacher_in_courselist') === 'true') {
3897
                $teachers = self::getTeachersFromCourse(
3898
                    $course_info['real_id'],
3899
                    true
3900
                );
3901
            }
3902
3903
            $params['status'] = $row['status'];
3904
            if (api_get_setting('display_coursecode_in_courselist') === 'true') {
3905
                $params['code_course'] = '('.$course_info['visual_code'].') ';
3906
            }
3907
3908
            $params['current_user_is_teacher'] = false;
3909
            /** @var array $teacher */
3910
            foreach ($teachers as $teacher) {
3911
                if ($teacher['id'] != $user_id) {
3912
                    continue;
3913
                }
3914
                $params['current_user_is_teacher'] = true;
3915
            }
3916
3917
            $params['visibility'] = $course_info['visibility'];
3918
            $params['link'] = $courseUrl;
3919
            $params['thumbnails'] = $thumbnails;
3920
            $params['image'] = $image;
3921
            $params['title'] = $course_info['title'];
3922
            $params['title_cut'] = $params['title'];
3923
            $params['category'] = $course_info['categoryName'];
3924
            $params['category_code'] = $course_info['categoryCode'];
3925
            $params['teachers'] = $teachers;
3926
            $params['real_id'] = $course_info['real_id'];
3927
3928
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3929
                $params['notifications'] = $showNotification;
3930
            }
3931
            $courseAdded[] = $course_info['real_id'];
3932
            $courseList[] = $params;
3933
        }
3934
3935
        return $courseList;
3936
    }
3937
3938
    /**
3939
     * Retrieves the user defined course categories.
3940
     *
3941
     * @param int $userId
3942
     *
3943
     * @return array
3944
     */
3945
    public static function get_user_course_categories($userId = 0)
3946
    {
3947
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
3948
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3949
        $sql = "SELECT * FROM $table 
3950
                WHERE user_id = $userId
3951
                ORDER BY sort ASC
3952
                ";
3953
        $result = Database::query($sql);
3954
        $output = [];
3955
        while ($row = Database::fetch_array($result, 'ASSOC')) {
3956
            $output[$row['id']] = $row;
3957
        }
3958
3959
        return $output;
3960
    }
3961
3962
    /**
3963
     * Return an array the user_category id and title for the course $courseId for user $userId.
3964
     *
3965
     * @param $userId
3966
     * @param $courseId
3967
     *
3968
     * @return array
3969
     */
3970
    public static function getUserCourseCategoryForCourse($userId, $courseId)
3971
    {
3972
        $tblCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3973
        $tblUserCategory = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3974
        $courseId = intval($courseId);
3975
        $userId = intval($userId);
3976
3977
        $sql = "SELECT user_course_cat, title
3978
                FROM $tblCourseRelUser cru
3979
                LEFT JOIN $tblUserCategory ucc
3980
                ON cru.user_course_cat = ucc.id
3981
                WHERE
3982
                    cru.user_id = $userId AND c_id = $courseId ";
3983
3984
        $res = Database::query($sql);
3985
3986
        $data = [];
3987
        if (Database::num_rows($res) > 0) {
3988
            $data = Database::fetch_assoc($res);
3989
        }
3990
3991
        return $data;
3992
    }
3993
3994
    /**
3995
     * Get the course id based on the original id and field name in the extra fields.
3996
     * Returns 0 if course was not found.
3997
     *
3998
     * @param string $value    Original course code
3999
     * @param string $variable Original field name
4000
     *
4001
     * @return array
4002
     */
4003
    public static function getCourseInfoFromOriginalId($value, $variable)
4004
    {
4005
        $extraFieldValue = new ExtraFieldValue('course');
4006
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
4007
            $variable,
4008
            $value
4009
        );
4010
4011
        if (!empty($result)) {
4012
            $courseInfo = api_get_course_info_by_id($result['item_id']);
4013
4014
            return $courseInfo;
4015
        }
4016
4017
        return [];
4018
    }
4019
4020
    /**
4021
     * Display code for one specific course a logged in user is subscribed to.
4022
     * Shows a link to the course, what's new icons...
4023
     *
4024
     * $my_course['d'] - course directory
4025
     * $my_course['i'] - course title
4026
     * $my_course['c'] - visual course code
4027
     * $my_course['k']  - system course code
4028
     *
4029
     * @param   array       Course details
4030
     * @param   int     Session ID
4031
     * @param   string      CSS class to apply to course entry
4032
     * @param   bool     Whether the session is supposedly accessible now
4033
     * (not in the case it has passed and is in invisible/unaccessible mode)
4034
     * @param bool      Whether to show the document quick-loader or not
4035
     *
4036
     * @return string The HTML to be printed for the course entry
4037
     *
4038
     * @version 1.0.3
4039
     *
4040
     * @todo refactor into different functions for database calls | logic | display
4041
     * @todo replace single-character $my_course['d'] indices
4042
     * @todo move code for what's new icons to a separate function to clear things up
4043
     * @todo add a parameter user_id so that it is possible to show the
4044
     * courselist of other users (=generalisation).
4045
     * This will prevent having to write a new function for this.
4046
     */
4047
    public static function get_logged_user_course_html(
4048
        $course,
4049
        $session_id = 0,
4050
        $class = 'courses',
4051
        $session_accessible = true,
4052
        $load_dirs = false
4053
    ) {
4054
        $now = date('Y-m-d h:i:s');
4055
        $user_id = api_get_user_id();
4056
        $course_info = api_get_course_info_by_id($course['real_id']);
4057
        $course_visibility = (int) $course_info['visibility'];
4058
4059
        if ($course_visibility === COURSE_VISIBILITY_HIDDEN) {
4060
            return '';
4061
        }
4062
4063
        $userInCourseStatus = self::getUserInCourseStatus(
4064
            $user_id,
4065
            $course_info['real_id']
4066
        );
4067
4068
        $course_info['status'] = empty($session_id) ? $userInCourseStatus : STUDENT;
4069
        $course_info['id_session'] = $session_id;
4070
4071
        $is_coach = api_is_coach($session_id, $course_info['real_id']);
4072
4073
        // Display course entry.
4074
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
4075
        $session_url = '';
4076
        $params = [];
4077
        $params['icon'] = Display::return_icon(
4078
            'session.png',
4079
            null,
4080
            [],
4081
            ICON_SIZE_LARGE,
4082
            null,
4083
            true
4084
        );
4085
        $params['real_id'] = $course_info['real_id'];
4086
4087
        // Display the "what's new" icons
4088
        $notifications = '';
4089
        if (
4090
            ($course_visibility != COURSE_VISIBILITY_CLOSED && $course_visibility != COURSE_VISIBILITY_HIDDEN) ||
4091
            !api_get_configuration_value('hide_course_notification')
4092
        ) {
4093
            $notifications .= Display::show_notification($course_info);
4094
        }
4095
4096
        if ($session_accessible) {
4097
            if ($course_visibility != COURSE_VISIBILITY_CLOSED ||
4098
                $userInCourseStatus == COURSEMANAGER
4099
            ) {
4100
                if (empty($course_info['id_session'])) {
4101
                    $course_info['id_session'] = 0;
4102
                }
4103
4104
                $sessionCourseAvailable = false;
4105
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
4106
4107
                if (in_array(
4108
                    $sessionCourseStatus,
4109
                    [SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE]
4110
                )) {
4111
                    $sessionCourseAvailable = true;
4112
                }
4113
4114
                if ($userInCourseStatus === COURSEMANAGER || $sessionCourseAvailable) {
4115
                    $session_url = $course_info['course_public_url'].'?id_session='.$course_info['id_session'];
4116
                    $session_title = '<a title="'.$course_info['name'].'" href="'.$session_url.'">'.
4117
                        $course_info['name'].'</a>'.$notifications;
4118
                } else {
4119
                    $session_title = $course_info['name'];
4120
                }
4121
            } else {
4122
                $session_title =
4123
                    $course_info['name'].' '.
4124
                    Display::tag('span', get_lang('(the course is currently closed)'), ['class' => 'item_closed']);
4125
            }
4126
        } else {
4127
            $session_title = $course_info['name'];
4128
        }
4129
4130
        $thumbnails = null;
4131
        $image = null;
4132
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
4133
        $iconName = basename($course_info['course_image']);
4134
4135
        if ($showCustomIcon === 'true' && $iconName != 'course.png') {
4136
            $thumbnails = $course_info['course_image'];
4137
            $image = $course_info['course_image_large'];
4138
        } else {
4139
            $image = Display::return_icon(
4140
                'session_default.png',
4141
                null,
4142
                null,
4143
                null,
4144
                null,
4145
                true
4146
            );
4147
        }
4148
        $params['thumbnails'] = $thumbnails;
4149
        $params['image'] = $image;
4150
        $params['html_image'] = '';
4151
        if (!empty($thumbnails)) {
4152
            $params['html_image'] = Display::img($thumbnails, $course_info['name'], ['class' => 'img-responsive']);
4153
        } else {
4154
            $params['html_image'] = Display::return_icon('session.png', $course_info['name'], ['class' => 'img-responsive'], ICON_SIZE_LARGE, $course_info['name']);
4155
        }
4156
        $params['link'] = $session_url;
4157
        $params['title'] = $session_title;
4158
        $params['name'] = $course_info['name'];
4159
        $params['edit_actions'] = '';
4160
        $params['document'] = '';
4161
        $params['category'] = $course_info['categoryName'];
4162
4163
        if ($course_visibility != COURSE_VISIBILITY_CLOSED &&
4164
            $course_visibility != COURSE_VISIBILITY_HIDDEN
4165
        ) {
4166
            if (api_is_platform_admin()) {
4167
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course_info['code'];
4168
                if ($load_dirs) {
4169
                    $params['document'] .= '<a 
4170
                        id="document_preview_'.$course_info['real_id'].'_'.$course_info['id_session'].'" 
4171
                        class="document_preview btn btn-default btn-sm" 
4172
                        href="javascript:void(0);">'.
4173
                        Display::returnFontAwesomeIcon('folder-open').'</a>';
4174
                    $params['document'] .= Display::div('', [
4175
                        'id' => 'document_result_'.$course_info['real_id'].'_'.$course_info['id_session'],
4176
                        'class' => 'document_preview_container',
4177
                    ]);
4178
                }
4179
            }
4180
        }
4181
        if (api_get_setting('display_teacher_in_courselist') === 'true') {
4182
            $teacher_list = self::getTeachersFromCourse(
4183
                $course_info['real_id'],
4184
                true
4185
            );
4186
            $course_coachs = self::get_coachs_from_course(
4187
                $course_info['id_session'],
4188
                $course_info['real_id']
4189
            );
4190
            $params['teachers'] = $teacher_list;
4191
4192
            if (($course_info['status'] == STUDENT && !empty($course_info['id_session'])) ||
4193
                ($is_coach && $course_info['status'] != COURSEMANAGER)
4194
            ) {
4195
                $params['coaches'] = $course_coachs;
4196
            }
4197
        }
4198
        $special = isset($course['special_course']) ? true : false;
4199
        $params['title'] = $session_title;
4200
        $params['special'] = $special;
4201
        if (api_get_setting('display_coursecode_in_courselist') === 'true') {
4202
            $params['visual_code'] = '('.$course_info['visual_code'].')';
4203
        }
4204
        $params['extra'] = '';
4205
        $html = $params;
4206
4207
        $session_category_id = null;
4208
        if (1) {
4209
            $session = '';
4210
            $active = false;
4211
            if (!empty($course_info['id_session'])) {
4212
                $session = api_get_session_info($course_info['id_session']);
4213
                $sessionCoachName = '';
4214
                if (!empty($session['id_coach'])) {
4215
                    $coachInfo = api_get_user_info($session['id_coach']);
4216
                    $sessionCoachName = $coachInfo['complete_name'];
4217
                }
4218
4219
                $session_category_id = self::get_session_category_id_by_session_id($course_info['id_session']);
4220
4221
                if (
4222
                    $session['access_start_date'] === '0000-00-00 00:00:00' || empty($session['access_start_date']) ||
4223
                    $session['access_start_date'] === '0000-00-00'
4224
                ) {
4225
                    $session['dates'] = '';
4226
                    if (api_get_setting('show_session_coach') === 'true') {
4227
                        $session['coach'] = get_lang('General coach').': '.$sessionCoachName;
4228
                    }
4229
                    $active = true;
4230
                } else {
4231
                    $session['dates'] = ' - '.
4232
                        get_lang('From').' '.$session['access_start_date'].' '.
4233
                        get_lang('To').' '.$session['access_end_date'];
4234
                    if (api_get_setting('show_session_coach') === 'true') {
4235
                        $session['coach'] = get_lang('General coach').': '.$sessionCoachName;
4236
                    }
4237
                    $date_start = $session['access_start_date'];
4238
                    $date_end = $session['access_end_date'];
4239
                    $active = !$date_end ? ($date_start <= $now) : ($date_start <= $now && $date_end >= $now);
4240
                }
4241
            }
4242
            $user_course_category = '';
4243
            if (isset($course_info['user_course_cat'])) {
4244
                $user_course_category = $course_info['user_course_cat'];
4245
            }
4246
            $output = [
4247
                $user_course_category,
4248
                $html,
4249
                $course_info['id_session'],
4250
                $session,
4251
                'active' => $active,
4252
                'session_category_id' => $session_category_id,
4253
            ];
4254
4255
            if (Skill::isAllowed($user_id, false)) {
4256
                $em = Database::getManager();
4257
                $objUser = api_get_user_entity($user_id);
4258
                /** @var Course $objCourse */
4259
                $objCourse = $em->find('ChamiloCoreBundle:Course', $course['real_id']);
4260
                $objSession = $em->find('ChamiloCoreBundle:Session', $session_id);
4261
4262
                $skill = $em->getRepository('ChamiloCoreBundle:Skill')->getLastByUser($objUser, $objCourse, $objSession);
4263
4264
                $output['skill'] = null;
4265
                if ($skill) {
4266
                    $output['skill']['name'] = $skill->getName();
4267
                    $output['skill']['icon'] = $skill->getIcon();
4268
                }
4269
            }
4270
        } else {
4271
            $output = [$course_info['user_course_cat'], $html];
4272
        }
4273
4274
        return $output;
4275
    }
4276
4277
    /**
4278
     * @param string $source_course_code
4279
     * @param int    $source_session_id
4280
     * @param string $destination_course_code
4281
     * @param int    $destination_session_id
4282
     * @param array  $params
4283
     *
4284
     * @return bool
4285
     */
4286
    public static function copy_course(
4287
        $source_course_code,
4288
        $source_session_id,
4289
        $destination_course_code,
4290
        $destination_session_id,
4291
        $params = []
4292
    ) {
4293
        $course_info = api_get_course_info($source_course_code);
4294
4295
        if (!empty($course_info)) {
4296
            $cb = new CourseBuilder('', $course_info);
4297
            $course = $cb->build($source_session_id, $source_course_code, true);
4298
            $course_restorer = new CourseRestorer($course);
4299
            $course_restorer->skip_content = $params;
4300
            $course_restorer->restore(
4301
                $destination_course_code,
4302
                $destination_session_id,
4303
                true,
4304
                true
4305
            );
4306
4307
            return true;
4308
        }
4309
4310
        return false;
4311
    }
4312
4313
    /**
4314
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code.
4315
     *
4316
     * @param string $new_title new course title
4317
     * @param string source course code
4318
     * @param int source session id
4319
     * @param int destination session id
4320
     * @param array $params
4321
     *
4322
     * @return array
4323
     */
4324
    public static function copy_course_simple(
4325
        $new_title,
4326
        $source_course_code,
4327
        $source_session_id = 0,
4328
        $destination_session_id = 0,
4329
        $params = []
4330
    ) {
4331
        $source_course_info = api_get_course_info($source_course_code);
4332
        if (!empty($source_course_info)) {
4333
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4334
            if ($new_course_code) {
4335
                $new_course_info = self::create_course(
4336
                    $new_title,
4337
                    $new_course_code,
4338
                    false
4339
                );
4340
                if (!empty($new_course_info['code'])) {
4341
                    $result = self::copy_course(
4342
                        $source_course_code,
4343
                        $source_session_id,
4344
                        $new_course_info['code'],
4345
                        $destination_session_id,
4346
                        $params
4347
                    );
4348
                    if ($result) {
4349
                        return $new_course_info;
4350
                    }
4351
                }
4352
            }
4353
        }
4354
4355
        return false;
4356
    }
4357
4358
    /**
4359
     * Creates a new course code based in a given code.
4360
     *
4361
     * @param string    wanted code
4362
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return: course3</code>
4363
     * if the course code doest not exist in the DB the same course code will be returned
4364
     *
4365
     * @return string wanted unused code
4366
     */
4367
    public static function generate_nice_next_course_code($wanted_code)
4368
    {
4369
        $course_code_ok = !self::course_code_exists($wanted_code);
4370
        if (!$course_code_ok) {
4371
            $wanted_code = self::generate_course_code($wanted_code);
4372
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4373
            $wanted_code = Database::escape_string($wanted_code);
4374
            $sql = "SELECT count(id) as count
4375
                    FROM $table
4376
                    WHERE code LIKE '$wanted_code%'";
4377
            $result = Database::query($sql);
4378
            if (Database::num_rows($result) > 0) {
4379
                $row = Database::fetch_array($result);
4380
                $count = $row['count'] + 1;
4381
                $wanted_code = $wanted_code.'_'.$count;
4382
                $result = api_get_course_info($wanted_code);
4383
                if (empty($result)) {
4384
                    return $wanted_code;
4385
                }
4386
            }
4387
4388
            return false;
4389
        }
4390
4391
        return $wanted_code;
4392
    }
4393
4394
    /**
4395
     * Gets the status of the users agreement in a course course-session.
4396
     *
4397
     * @param int    $user_id
4398
     * @param string $course_code
4399
     * @param int    $session_id
4400
     *
4401
     * @return bool
4402
     */
4403
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = 0)
4404
    {
4405
        $user_id = intval($user_id);
4406
        $course_code = Database::escape_string($course_code);
4407
        $session_id = intval($session_id);
4408
4409
        $courseInfo = api_get_course_info($course_code);
4410
        $courseId = $courseInfo['real_id'];
4411
4412
        // Course legal
4413
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4414
4415
        if ($enabled == 'true') {
4416
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4417
            $plugin = CourseLegalPlugin::create();
4418
4419
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4420
        }
4421
4422
        if (empty($session_id)) {
4423
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4424
            $sql = "SELECT legal_agreement FROM $table
4425
                    WHERE user_id = $user_id AND c_id = $courseId ";
4426
            $result = Database::query($sql);
4427
            if (Database::num_rows($result) > 0) {
4428
                $result = Database::fetch_array($result);
4429
                if ($result['legal_agreement'] == 1) {
4430
                    return true;
4431
                }
4432
            }
4433
4434
            return false;
4435
        } else {
4436
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4437
            $sql = "SELECT legal_agreement FROM $table
4438
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4439
            $result = Database::query($sql);
4440
            if (Database::num_rows($result) > 0) {
4441
                $result = Database::fetch_array($result);
4442
                if ($result['legal_agreement'] == 1) {
4443
                    return true;
4444
                }
4445
            }
4446
4447
            return false;
4448
        }
4449
    }
4450
4451
    /**
4452
     * Saves the user-course legal agreement.
4453
     *
4454
     * @param   int user id
4455
     * @param   string course code
4456
     * @param   int session id
4457
     *
4458
     * @return mixed
4459
     */
4460
    public static function save_user_legal($user_id, $course_code, $session_id = null)
4461
    {
4462
        // Course plugin legal
4463
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4464
        if ($enabled == 'true') {
4465
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4466
            $plugin = CourseLegalPlugin::create();
4467
4468
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4469
        }
4470
4471
        $user_id = intval($user_id);
4472
        $course_code = Database::escape_string($course_code);
4473
        $session_id = intval($session_id);
4474
        $courseInfo = api_get_course_info($course_code);
4475
        $courseId = $courseInfo['real_id'];
4476
4477
        if (empty($session_id)) {
4478
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4479
            $sql = "UPDATE $table SET legal_agreement = '1'
4480
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4481
            Database::query($sql);
4482
        } else {
4483
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4484
            $sql = "UPDATE  $table SET legal_agreement = '1'
4485
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4486
            Database::query($sql);
4487
        }
4488
    }
4489
4490
    /**
4491
     * @param int $user_id
4492
     * @param int $course_id
4493
     * @param int $session_id
4494
     * @param int $url_id
4495
     *
4496
     * @return bool
4497
     */
4498
    public static function get_user_course_vote($user_id, $course_id, $session_id = 0, $url_id = 0)
4499
    {
4500
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4501
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4502
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4503
        $user_id = intval($user_id);
4504
4505
        if (empty($user_id)) {
4506
            return false;
4507
        }
4508
4509
        $params = [
4510
            'user_id' => $user_id,
4511
            'c_id' => $course_id,
4512
            'session_id' => $session_id,
4513
            'url_id' => $url_id,
4514
        ];
4515
4516
        $result = Database::select(
4517
            'vote',
4518
            $table_user_course_vote,
4519
            [
4520
                'where' => [
4521
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params,
4522
                ],
4523
            ],
4524
            'first'
4525
        );
4526
        if (!empty($result)) {
4527
            return $result['vote'];
4528
        }
4529
4530
        return false;
4531
    }
4532
4533
    /**
4534
     * @param int $course_id
4535
     * @param int $session_id
4536
     * @param int $url_id
4537
     *
4538
     * @return array
4539
     */
4540
    public static function get_course_ranking(
4541
        $course_id,
4542
        $session_id = 0,
4543
        $url_id = 0
4544
    ) {
4545
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4546
4547
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4548
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4549
        $now = api_get_utc_datetime();
4550
4551
        $params = [
4552
            'c_id' => $course_id,
4553
            'session_id' => $session_id,
4554
            'url_id' => $url_id,
4555
            'creation_date' => $now,
4556
        ];
4557
4558
        $result = Database::select(
4559
            'c_id, accesses, total_score, users',
4560
            $table_course_ranking,
4561
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4562
            'first'
4563
        );
4564
4565
        $point_average_in_percentage = 0;
4566
        $point_average_in_star = 0;
4567
        $users_who_voted = 0;
4568
4569
        if (!empty($result['users'])) {
4570
            $users_who_voted = $result['users'];
4571
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4572
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4573
        }
4574
4575
        $result['user_vote'] = false;
4576
        if (!api_is_anonymous()) {
4577
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4578
        }
4579
4580
        $result['point_average'] = $point_average_in_percentage;
4581
        $result['point_average_star'] = $point_average_in_star;
4582
        $result['users_who_voted'] = $users_who_voted;
4583
4584
        return $result;
4585
    }
4586
4587
    /**
4588
     * Updates the course ranking.
4589
     *
4590
     * @param int   course id
4591
     * @param int $session_id
4592
     * @param int    url id
4593
     * @param $points_to_add
4594
     * @param bool $add_access
4595
     * @param bool $add_user
4596
     *
4597
     * @return array
4598
     */
4599
    public static function update_course_ranking(
4600
        $course_id = 0,
4601
        $session_id = 0,
4602
        $url_id = 0,
4603
        $points_to_add = null,
4604
        $add_access = true,
4605
        $add_user = true
4606
    ) {
4607
        // Course catalog stats modifications see #4191
4608
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4609
        $now = api_get_utc_datetime();
4610
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4611
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4612
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4613
4614
        $params = [
4615
            'c_id' => $course_id,
4616
            'session_id' => $session_id,
4617
            'url_id' => $url_id,
4618
            'creation_date' => $now,
4619
            'total_score' => 0,
4620
            'users' => 0,
4621
        ];
4622
4623
        $result = Database::select(
4624
            'id, accesses, total_score, users',
4625
            $table_course_ranking,
4626
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4627
            'first'
4628
        );
4629
4630
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4631
        if (empty($result)) {
4632
            if ($add_access) {
4633
                $params['accesses'] = 1;
4634
            }
4635
            //The votes and users are empty
4636
            if (isset($points_to_add) && !empty($points_to_add)) {
4637
                $params['total_score'] = intval($points_to_add);
4638
            }
4639
            if ($add_user) {
4640
                $params['users'] = 1;
4641
            }
4642
            $result = Database::insert($table_course_ranking, $params);
4643
        } else {
4644
            $my_params = [];
4645
4646
            if ($add_access) {
4647
                $my_params['accesses'] = intval($result['accesses']) + 1;
4648
            }
4649
            if (isset($points_to_add) && !empty($points_to_add)) {
4650
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4651
            }
4652
            if ($add_user) {
4653
                $my_params['users'] = $result['users'] + 1;
4654
            }
4655
4656
            if (!empty($my_params)) {
4657
                $result = Database::update(
4658
                    $table_course_ranking,
4659
                    $my_params,
4660
                    ['c_id = ? AND session_id = ? AND url_id = ?' => $params]
4661
                );
4662
            }
4663
        }
4664
4665
        return $result;
4666
    }
4667
4668
    /**
4669
     * Add user vote to a course.
4670
     *
4671
     * @param   int user id
4672
     * @param   int vote [1..5]
4673
     * @param   int course id
4674
     * @param   int session id
4675
     * @param   int url id (access_url_id)
4676
     *
4677
     * @return false|string 'added', 'updated' or 'nothing'
4678
     */
4679
    public static function add_course_vote(
4680
        $user_id,
4681
        $vote,
4682
        $course_id,
4683
        $session_id = 0,
4684
        $url_id = 0
4685
    ) {
4686
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4687
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4688
4689
        if (empty($course_id) || empty($user_id)) {
4690
            return false;
4691
        }
4692
4693
        if (!in_array($vote, [1, 2, 3, 4, 5])) {
4694
            return false;
4695
        }
4696
4697
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4698
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4699
        $vote = intval($vote);
4700
4701
        $params = [
4702
            'user_id' => intval($user_id),
4703
            'c_id' => $course_id,
4704
            'session_id' => $session_id,
4705
            'url_id' => $url_id,
4706
            'vote' => $vote,
4707
        ];
4708
4709
        $action_done = 'nothing';
4710
        $result = Database::select(
4711
            'id, vote',
4712
            $table_user_course_vote,
4713
            ['where' => ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4714
            'first'
4715
        );
4716
4717
        if (empty($result)) {
4718
            Database::insert($table_user_course_vote, $params);
4719
            $points_to_add = $vote;
4720
            $add_user = true;
4721
            $action_done = 'added';
4722
        } else {
4723
            $my_params = ['vote' => $vote];
4724
            $points_to_add = $vote - $result['vote'];
4725
            $add_user = false;
4726
4727
            Database::update(
4728
                $table_user_course_vote,
4729
                $my_params,
4730
                ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]
4731
            );
4732
            $action_done = 'updated';
4733
        }
4734
4735
        // Current points
4736
        if (!empty($points_to_add)) {
4737
            self::update_course_ranking(
4738
                $course_id,
4739
                $session_id,
4740
                $url_id,
4741
                $points_to_add,
4742
                false,
4743
                $add_user
4744
            );
4745
        }
4746
4747
        return $action_done;
4748
    }
4749
4750
    /**
4751
     * Remove course ranking + user votes.
4752
     *
4753
     * @param int $course_id
4754
     * @param int $session_id
4755
     * @param int $url_id
4756
     */
4757
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
4758
    {
4759
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4760
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4761
4762
        if (!empty($course_id) && isset($session_id)) {
4763
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4764
            $params = [
4765
                'c_id' => $course_id,
4766
                'session_id' => $session_id,
4767
                'url_id' => $url_id,
4768
            ];
4769
            Database::delete($table_course_ranking, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4770
            Database::delete($table_user_course_vote, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
4771
        }
4772
    }
4773
4774
    /**
4775
     * Returns an array with the hottest courses.
4776
     *
4777
     * @param int $days  number of days
4778
     * @param int $limit number of hottest courses
4779
     *
4780
     * @return array
4781
     */
4782
    public static function return_hot_courses($days = 30, $limit = 6)
4783
    {
4784
        if (api_is_invitee()) {
4785
            return [];
4786
        }
4787
4788
        $limit = (int) $limit;
4789
        $userId = api_get_user_id();
4790
4791
        // Getting my courses
4792
        $my_course_list = self::get_courses_list_by_user_id($userId);
4793
4794
        $codeList = [];
4795
        foreach ($my_course_list as $course) {
4796
            $codeList[$course['real_id']] = $course['real_id'];
4797
        }
4798
4799
        if (api_is_drh()) {
4800
            $courses = self::get_courses_followed_by_drh($userId);
4801
            foreach ($courses as $course) {
4802
                $codeList[$course['real_id']] = $course['real_id'];
4803
            }
4804
        }
4805
4806
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4807
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4808
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4809
        $urlId = api_get_current_access_url_id();
4810
        //$table_course_access table uses the now() and interval ...
4811
        $now = api_get_utc_datetime();
4812
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
4813
                FROM $table_course c
4814
                INNER JOIN $table_course_access a
4815
                ON (c.id = a.c_id)
4816
                INNER JOIN $table_course_url u
4817
                ON u.c_id = c.id
4818
                WHERE
4819
                    u.access_url_id = $urlId AND
4820
                    login_course_date <= '$now' AND
4821
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
4822
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
4823
                    visibility <> ".COURSE_VISIBILITY_HIDDEN." 
4824
                GROUP BY a.c_id
4825
                ORDER BY course_count DESC
4826
                LIMIT $limit
4827
            ";
4828
4829
        $result = Database::query($sql);
4830
        $courses = [];
4831
        if (Database::num_rows($result)) {
4832
            $courses = Database::store_result($result, 'ASSOC');
4833
            $courses = self::processHotCourseItem($courses, $codeList);
4834
        }
4835
4836
        return $courses;
4837
    }
4838
4839
    /**
4840
     * @param array $courses
4841
     * @param array $codeList
4842
     *
4843
     * @return mixed
4844
     */
4845
    public static function processHotCourseItem($courses, $codeList = [])
4846
    {
4847
        $hotCourses = [];
4848
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
4849
        $stok = Security::get_existing_token();
4850
        $user_id = api_get_user_id();
4851
4852
        foreach ($courses as $courseId) {
4853
            $course_info = api_get_course_info_by_id($courseId['c_id']);
4854
            $courseCode = $course_info['code'];
4855
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
4856
            $my_course = $course_info;
4857
            $my_course['go_to_course_button'] = '';
4858
            $my_course['register_button'] = '';
4859
4860
            $access_link = self::get_access_link_by_user(
4861
                api_get_user_id(),
4862
                $course_info,
4863
                $codeList
4864
            );
4865
4866
            $userRegisteredInCourse = self::is_user_subscribed_in_course($user_id, $course_info['code']);
4867
            $userRegisteredInCourseAsTeacher = self::is_course_teacher($user_id, $course_info['code']);
4868
            $userRegistered = $userRegisteredInCourse && $userRegisteredInCourseAsTeacher;
4869
            $my_course['is_course_student'] = $userRegisteredInCourse;
4870
            $my_course['is_course_teacher'] = $userRegisteredInCourseAsTeacher;
4871
            $my_course['is_registered'] = $userRegistered;
4872
            $my_course['title_cut'] = cut($course_info['title'], 45);
4873
4874
            // Course visibility
4875
            if ($access_link && in_array('register', $access_link)) {
4876
                $my_course['register_button'] = Display::url(
4877
                    get_lang('Subscribe').' '.
4878
                    Display::returnFontAwesomeIcon('sign-in'),
4879
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].
4880
                     '/index.php?action=subscribe&sec_token='.$stok,
4881
                    [
4882
                        'class' => 'btn btn-success btn-sm',
4883
                        'title' => get_lang('Subscribe'),
4884
                        'aria-label' => get_lang('Subscribe'),
4885
                    ]
4886
                );
4887
            }
4888
4889
            if ($access_link && in_array('enter', $access_link) ||
4890
                $course_info['visibility'] == COURSE_VISIBILITY_OPEN_WORLD
4891
            ) {
4892
                $my_course['go_to_course_button'] = Display::url(
4893
                    get_lang('Go to the course').' '.
4894
                    Display::returnFontAwesomeIcon('share'),
4895
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php',
4896
                    [
4897
                        'class' => 'btn btn-default btn-sm',
4898
                        'title' => get_lang('Go to the course'),
4899
                        'aria-label' => get_lang('Go to the course'),
4900
                    ]
4901
                );
4902
            }
4903
4904
            if ($access_link && in_array('unsubscribe', $access_link)) {
4905
                $my_course['unsubscribe_button'] = Display::url(
4906
                    get_lang('Unsubscribe').' '.
4907
                    Display::returnFontAwesomeIcon('sign-out'),
4908
                    api_get_path(WEB_CODE_PATH).'auth/courses.php?action=unsubscribe&unsubscribe='.$courseCode
4909
                    .'&sec_token='.$stok.'&category_code='.$categoryCode,
4910
                    [
4911
                        'class' => 'btn btn-danger btn-sm',
4912
                        'title' => get_lang('Unsubscribe'),
4913
                        'aria-label' => get_lang('Unsubscribe'),
4914
                    ]
4915
                );
4916
            }
4917
4918
            // start buycourse validation
4919
            // display the course price and buy button if the buycourses plugin is enabled and this course is configured
4920
            $plugin = BuyCoursesPlugin::create();
4921
            $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
4922
                $course_info['real_id'],
4923
                BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4924
            );
4925
            if ($isThisCourseInSale) {
4926
                // set the price label
4927
                $my_course['price'] = $isThisCourseInSale['html'];
4928
                // set the Buy button instead register.
4929
                if ($isThisCourseInSale['verificator'] && !empty($my_course['register_button'])) {
4930
                    $my_course['register_button'] = $plugin->returnBuyCourseButton(
4931
                        $course_info['real_id'],
4932
                        BuyCoursesPlugin::PRODUCT_TYPE_COURSE
4933
                    );
4934
                }
4935
            }
4936
            // end buycourse validation
4937
4938
            // Description
4939
            $my_course['description_button'] = self::returnDescriptionButton($course_info);
4940
            $my_course['teachers'] = self::getTeachersFromCourse($course_info['real_id'], true);
4941
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
4942
            $my_course['rating_html'] = '';
4943
            if (api_get_configuration_value('hide_course_rating') === false) {
4944
                $my_course['rating_html'] = Display::return_rating_system(
4945
                    'star_'.$course_info['real_id'],
4946
                    $ajax_url.'&course_id='.$course_info['real_id'],
4947
                    $point_info
4948
                );
4949
            }
4950
            $hotCourses[] = $my_course;
4951
        }
4952
4953
        return $hotCourses;
4954
    }
4955
4956
    public function totalSubscribedUsersInCourses($urlId)
4957
    {
4958
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4959
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4960
        $courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4961
4962
        $urlId = (int) $urlId;
4963
4964
        $sql = "SELECT count(cu.user_id) count 
4965
                FROM $courseUsers cu 
4966
                INNER JOIN $table_course_rel_access_url u 
4967
                ON cu.c_id = u.c_id                
4968
                WHERE
4969
                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
4970
                    u.access_url_id = $urlId AND 
4971
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
4972
                    visibility <> ".COURSE_VISIBILITY_HIDDEN." 
4973
                     ";
4974
4975
        $res = Database::query($sql);
4976
        $row = Database::fetch_array($res);
4977
4978
        return $row['count'];
4979
    }
4980
4981
    /**
4982
     * Get courses count.
4983
     *
4984
     * @param int $access_url_id Access URL ID (optional)
4985
     * @param int $visibility
4986
     *
4987
     * @return int Number of courses
4988
     */
4989
    public static function count_courses($access_url_id = null, $visibility = null)
4990
    {
4991
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4992
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4993
        $sql = "SELECT count(c.id) FROM $table_course c";
4994
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
4995
            $sql .= ", $table_course_rel_access_url u
4996
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
4997
            if (!empty($visibility)) {
4998
                $visibility = intval($visibility);
4999
                $sql .= " AND visibility = $visibility ";
5000
            }
5001
        } else {
5002
            if (!empty($visibility)) {
5003
                $visibility = intval($visibility);
5004
                $sql .= " WHERE visibility = $visibility ";
5005
            }
5006
        }
5007
5008
        $res = Database::query($sql);
5009
        $row = Database::fetch_row($res);
5010
5011
        return $row[0];
5012
    }
5013
5014
    /**
5015
     * Get active courses count.
5016
     * Active = all courses except the ones with hidden visibility.
5017
     *
5018
     * @param int $urlId Access URL ID (optional)
5019
     *
5020
     * @return int Number of courses
5021
     */
5022
    public static function countActiveCourses($urlId = null)
5023
    {
5024
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5025
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5026
        $sql = "SELECT count(c.id) FROM $table_course c";
5027
        if (!empty($urlId)) {
5028
            $urlId = (int) $urlId;
5029
            $sql .= ", $table_course_rel_access_url u
5030
                    WHERE
5031
                        c.id = u.c_id AND
5032
                        u.access_url_id = $urlId AND
5033
                        visibility <> ".COURSE_VISIBILITY_HIDDEN;
5034
        } else {
5035
            $sql .= " WHERE visibility <> ".COURSE_VISIBILITY_HIDDEN;
5036
        }
5037
        $res = Database::query($sql);
5038
        $row = Database::fetch_row($res);
5039
5040
        return $row[0];
5041
    }
5042
5043
    /**
5044
     * Returns the SQL conditions to filter course only visible by the user in the catalogue.
5045
     *
5046
     * @param string $courseTableAlias Alias of the course table
5047
     * @param bool   $hideClosed       Whether to hide closed and hidden courses
5048
     *
5049
     * @return string SQL conditions
5050
     */
5051
    public static function getCourseVisibilitySQLCondition(
5052
        $courseTableAlias,
5053
        $hideClosed = false
5054
    ) {
5055
        $visibilityCondition = '';
5056
        $hidePrivate = api_get_setting('course_catalog_hide_private');
5057
        if ($hidePrivate === 'true') {
5058
            $visibilityCondition .= " AND $courseTableAlias.visibility <> ".COURSE_VISIBILITY_REGISTERED;
5059
        }
5060
        if ($hideClosed) {
5061
            $visibilityCondition .= " AND $courseTableAlias.visibility NOT IN (".COURSE_VISIBILITY_CLOSED.','.COURSE_VISIBILITY_HIDDEN.')';
5062
        }
5063
5064
        // Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
5065
        $currentUserId = api_get_user_id();
5066
        $restrictedCourses = self::getCatalogueCourseList(true);
5067
        $allowedCoursesToCurrentUser = self::getCatalogueCourseList(true, $currentUserId);
5068
        if (!empty($restrictedCourses)) {
5069
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5070
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("'.implode('","', $allowedCoursesToCurrentUser).'"))';
5071
        }
5072
5073
        // Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
5074
        $restrictedCourses = self::getCatalogueCourseList(false);
5075
        $notAllowedCoursesToCurrentUser = self::getCatalogueCourseList(false, $currentUserId);
5076
        if (!empty($restrictedCourses)) {
5077
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5078
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("'.implode('","', $notAllowedCoursesToCurrentUser).'"))';
5079
        }
5080
5081
        return $visibilityCondition;
5082
    }
5083
5084
    /**
5085
     * Return a link to go to the course, validating the visibility of the
5086
     * course and the user status.
5087
     *
5088
     * @param int $uid User ID
5089
     * @param array Course details array
5090
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
5091
     *
5092
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
5093
     */
5094
    public static function get_access_link_by_user($uid, $course, $user_courses = [])
5095
    {
5096
        if (empty($uid) || empty($course)) {
5097
            return false;
5098
        }
5099
5100
        if (empty($user_courses)) {
5101
            // get the array of courses to which the user is subscribed
5102
            $user_courses = self::get_courses_list_by_user_id($uid);
5103
            foreach ($user_courses as $k => $v) {
5104
                $user_courses[$k] = $v['real_id'];
5105
            }
5106
        }
5107
5108
        if (!isset($course['real_id']) && empty($course['real_id'])) {
5109
            $course = api_get_course_info($course['code']);
5110
        }
5111
5112
        if ($course['visibility'] == COURSE_VISIBILITY_HIDDEN) {
5113
            return [];
5114
        }
5115
5116
        $is_admin = api_is_platform_admin_by_id($uid);
5117
        $options = [];
5118
        // Register button
5119
        if (!api_is_anonymous($uid) &&
5120
            (
5121
            ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD || $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM)
5122
                //$course['visibility'] == COURSE_VISIBILITY_REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
5123
            ) &&
5124
            $course['subscribe'] == SUBSCRIBE_ALLOWED &&
5125
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
5126
        ) {
5127
            $options[] = 'register';
5128
        }
5129
5130
        // Go To Course button (only if admin, if course public or if student already subscribed)
5131
        if ($is_admin ||
5132
            $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD && empty($course['registration_code']) ||
5133
            (api_user_is_login($uid) && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM && empty($course['registration_code'])) ||
5134
            (in_array($course['real_id'], $user_courses) && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
5135
        ) {
5136
            $options[] = 'enter';
5137
        }
5138
5139
        if ($is_admin ||
5140
            $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD && empty($course['registration_code']) ||
5141
            (api_user_is_login($uid) && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM && empty($course['registration_code'])) ||
5142
            (in_array($course['real_id'], $user_courses) && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
5143
        ) {
5144
            $options[] = 'enter';
5145
        }
5146
5147
        if ($course['visibility'] != COURSE_VISIBILITY_HIDDEN &&
5148
            empty($course['registration_code']) &&
5149
            $course['unsubscribe'] == UNSUBSCRIBE_ALLOWED &&
5150
            api_user_is_login($uid) &&
5151
            in_array($course['real_id'], $user_courses)
5152
        ) {
5153
            $options[] = 'unsubscribe';
5154
        }
5155
5156
        return $options;
5157
    }
5158
5159
    /**
5160
     * @param array          $courseInfo
5161
     * @param array          $teachers
5162
     * @param bool           $deleteTeachersNotInList
5163
     * @param bool           $editTeacherInSessions
5164
     * @param bool           $deleteSessionTeacherNotInList
5165
     * @param array          $teacherBackup
5166
     * @param Monolog\Logger $logger
5167
     *
5168
     * @return false|null
5169
     */
5170
    public static function updateTeachers(
5171
        $courseInfo,
5172
        $teachers,
5173
        $deleteTeachersNotInList = true,
5174
        $editTeacherInSessions = false,
5175
        $deleteSessionTeacherNotInList = false,
5176
        $teacherBackup = [],
5177
        $logger = null
5178
    ) {
5179
        if (!is_array($teachers)) {
5180
            $teachers = [$teachers];
5181
        }
5182
5183
        if (empty($courseInfo) || !isset($courseInfo['real_id'])) {
5184
            return false;
5185
        }
5186
5187
        $teachers = array_filter($teachers);
5188
        $courseId = $courseInfo['real_id'];
5189
        $course_code = $courseInfo['code'];
5190
5191
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5192
        $alreadyAddedTeachers = self::get_teacher_list_from_course_code($course_code);
5193
5194
        if ($deleteTeachersNotInList) {
5195
            // Delete only teacher relations that doesn't match the selected teachers
5196
            $cond = null;
5197
            if (count($teachers) > 0) {
5198
                foreach ($teachers as $key) {
5199
                    $key = Database::escape_string($key);
5200
                    $cond .= " AND user_id <> '".$key."'";
5201
                }
5202
            }
5203
5204
            // Recover user categories
5205
            $sql = "SELECT * FROM $course_user_table
5206
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5207
            $result = Database::query($sql);
5208
            if (Database::num_rows($result)) {
5209
                $teachersToDelete = Database::store_result($result, 'ASSOC');
5210
                foreach ($teachersToDelete as $data) {
5211
                    $userId = $data['user_id'];
5212
                    $teacherBackup[$userId][$course_code] = $data;
5213
                }
5214
            }
5215
5216
            $sql = "DELETE FROM $course_user_table
5217
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5218
5219
            Database::query($sql);
5220
        }
5221
5222
        if (count($teachers) > 0) {
5223
            foreach ($teachers as $userId) {
5224
                $userId = intval($userId);
5225
                // We check if the teacher is already subscribed in this course
5226
                $sql = "SELECT 1 FROM $course_user_table
5227
                        WHERE user_id = $userId AND c_id = $courseId";
5228
                $result = Database::query($sql);
5229
                if (Database::num_rows($result)) {
5230
                    $sql = "UPDATE $course_user_table 
5231
                            SET status = 1
5232
                            WHERE c_id = $courseId AND user_id = $userId ";
5233
                } else {
5234
                    $userCourseCategory = '0';
5235
                    if (isset($teacherBackup[$userId]) &&
5236
                        isset($teacherBackup[$userId][$course_code])
5237
                    ) {
5238
                        $courseUserData = $teacherBackup[$userId][$course_code];
5239
                        $userCourseCategory = $courseUserData['user_course_cat'];
5240
                        if ($logger) {
5241
                            $logger->addInfo("Recovering user_course_cat: $userCourseCategory");
5242
                        }
5243
                    }
5244
5245
                    $sql = "INSERT INTO $course_user_table SET
5246
                            c_id = $courseId,
5247
                            user_id = $userId,
5248
                            status = 1,
5249
                            is_tutor = 0,
5250
                            sort = 0,
5251
                            relation_type = 0,
5252
                            user_course_cat = $userCourseCategory
5253
                    ";
5254
                }
5255
                Database::query($sql);
5256
            }
5257
        }
5258
5259
        if ($editTeacherInSessions) {
5260
            $sessions = SessionManager::get_session_by_course($courseId);
5261
            if (!empty($sessions)) {
5262
                if ($logger) {
5263
                    $logger->addInfo("Edit teachers in sessions");
5264
                }
5265
                foreach ($sessions as $session) {
5266
                    $sessionId = $session['id'];
5267
                    // Remove old and add new
5268
                    if ($deleteSessionTeacherNotInList) {
5269
                        foreach ($teachers as $userId) {
5270
                            if ($logger) {
5271
                                $logger->addInfo("Set coach #$userId in session #$sessionId of course #$courseId ");
5272
                            }
5273
                            SessionManager::set_coach_to_course_session(
5274
                                $userId,
5275
                                $sessionId,
5276
                                $courseId
5277
                            );
5278
                        }
5279
5280
                        $teachersToDelete = [];
5281
                        if (!empty($alreadyAddedTeachers)) {
5282
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
5283
                        }
5284
5285
                        if (!empty($teachersToDelete)) {
5286
                            foreach ($teachersToDelete as $userId) {
5287
                                if ($logger) {
5288
                                    $logger->addInfo("Delete coach #$userId in session #$sessionId of course #$courseId ");
5289
                                }
5290
                                SessionManager::set_coach_to_course_session(
5291
                                    $userId,
5292
                                    $sessionId,
5293
                                    $courseId,
5294
                                    true
5295
                                );
5296
                            }
5297
                        }
5298
                    } else {
5299
                        // Add new teachers only
5300
                        foreach ($teachers as $userId) {
5301
                            if ($logger) {
5302
                                $logger->addInfo("Add coach #$userId in session #$sessionId of course #$courseId ");
5303
                            }
5304
                            SessionManager::set_coach_to_course_session(
5305
                                $userId,
5306
                                $sessionId,
5307
                                $courseId
5308
                            );
5309
                        }
5310
                    }
5311
                }
5312
            }
5313
        }
5314
    }
5315
5316
    /**
5317
     * Course available settings variables see c_course_setting table.
5318
     *
5319
     * @param AppPlugin $appPlugin
5320
     *
5321
     * @return array
5322
     */
5323
    public static function getCourseSettingVariables(AppPlugin $appPlugin)
5324
    {
5325
        $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
5326
        $courseSettings = [
5327
            // Get allow_learning_path_theme from table
5328
            'allow_learning_path_theme',
5329
            // Get allow_open_chat_window from table
5330
            'allow_open_chat_window',
5331
            'allow_public_certificates',
5332
            // Get allow_user_edit_agenda from table
5333
            'allow_user_edit_agenda',
5334
            // Get allow_user_edit_announcement from table
5335
            'allow_user_edit_announcement',
5336
            // Get allow_user_image_forum from table
5337
            'allow_user_image_forum',
5338
            //Get allow show user list
5339
            'allow_user_view_user_list',
5340
            // Get course_theme from table
5341
            'course_theme',
5342
            //Get allow show user list
5343
            'display_info_advance_inside_homecourse',
5344
            'documents_default_visibility',
5345
            // Get send_mail_setting (work)from table
5346
            'email_alert_manager_on_new_doc',
5347
            // Get send_mail_setting (work)from table
5348
            'email_alert_manager_on_new_quiz',
5349
            // Get send_mail_setting (dropbox) from table
5350
            'email_alert_on_new_doc_dropbox',
5351
            'email_alert_students_on_new_homework',
5352
            // Get send_mail_setting (auth)from table
5353
            'email_alert_to_teacher_on_new_user_in_course',
5354
            'enable_lp_auto_launch',
5355
            'enable_exercise_auto_launch',
5356
            'enable_document_auto_launch',
5357
            'pdf_export_watermark_text',
5358
            'show_system_folders',
5359
            'exercise_invisible_in_session',
5360
            'enable_forum_auto_launch',
5361
            'show_course_in_user_language',
5362
            'email_to_teachers_on_new_work_feedback',
5363
            'student_delete_own_publication',
5364
            'hide_forum_notifications',
5365
            'quiz_question_limit_per_day',
5366
            'subscribe_users_to_forum_notifications',
5367
        ];
5368
5369
        $courseModels = ExerciseLib::getScoreModels();
5370
        if (!empty($courseModels)) {
5371
            $courseSettings[] = 'score_model_id';
5372
        }
5373
5374
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5375
        if ($allowLPReturnLink === 'true') {
5376
            $courseSettings[] = 'lp_return_link';
5377
        }
5378
5379
        if (!empty($pluginCourseSettings)) {
5380
            $courseSettings = array_merge(
5381
                $courseSettings,
5382
                $pluginCourseSettings
5383
            );
5384
        }
5385
5386
        return $courseSettings;
5387
    }
5388
5389
    /**
5390
     * @param AppPlugin    $appPlugin
5391
     * @param string       $variable
5392
     * @param string|array $value
5393
     * @param int          $courseId
5394
     *
5395
     * @return bool
5396
     */
5397
    public static function saveCourseConfigurationSetting(AppPlugin $appPlugin, $variable, $value, $courseId)
5398
    {
5399
        $settingList = self::getCourseSettingVariables($appPlugin);
5400
5401
        if (!in_array($variable, $settingList)) {
5402
            return false;
5403
        }
5404
5405
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5406
5407
        if (is_array($value)) {
5408
            $value = implode(',', $value);
5409
        }
5410
5411
        if (self::hasCourseSetting($variable, $courseId)) {
5412
            // Update
5413
            Database::update(
5414
                $courseSettingTable,
5415
                ['value' => $value],
5416
                ['variable = ? AND c_id = ?' => [$variable, $courseId]]
5417
            );
5418
        } else {
5419
            // Create
5420
            Database::insert(
5421
                $courseSettingTable,
5422
                [
5423
                    'title' => $variable,
5424
                    'value' => $value,
5425
                    'c_id' => $courseId,
5426
                    'variable' => $variable,
5427
                ]
5428
            );
5429
        }
5430
5431
        return true;
5432
    }
5433
5434
    /**
5435
     * Check if course setting exists.
5436
     *
5437
     * @param string $variable
5438
     * @param int    $courseId
5439
     *
5440
     * @return bool
5441
     */
5442
    public static function hasCourseSetting($variable, $courseId)
5443
    {
5444
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5445
        $courseId = (int) $courseId;
5446
        $variable = Database::escape_string($variable);
5447
        $sql = "SELECT variable FROM $courseSetting
5448
                WHERE c_id = $courseId AND variable = '$variable'";
5449
        $result = Database::query($sql);
5450
5451
        return Database::num_rows($result) > 0;
5452
    }
5453
5454
    /**
5455
     * Get information from the track_e_course_access table.
5456
     *
5457
     * @param int    $courseId
5458
     * @param int    $sessionId
5459
     * @param string $startDate
5460
     * @param string $endDate
5461
     *
5462
     * @return array
5463
     */
5464
    public static function getCourseAccessPerCourseAndSession(
5465
        $courseId,
5466
        $sessionId,
5467
        $startDate,
5468
        $endDate
5469
    ) {
5470
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5471
        $courseId = (int) $courseId;
5472
        $sessionId = (int) $sessionId;
5473
        $startDate = Database::escape_string($startDate);
5474
        $endDate = Database::escape_string($endDate);
5475
5476
        $sql = "SELECT * FROM $table
5477
                WHERE
5478
                    c_id = $courseId AND
5479
                    session_id = $sessionId AND
5480
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5481
                ";
5482
5483
        $result = Database::query($sql);
5484
5485
        return Database::store_result($result);
5486
    }
5487
5488
    /**
5489
     * Get login information from the track_e_course_access table, for any
5490
     * course in the given session.
5491
     *
5492
     * @param int $sessionId
5493
     * @param int $userId
5494
     *
5495
     * @return array
5496
     */
5497
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5498
    {
5499
        $sessionId = (int) $sessionId;
5500
        $userId = (int) $userId;
5501
5502
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5503
        $sql = "SELECT * FROM $table
5504
                WHERE session_id = $sessionId AND user_id = $userId
5505
                ORDER BY login_course_date ASC
5506
                LIMIT 1";
5507
5508
        $result = Database::query($sql);
5509
        $courseAccess = [];
5510
        if (Database::num_rows($result)) {
5511
            $courseAccess = Database::fetch_array($result, 'ASSOC');
5512
        }
5513
5514
        return $courseAccess;
5515
    }
5516
5517
    /**
5518
     * @param int  $courseId
5519
     * @param int  $sessionId
5520
     * @param bool $getAllSessions
5521
     *
5522
     * @return mixed
5523
     */
5524
    public static function getCountForum(
5525
        $courseId,
5526
        $sessionId = 0,
5527
        $getAllSessions = false
5528
    ) {
5529
        $forum = Database::get_course_table(TABLE_FORUM);
5530
        if ($getAllSessions) {
5531
            $sql = "SELECT count(*) as count
5532
                    FROM $forum f
5533
                    WHERE f.c_id = %s";
5534
        } else {
5535
            $sql = "SELECT count(*) as count
5536
                    FROM $forum f
5537
                    WHERE f.c_id = %s and f.session_id = %s";
5538
        }
5539
5540
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5541
        $result = Database::query($sql);
5542
        $row = Database::fetch_array($result);
5543
5544
        return $row['count'];
5545
    }
5546
5547
    /**
5548
     * @param int $userId
5549
     * @param int $courseId
5550
     * @param int $sessionId
5551
     *
5552
     * @return mixed
5553
     */
5554
    public static function getCountPostInForumPerUser(
5555
        $userId,
5556
        $courseId,
5557
        $sessionId = 0
5558
    ) {
5559
        $forum = Database::get_course_table(TABLE_FORUM);
5560
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5561
5562
        $sql = "SELECT count(distinct post_id) as count
5563
                FROM $forum_post p
5564
                INNER JOIN $forum f
5565
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5566
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5567
5568
        $sql = sprintf(
5569
            $sql,
5570
            intval($userId),
5571
            intval($sessionId),
5572
            intval($courseId)
5573
        );
5574
5575
        $result = Database::query($sql);
5576
        $row = Database::fetch_array($result);
5577
5578
        return $row['count'];
5579
    }
5580
5581
    /**
5582
     * @param int $userId
5583
     * @param int $courseId
5584
     * @param int $sessionId
5585
     *
5586
     * @return mixed
5587
     */
5588
    public static function getCountForumPerUser(
5589
        $userId,
5590
        $courseId,
5591
        $sessionId = 0
5592
    ) {
5593
        $forum = Database::get_course_table(TABLE_FORUM);
5594
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5595
5596
        $sql = "SELECT count(distinct f.forum_id) as count
5597
                FROM $forum_post p
5598
                INNER JOIN $forum f
5599
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5600
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5601
5602
        $sql = sprintf(
5603
            $sql,
5604
            intval($userId),
5605
            intval($sessionId),
5606
            intval($courseId)
5607
        );
5608
5609
        $result = Database::query($sql);
5610
        $row = Database::fetch_array($result);
5611
5612
        return $row['count'];
5613
    }
5614
5615
    /**
5616
     * Returns the course name from a given code.
5617
     *
5618
     * @param string $code
5619
     *
5620
     * @return string
5621
     */
5622
    public static function getCourseNameFromCode($code)
5623
    {
5624
        $tbl_main_categories = Database::get_main_table(TABLE_MAIN_COURSE);
5625
        $code = Database::escape_string($code);
5626
        $sql = "SELECT title
5627
                FROM $tbl_main_categories
5628
                WHERE code = '$code'";
5629
        $result = Database::query($sql);
5630
        if ($col = Database::fetch_array($result)) {
5631
            return $col['title'];
5632
        }
5633
    }
5634
5635
    /**
5636
     * Generates a course code from a course title.
5637
     *
5638
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
5639
     * @todo the function might be upgraded for avoiding code duplications (currently,
5640
     * it might suggest a code that is already in use)
5641
     *
5642
     * @param string $title A course title
5643
     *
5644
     * @return string A proposed course code
5645
     *                +
5646
     * @assert (null,null) === false
5647
     * @assert ('ABC_DEF', null) === 'ABCDEF'
5648
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
5649
     */
5650
    public static function generate_course_code($title)
5651
    {
5652
        return substr(
5653
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
5654
            0,
5655
            self::MAX_COURSE_LENGTH_CODE
5656
        );
5657
    }
5658
5659
    /**
5660
     * this function gets all the users of the course,
5661
     * including users from linked courses.
5662
     *
5663
     * @param $filterByActive
5664
     *
5665
     * @return array
5666
     */
5667
    public static function getCourseUsers($filterByActive = null)
5668
    {
5669
        // This would return only the users from real courses:
5670
        $userList = self::get_user_list_from_course_code(
5671
            api_get_course_id(),
5672
            api_get_session_id(),
5673
            null,
5674
            null,
5675
            null,
5676
            null,
5677
            false,
5678
            false,
5679
            [],
5680
            [],
5681
            [],
5682
            $filterByActive
5683
        );
5684
5685
        return $userList;
5686
    }
5687
5688
    /**
5689
     * this function gets all the groups of the course,
5690
     * not including linked courses.
5691
     */
5692
    public static function getCourseGroups()
5693
    {
5694
        $sessionId = api_get_session_id();
5695
        if ($sessionId != 0) {
5696
            $groupList = self::get_group_list_of_course(
5697
                api_get_course_id(),
5698
                $sessionId,
5699
                1
5700
            );
5701
        } else {
5702
            $groupList = self::get_group_list_of_course(
5703
                api_get_course_id(),
5704
                0,
5705
                1
5706
            );
5707
        }
5708
5709
        return $groupList;
5710
    }
5711
5712
    /**
5713
     * @param FormValidator $form
5714
     * @param array         $alreadySelected
5715
     *
5716
     * @return HTML_QuickForm_element
5717
     */
5718
    public static function addUserGroupMultiSelect(&$form, $alreadySelected)
5719
    {
5720
        $userList = self::getCourseUsers(true);
5721
        $groupList = self::getCourseGroups();
5722
5723
        $array = self::buildSelectOptions(
5724
            $groupList,
5725
            $userList,
5726
            $alreadySelected
5727
        );
5728
5729
        $result = [];
5730
        foreach ($array as $content) {
5731
            $result[$content['value']] = $content['content'];
5732
        }
5733
5734
        return $form->addElement(
5735
            'advmultiselect',
5736
            'users',
5737
            get_lang('Users'),
5738
            $result,
5739
            ['select_all_checkbox' => true]
5740
        );
5741
    }
5742
5743
    /**
5744
     * This function separates the users from the groups
5745
     * users have a value USER:XXX (with XXX the groups id have a value
5746
     *  GROUP:YYY (with YYY the group id).
5747
     *
5748
     * @param array $to Array of strings that define the type and id of each destination
5749
     *
5750
     * @return array Array of groups and users (each an array of IDs)
5751
     */
5752
    public static function separateUsersGroups($to)
5753
    {
5754
        $groupList = [];
5755
        $userList = [];
5756
5757
        foreach ($to as $to_item) {
5758
            if (!empty($to_item)) {
5759
                $parts = explode(':', $to_item);
5760
                $type = isset($parts[0]) ? $parts[0] : '';
5761
                $id = isset($parts[1]) ? $parts[1] : '';
5762
5763
                switch ($type) {
5764
                    case 'GROUP':
5765
                        $groupList[] = (int) $id;
5766
                        break;
5767
                    case 'USER':
5768
                        $userList[] = (int) $id;
5769
                        break;
5770
                }
5771
            }
5772
        }
5773
5774
        $send_to['groups'] = $groupList;
5775
        $send_to['users'] = $userList;
5776
5777
        return $send_to;
5778
    }
5779
5780
    /**
5781
     * Shows the form for sending a message to a specific group or user.
5782
     *
5783
     * @param FormValidator $form
5784
     * @param array         $groupInfo
5785
     * @param array         $to
5786
     *
5787
     * @return HTML_QuickForm_element
5788
     */
5789
    public static function addGroupMultiSelect($form, $groupInfo, $to = [])
5790
    {
5791
        $groupUsers = GroupManager::get_subscribed_users($groupInfo);
5792
        $array = self::buildSelectOptions([$groupInfo], $groupUsers, $to);
5793
5794
        $result = [];
5795
        foreach ($array as $content) {
5796
            $result[$content['value']] = $content['content'];
5797
        }
5798
5799
        return $form->addElement('advmultiselect', 'users', get_lang('Users'), $result);
5800
    }
5801
5802
    /**
5803
     * this function shows the form for sending a message to a specific group or user.
5804
     *
5805
     * @param array $groupList
5806
     * @param array $userList
5807
     * @param array $alreadySelected
5808
     *
5809
     * @return array
5810
     */
5811
    public static function buildSelectOptions(
5812
        $groupList = [],
5813
        $userList = [],
5814
        $alreadySelected = []
5815
    ) {
5816
        if (empty($alreadySelected)) {
5817
            $alreadySelected = [];
5818
        }
5819
5820
        $result = [];
5821
        // adding the groups to the select form
5822
        if ($groupList) {
5823
            foreach ($groupList as $thisGroup) {
5824
                $groupId = $thisGroup['iid'];
5825
                if (is_array($alreadySelected)) {
5826
                    if (!in_array(
5827
                        "GROUP:".$groupId,
5828
                        $alreadySelected
5829
                    )
5830
                    ) {
5831
                        $userCount = isset($thisGroup['userNb']) ? $thisGroup['userNb'] : 0;
5832
                        if (empty($userCount)) {
5833
                            $userCount = isset($thisGroup['count_users']) ? $thisGroup['count_users'] : 0;
5834
                        }
5835
                        // $alreadySelected is the array containing the groups (and users) that are already selected
5836
                        $user_label = ($userCount > 0) ? get_lang('Users') : get_lang('user');
5837
                        $user_disabled = ($userCount > 0) ? "" : "disabled=disabled";
5838
                        $result[] = [
5839
                            'disabled' => $user_disabled,
5840
                            'value' => "GROUP:".$groupId,
5841
                            // The space before "G" is needed in order to advmultiselect.php js puts groups first
5842
                            'content' => " G: ".$thisGroup['name']." - ".$userCount." ".$user_label,
5843
                        ];
5844
                    }
5845
                }
5846
            }
5847
        }
5848
5849
        // adding the individual users to the select form
5850
        if ($userList) {
5851
            foreach ($userList as $user) {
5852
                if (is_array($alreadySelected)) {
5853
                    if (!in_array(
5854
                        "USER:".$user['user_id'],
5855
                        $alreadySelected
5856
                    )
5857
                    ) {
5858
                        // $alreadySelected is the array containing the users (and groups) that are already selected
5859
                        $result[] = [
5860
                            'value' => "USER:".$user['user_id'],
5861
                            'content' => api_get_person_name($user['firstname'], $user['lastname']),
5862
                        ];
5863
                    }
5864
                }
5865
            }
5866
        }
5867
5868
        return $result;
5869
    }
5870
5871
    /**
5872
     * @return array a list (array) of all courses
5873
     */
5874
    public static function get_course_list()
5875
    {
5876
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
5877
5878
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
5879
    }
5880
5881
    /**
5882
     * Returns course code from a given gradebook category's id.
5883
     *
5884
     * @param int  Category ID
5885
     *
5886
     * @return string Course code
5887
     */
5888
    public static function get_course_by_category($category_id)
5889
    {
5890
        $category_id = (int) $category_id;
5891
        $sql = 'SELECT c_id FROM '.Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY).'
5892
                WHERE id='.$category_id;
5893
        $info = Database::fetch_array(Database::query($sql), 'ASSOC');
5894
5895
        return $info ? $info['c_id'] : false;
5896
    }
5897
5898
    /**
5899
     * This function gets all the courses that are not in a session.
5900
     *
5901
     * @param date Start date
5902
     * @param date End date
5903
     * @param bool $includeClosed Whether to include closed and hidden courses
5904
     *
5905
     * @return array Not-in-session courses
5906
     */
5907
    public static function getCoursesWithoutSession(
5908
        $startDate = null,
5909
        $endDate = null,
5910
        $includeClosed = false
5911
    ) {
5912
        $dateConditional = ($startDate && $endDate) ?
5913
            " WHERE session_id IN (SELECT id FROM ".Database::get_main_table(TABLE_MAIN_SESSION).
5914
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" : null;
5915
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
5916
5917
        $sql = "SELECT id, code, title
5918
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
5919
                WHERE $visibility code NOT IN (
5920
                    SELECT DISTINCT course_code 
5921
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE).$dateConditional."
5922
                )
5923
                ORDER BY id";
5924
5925
        $result = Database::query($sql);
5926
        $courses = [];
5927
        while ($row = Database::fetch_array($result)) {
5928
            $courses[] = $row;
5929
        }
5930
5931
        return $courses;
5932
    }
5933
5934
    /**
5935
     * Get list of courses based on users of a group for a group admin.
5936
     *
5937
     * @param int $userId The user id
5938
     *
5939
     * @return array
5940
     */
5941
    public static function getCoursesFollowedByGroupAdmin($userId)
5942
    {
5943
        $coursesList = [];
5944
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5945
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5946
        $userGroup = new UserGroup();
5947
        $userIdList = $userGroup->getGroupUsersByUser($userId);
5948
5949
        if (empty($userIdList)) {
5950
            return [];
5951
        }
5952
5953
        $sql = "SELECT DISTINCT(c.id), c.title
5954
                FROM $courseTable c
5955
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
5956
                WHERE (
5957
                    cru.user_id IN (".implode(', ', $userIdList).")
5958
                    AND cru.relation_type = 0
5959
                )";
5960
5961
        if (api_is_multiple_url_enabled()) {
5962
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5963
            $accessUrlId = api_get_current_access_url_id();
5964
5965
            if ($accessUrlId != -1) {
5966
                $sql = "SELECT DISTINCT(c.id), c.title
5967
                        FROM $courseTable c
5968
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
5969
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
5970
                        WHERE crau.access_url_id = $accessUrlId
5971
                            AND (
5972
                            cru.id_user IN (".implode(', ', $userIdList).") AND
5973
                            cru.relation_type = 0
5974
                        )";
5975
            }
5976
        }
5977
5978
        $result = Database::query($sql);
5979
        while ($row = Database::fetch_assoc($result)) {
5980
            $coursesList[] = $row;
5981
        }
5982
5983
        return $coursesList;
5984
    }
5985
5986
    /**
5987
     * Direct course link see #5299.
5988
     *
5989
     * You can send to your students an URL like this
5990
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
5991
     * Where "c" is the course code and "e" is the exercise Id, after a successful
5992
     * registration the user will be sent to the course or exercise
5993
     *
5994
     * @param array $form_data
5995
     *
5996
     * @return array
5997
     */
5998
    public static function redirectToCourse($form_data)
5999
    {
6000
        $course_code_redirect = Session::read('course_redirect');
6001
        $_user = api_get_user_info();
6002
        $userId = api_get_user_id();
6003
6004
        if (!empty($course_code_redirect)) {
6005
            $course_info = api_get_course_info($course_code_redirect);
6006
            if (!empty($course_info)) {
6007
                if (in_array(
6008
                    $course_info['visibility'],
6009
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
6010
                )
6011
                ) {
6012
                    if (self::is_user_subscribed_in_course($userId, $course_info['code'])) {
6013
                        $form_data['action'] = $course_info['course_public_url'];
6014
                        $form_data['message'] = sprintf(get_lang('You have been registered to course %s'), $course_info['title']);
6015
                        $form_data['button'] = Display::button(
6016
                            'next',
6017
                            get_lang('Go to the course', null, $_user['language']),
6018
                            ['class' => 'btn btn-primary btn-large']
6019
                        );
6020
6021
                        $exercise_redirect = intval(Session::read('exercise_redirect'));
6022
                        // Specify the course id as the current context does not
6023
                        // hold a global $_course array
6024
                        $objExercise = new Exercise($course_info['real_id']);
6025
                        $result = $objExercise->read($exercise_redirect);
6026
6027
                        if (!empty($exercise_redirect) && !empty($result)) {
6028
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).
6029
                                'exercise/overview.php?exerciseId='.$exercise_redirect.'&cidReq='.$course_info['code'];
6030
                            $form_data['message'] .= '<br />'.get_lang('Go to the test');
6031
                            $form_data['button'] = Display::button(
6032
                                'next',
6033
                                get_lang('Go', null, $_user['language']),
6034
                                ['class' => 'btn btn-primary btn-large']
6035
                            );
6036
                        }
6037
6038
                        if (!empty($form_data['action'])) {
6039
                            header('Location: '.$form_data['action']);
6040
                            exit;
6041
                        }
6042
                    }
6043
                }
6044
            }
6045
        }
6046
6047
        return $form_data;
6048
    }
6049
6050
    /**
6051
     * Return tab of params to display a course title in the My Courses tab
6052
     * Check visibility, right, and notification icons, and load_dirs option
6053
     * get html course params.
6054
     *
6055
     * @param $courseId
6056
     * @param bool $loadDirs
6057
     *
6058
     * @return array with keys ['right_actions'] ['teachers'] ['notifications']
6059
     */
6060
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
6061
    {
6062
        $userId = api_get_user_id();
6063
        $courseId = intval($courseId);
6064
        // Table definitions
6065
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
6066
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6067
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6068
        $current_url_id = api_get_current_access_url_id();
6069
6070
        // Get course list auto-register
6071
        $special_course_list = self::get_special_course_list();
6072
6073
        $without_special_courses = '';
6074
        if (!empty($special_course_list)) {
6075
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
6076
        }
6077
6078
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
6079
        $sql = "SELECT 
6080
                    course.id, 
6081
                    course.title, 
6082
                    course.code, 
6083
                    course.subscribe subscr, 
6084
                    course.unsubscribe unsubscr, 
6085
                    course_rel_user.status status,
6086
                    course_rel_user.sort sort, 
6087
                    course_rel_user.user_course_cat user_course_cat
6088
                FROM
6089
                $TABLECOURS course 
6090
                INNER JOIN $TABLECOURSUSER course_rel_user                
6091
                ON (course.id = course_rel_user.c_id)
6092
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
6093
                ON (url.c_id = course.id)
6094
                WHERE
6095
                    course.id = $courseId AND
6096
                    course_rel_user.user_id = $userId
6097
                    $without_special_courses
6098
                ";
6099
6100
        // If multiple URL access mode is enabled, only fetch courses
6101
        // corresponding to the current URL.
6102
        if (api_get_multiple_access_url() && $current_url_id != -1) {
6103
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id";
6104
        }
6105
        // Use user's classification for courses (if any).
6106
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
6107
6108
        $result = Database::query($sql);
6109
6110
        // Browse through all courses. We can only have one course because
6111
        // of the  course.id=".intval($courseId) in sql query
6112
        $course = Database::fetch_array($result);
6113
        $course_info = api_get_course_info_by_id($courseId);
6114
        if (empty($course_info)) {
6115
            return '';
6116
        }
6117
6118
        //$course['id_session'] = null;
6119
        $course_info['id_session'] = null;
6120
        $course_info['status'] = $course['status'];
6121
6122
        // For each course, get if there is any notification icon to show
6123
        // (something that would have changed since the user's last visit).
6124
        $show_notification = !api_get_configuration_value('hide_course_notification')
6125
            ? Display::show_notification($course_info)
6126
            : '';
6127
6128
        // New code displaying the user's status in respect to this course.
6129
        $status_icon = Display::return_icon(
6130
            'blackboard.png',
6131
            $course_info['title'],
6132
            [],
6133
            ICON_SIZE_LARGE
6134
        );
6135
6136
        $params = [];
6137
        $params['right_actions'] = '';
6138
6139
        if (api_is_platform_admin()) {
6140
            if ($loadDirs) {
6141
                $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6142
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.
6143
                    Display::return_icon('edit.png', get_lang('Edit'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).
6144
                    '</a>';
6145
                $params['right_actions'] .= Display::div(
6146
                    '',
6147
                    [
6148
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
6149
                        'class' => 'document_preview_container',
6150
                    ]
6151
                );
6152
            } else {
6153
                $params['right_actions'] .= '<a class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.
6154
                    Display::returnFontAwesomeIcon('pencil').'</a>';
6155
            }
6156
        } else {
6157
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
6158
                if ($loadDirs) {
6159
                    $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.
6160
                        Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6161
                    $params['right_actions'] .= Display::div(
6162
                        '',
6163
                        [
6164
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
6165
                            'class' => 'document_preview_container',
6166
                        ]
6167
                    );
6168
                } else {
6169
                    if ($course_info['status'] == COURSEMANAGER) {
6170
                        $params['right_actions'] .= '<a class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.
6171
                            Display::returnFontAwesomeIcon('pencil').'</a>';
6172
                    }
6173
                }
6174
            }
6175
        }
6176
6177
        $course_title_url = '';
6178
        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED || $course['status'] == COURSEMANAGER) {
6179
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
6180
            $course_title = Display::url($course_info['title'], $course_title_url);
6181
        } else {
6182
            $course_title = $course_info['title'].' '.Display::tag(
6183
                'span',
6184
                get_lang('(the course is currently closed)'),
6185
                ['class' => 'item_closed']
6186
            );
6187
        }
6188
6189
        // Start displaying the course block itself
6190
        if (api_get_setting('display_coursecode_in_courselist') === 'true') {
6191
            $course_title .= ' ('.$course_info['visual_code'].') ';
6192
        }
6193
        $teachers = '';
6194
        if (api_get_setting('display_teacher_in_courselist') === 'true') {
6195
            $teachers = self::getTeacherListFromCourseCodeToString(
6196
                $course['code'],
6197
                self::USER_SEPARATOR,
6198
                true
6199
            );
6200
        }
6201
        $params['link'] = $course_title_url;
6202
        $params['icon'] = $status_icon;
6203
        $params['title'] = $course_title;
6204
        $params['teachers'] = $teachers;
6205
        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
6206
            $params['notifications'] = $show_notification;
6207
        }
6208
6209
        return $params;
6210
    }
6211
6212
    /**
6213
     * Get the course id based on the original id and field name in the extra fields.
6214
     * Returns 0 if course was not found.
6215
     *
6216
     * @param string $original_course_id_value Original course id
6217
     * @param string $original_course_id_name  Original field name
6218
     *
6219
     * @return int Course id
6220
     */
6221
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
6222
    {
6223
        $extraFieldValue = new ExtraFieldValue('course');
6224
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
6225
            $original_course_id_name,
6226
            $original_course_id_value
6227
        );
6228
6229
        if ($value) {
6230
            return $value['item_id'];
6231
        }
6232
6233
        return 0;
6234
    }
6235
6236
    /**
6237
     * Helper function to create a default gradebook (if necessary) upon course creation.
6238
     *
6239
     * @param int    $modelId    The gradebook model ID
6240
     * @param string $courseCode Course code
6241
     */
6242
    public static function createDefaultGradebook($modelId, $courseCode)
6243
    {
6244
        if (api_get_setting('gradebook_enable_grade_model') === 'true') {
6245
            //Create gradebook_category for the new course and add
6246
            // a gradebook model for the course
6247
            if (isset($modelId) &&
6248
                !empty($modelId) &&
6249
                $modelId != '-1'
6250
            ) {
6251
                GradebookUtils::create_default_course_gradebook(
6252
                    $courseCode,
6253
                    $modelId
6254
                );
6255
            }
6256
        }
6257
    }
6258
6259
    /**
6260
     * Helper function to check if there is a course template and, if so, to
6261
     * copy the template as basis for the new course.
6262
     *
6263
     * @param string $courseCode     Course code
6264
     * @param int    $courseTemplate 0 if no course template is defined
6265
     */
6266
    public static function useTemplateAsBasisIfRequired($courseCode, $courseTemplate)
6267
    {
6268
        $template = api_get_setting('course_creation_use_template');
6269
        $teacherCanSelectCourseTemplate = api_get_setting('teacher_can_select_course_template') === 'true';
6270
        $courseTemplate = isset($courseTemplate) ? intval($courseTemplate) : 0;
6271
6272
        $useTemplate = false;
6273
6274
        if ($teacherCanSelectCourseTemplate && $courseTemplate) {
6275
            $useTemplate = true;
6276
            $originCourse = api_get_course_info_by_id($courseTemplate);
6277
        } elseif (!empty($template)) {
6278
            $useTemplate = true;
6279
            $originCourse = api_get_course_info_by_id($template);
6280
        }
6281
6282
        if ($useTemplate) {
6283
            // Include the necessary libraries to generate a course copy
6284
            // Call the course copy object
6285
            $originCourse['official_code'] = $originCourse['code'];
6286
            $cb = new CourseBuilder(null, $originCourse);
6287
            $course = $cb->build(null, $originCourse['code']);
6288
            $cr = new CourseRestorer($course);
6289
            $cr->set_file_option();
6290
            $cr->restore($courseCode);
6291
        }
6292
    }
6293
6294
    /**
6295
     * Helper method to get the number of users defined with a specific course extra field.
6296
     *
6297
     * @param string $name                 Field title
6298
     * @param string $tableExtraFields     The extra fields table name
6299
     * @param string $tableUserFieldValues The user extra field value table name
6300
     *
6301
     * @return int The number of users with this extra field with a specific value
6302
     */
6303
    public static function getCountRegisteredUsersWithCourseExtraField(
6304
        $name,
6305
        $tableExtraFields = '',
6306
        $tableUserFieldValues = ''
6307
    ) {
6308
        if (empty($tableExtraFields)) {
6309
            $tableExtraFields = Database::get_main_table(TABLE_EXTRA_FIELD);
6310
        }
6311
        if (empty($tableUserFieldValues)) {
6312
            $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6313
        }
6314
6315
        $registered_users_with_extra_field = 0;
6316
        if (!empty($name) && $name != '-') {
6317
            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
6318
            $name = Database::escape_string($name);
6319
            $sql = "SELECT count(v.item_id) as count
6320
                    FROM $tableUserFieldValues v 
6321
                    INNER JOIN $tableExtraFields f
6322
                    ON (f.id = v.field_id)
6323
                    WHERE value = '$name' AND extra_field_type = $extraFieldType";
6324
            $result_count = Database::query($sql);
6325
            if (Database::num_rows($result_count)) {
6326
                $row_count = Database::fetch_array($result_count);
6327
                $registered_users_with_extra_field = $row_count['count'];
6328
            }
6329
        }
6330
6331
        return $registered_users_with_extra_field;
6332
    }
6333
6334
    /**
6335
     * Get the course categories form a course list.
6336
     *
6337
     * @param array $courseList
6338
     *
6339
     * @return array
6340
     */
6341
    public static function getCourseCategoriesFromCourseList(array $courseList)
6342
    {
6343
        $allCategories = array_column($courseList, 'category');
6344
        $categories = array_unique($allCategories);
6345
6346
        sort($categories);
6347
6348
        return $categories;
6349
    }
6350
6351
    /**
6352
     * Display the description button of a course in the course catalog.
6353
     *
6354
     * @param array $course
6355
     *
6356
     * @return string HTML string
6357
     */
6358
    public static function returnDescriptionButton($course)
6359
    {
6360
        if (empty($course)) {
6361
            return '';
6362
        }
6363
6364
        if (api_get_setting('show_courses_descriptions_in_catalog') == 'true') {
6365
            $title = $course['title'];
6366
            $url = api_get_path(WEB_CODE_PATH).'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
6367
            $html = Display::url(
6368
                Display::returnFontAwesomeIcon('info-circle', 'lg'),
6369
                $url,
6370
                [
6371
                    'class' => 'ajax btn btn-light btn-sm',
6372
                    'data-title' => $title,
6373
                    'title' => get_lang('Description'),
6374
                    'aria-label' => get_lang('Description'),
6375
                    'data-size' => 'lg',
6376
                ]
6377
            );
6378
6379
            return $html;
6380
        }
6381
6382
        return '';
6383
    }
6384
6385
    /**
6386
     * @param Course $course
6387
     *
6388
     * @return bool
6389
     */
6390
    public static function hasPicture(Course $course)
6391
    {
6392
        return file_exists(api_get_path(SYS_COURSE_PATH).$course->getDirectory().'/course-pic85x85.png');
6393
    }
6394
6395
    /**
6396
     * Get the course picture path.
6397
     *
6398
     * @param Course $course
6399
     * @param bool   $fullSize
6400
     *
6401
     * @return string|null
6402
     */
6403
    public static function getPicturePath(Course $course, $fullSize = false)
6404
    {
6405
        if (!self::hasPicture($course)) {
6406
            return null;
6407
        }
6408
6409
        if ($fullSize) {
6410
            return api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic.png';
6411
        }
6412
6413
        return api_get_path(WEB_COURSE_PATH).$course->getDirectory().'/course-pic85x85.png';
6414
    }
6415
6416
    /**
6417
     * @return int
6418
     */
6419
    public static function getCountOpenCourses()
6420
    {
6421
        $visibility = [
6422
            COURSE_VISIBILITY_REGISTERED,
6423
            COURSE_VISIBILITY_OPEN_PLATFORM,
6424
            COURSE_VISIBILITY_OPEN_WORLD,
6425
        ];
6426
6427
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6428
        $sql = "SELECT count(id) count 
6429
                FROM $table 
6430
                WHERE visibility IN (".implode(',', $visibility).")";
6431
        $result = Database::query($sql);
6432
        $row = Database::fetch_array($result);
6433
6434
        return (int) $row['count'];
6435
    }
6436
6437
    /**
6438
     * @return int
6439
     */
6440
    public static function getCountExercisesFromOpenCourse()
6441
    {
6442
        $visibility = [
6443
            COURSE_VISIBILITY_REGISTERED,
6444
            COURSE_VISIBILITY_OPEN_PLATFORM,
6445
            COURSE_VISIBILITY_OPEN_WORLD,
6446
        ];
6447
6448
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6449
        $tableExercise = Database::get_course_table(TABLE_QUIZ_TEST);
6450
        $sql = "SELECT count(e.iid) count 
6451
                FROM $table c INNER JOIN $tableExercise e
6452
                ON (c.id = e.c_id)
6453
                WHERE e.active <> -1 AND visibility IN (".implode(',', $visibility).")";
6454
        $result = Database::query($sql);
6455
        $row = Database::fetch_array($result);
6456
6457
        return (int) $row['count'];
6458
    }
6459
6460
    /**
6461
     * @param ToolChain $toolList
6462
     */
6463
    public static function setToolList($toolList)
6464
    {
6465
        self::$toolList = $toolList;
6466
    }
6467
6468
    /**
6469
     * @return ToolChain
6470
     */
6471
    public static function getToolList()
6472
    {
6473
        return self::$toolList;
6474
    }
6475
6476
    /**
6477
     * Check if a specific access-url-related setting is a problem or not.
6478
     *
6479
     * @param array  $_configuration The $_configuration array
6480
     * @param int    $accessUrlId    The access URL ID
6481
     * @param string $param
6482
     * @param string $msgLabel
6483
     *
6484
     * @return bool|string
6485
     */
6486
    private static function checkCreateCourseAccessUrlParam($_configuration, $accessUrlId, $param, $msgLabel)
6487
    {
6488
        if (isset($_configuration[$accessUrlId][$param]) && $_configuration[$accessUrlId][$param] > 0) {
6489
            $num = self::count_courses($accessUrlId);
6490
            if ($num >= $_configuration[$accessUrlId][$param]) {
6491
                api_warn_hosting_contact($param);
6492
6493
                Display::addFlash(
6494
                    Display::return_message($msgLabel)
6495
                );
6496
            }
6497
        }
6498
6499
        return false;
6500
    }
6501
6502
    /**
6503
     * Fill course with all necessary items.
6504
     *
6505
     * @param array $courseInfo Course info array
6506
     * @param array $params     Parameters from the course creation form
6507
     * @param int   $authorId
6508
     */
6509
    private static function fillCourse($courseInfo, $params, $authorId = 0)
6510
    {
6511
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
6512
6513
        AddCourse::prepare_course_repository($courseInfo['directory']);
6514
        AddCourse::fillCourse(
6515
            $courseInfo,
6516
            $params['exemplary_content'],
6517
            $authorId
6518
        );
6519
6520
        if (isset($params['gradebook_model_id'])) {
6521
            self::createDefaultGradebook(
6522
                $params['gradebook_model_id'],
6523
                $courseInfo['code']
6524
            );
6525
        }
6526
6527
        // If parameter defined, copy the contents from a specific
6528
        // template course into this new course
6529
        if (isset($params['course_template'])) {
6530
            self::useTemplateAsBasisIfRequired(
6531
                $courseInfo['id'],
6532
                $params['course_template']
6533
            );
6534
        }
6535
        $params['course_code'] = $courseInfo['code'];
6536
        $params['item_id'] = $courseInfo['real_id'];
6537
6538
        $courseFieldValue = new ExtraFieldValue('course');
6539
        $courseFieldValue->saveFieldValues($params);
6540
    }
6541
}
6542