Passed
Push — 1.11.x ( a83aa6...c231b6 )
by Julito
14:28
created

CourseManager::get_access_link_by_user()   D

Complexity

Conditions 35
Paths 69

Size

Total Lines 63
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 35
eloc 35
nc 69
nop 3
dl 0
loc 63
rs 4.1666
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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