Passed
Push — ofaj ( 0f9380...ade756 )
by
unknown
12:01 queued 12s
created

CourseManager::get_courses_list()   F

Complexity

Conditions 23
Paths 10368

Size

Total Lines 115
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

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