Passed
Push — master ( f437d8...92f70a )
by Julito
10:14
created

CourseManager::get_courses_list()   F

Complexity

Conditions 22
Paths 6912

Size

Total Lines 110
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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