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