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