Passed
Push — master ( 70e393...45daf5 )
by Julito
09:50
created

CourseManager::get_courses_list()   F

Complexity

Conditions 22
Paths 6912

Size

Total Lines 108
Code Lines 65

Duplication

Lines 0
Ratio 0 %

Importance

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