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

CourseManager::get_courses_list()   F

Complexity

Conditions 22
Paths 6912

Size

Total Lines 110
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 22
eloc 67
c 0
b 0
f 0
nc 6912
nop 10
dl 0
loc 110
rs 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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