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

CourseManager::delete_course()   C

Complexity

Conditions 14
Paths 101

Size

Total Lines 184
Code Lines 119

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 14
eloc 119
c 0
b 0
f 0
nc 101
nop 1
dl 0
loc 184
rs 5.0066

How to fix   Long Method    Complexity   

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:

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