Completed
Push — master ( a8dd9d...76a038 )
by Julito
11:51
created

CourseManager   F

Complexity

Total Complexity 837

Size/Duplication

Total Lines 7023
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 3440
dl 0
loc 7023
rs 0.8
c 0
b 0
f 0
wmc 837

121 Methods

Rating   Name   Duplication   Size   Complexity  
A getEntityManager() 0 3 1
A setEntityManager() 0 3 1
A getManager() 0 3 1
A getCourseSettingsManager() 0 3 1
A setCourseSettingsManager() 0 3 1
A is_course_teacher() 0 20 4
C update_course_ranking() 0 67 14
A getCourseListTabs() 0 24 3
A get_teacher_list_from_course_code() 0 28 3
A get_course_id_from_original_id() 0 13 2
A get_courses_followed_by_drh() 0 17 1
A getCountForum() 0 21 2
B redirectToCourse() 0 50 8
B is_user_subscribed_in_real_or_linked_course() 0 57 6
F getCourseParamsForDisplay() 0 152 16
A countActiveCourses() 0 19 2
B addUserGroupMultiSelect() 0 60 7
A getCoursesByUserCourseCategory() 0 50 2
F get_logged_user_course_html() 0 260 45
A get_course_code_from_original_id() 0 25 2
A generate_nice_next_course_code() 0 25 4
A isSpecialCourse() 0 15 3
A setToolList() 0 3 1
A getCourseVisibilitySQLCondition() 0 31 5
A getToolList() 0 3 1
B userCourseSort() 0 83 10
A update_course_extra_field_value() 0 13 1
F get_student_list_from_course_code() 0 114 20
A removeUserVisibilityToCourseInCatalogue() 0 33 5
A addGroupMultiSelect() 0 11 2
A getCountForumPerUser() 0 25 1
A get_course_information() 0 8 1
F get_user_list_from_course_code() 0 404 66
B subscribeCoursesToDrhManager() 0 48 7
A count_courses() 0 23 5
A get_session_category_id_by_session_id() 0 16 2
A remove_course_ranking() 0 14 4
A get_course_category() 0 7 1
B returnCourses() 0 73 8
B getTeacherListFromCourseCodeToString() 0 46 7
A copy_course() 0 25 2
F get_courses_list() 0 113 22
A getCourseUsers() 0 16 1
A fillCourse() 0 30 4
B get_details_course_description_html() 0 43 6
A copy_course_simple() 0 32 5
B get_course_list_of_user_as_course_admin() 0 67 7
A email_to_tutor() 0 68 4
A getCountOpenCourses() 0 16 1
A get_user_course_categories() 0 15 3
B returnPopularCoursesHandPicked() 0 63 8
A isUserSubscribedInCourseAsDrh() 0 26 5
C is_user_subscribed_in_course() 0 88 14
A getUserCourseCategoryForCourse() 0 22 2
D get_access_link_by_user() 0 65 35
A getCourseInfoFromOriginalId() 0 15 2
A getCountExercisesFromOpenCourse() 0 19 1
C autoSubscribeToCourse() 0 143 15
A get_tutor_in_course_status() 0 15 1
C buildSelectOptions() 0 58 15
F getCoursesFollowedByUser() 0 107 14
A getCourseGroups() 0 18 2
B separateUsersGroups() 0 26 7
F returnCoursesCategories() 0 201 29
A getCourseCategoriesFromCourseList() 0 8 1
A course_exists() 0 7 1
A save_user_legal() 0 33 4
A generate_course_code() 0 6 1
B checkCreateCourseAccessUrlParam() 0 25 7
D delete_course() 0 208 15
A getCoursesWithoutSession() 0 25 5
A get_course_code_from_course_id() 0 11 2
A getCountPostInForumPerUser() 0 25 1
A get_user_course_vote() 0 33 5
A createDefaultGradebook() 0 12 5
A totalSubscribedUsersInCourses() 0 23 1
A getUserInCourseStatus() 0 22 3
A getFirstCourseAccessPerSessionAndUser() 0 18 2
A get_courses_info_from_visual_code() 0 10 2
A getCourseSetting() 0 10 1
A getCourseAccessPerCourseAndSession() 0 22 1
B get_special_course_list() 0 55 8
A getCourseCodeFromDirectory() 0 14 3
B is_user_accepted_legal() 0 45 7
B saveSettingChanges() 0 30 7
A get_course_extra_field_value() 0 12 2
A getCourseNameFromCode() 0 10 2
A create_course_extra_field() 0 11 1
B addUserVisibilityToCourseInCatalogue() 0 50 8
A get_course_ranking() 0 45 5
A useTemplateAsBasisIfRequired() 0 25 6
B return_hot_courses() 0 55 6
B create_database_dump() 0 36 7
D get_courses_list_by_user_id() 0 146 21
F updateTeachers() 0 138 28
A update_attributes() 0 18 4
B getExtraFieldsToBePresented() 0 17 7
B get_coachs_from_course_to_string() 0 49 7
A get_count_user_list_from_course_code() 0 24 1
B get_coach_list_from_course_code() 0 41 8
A get_course_list() 0 5 1
A updateUserCourseTutor() 0 19 2
A getCoursesFollowedByGroupAdmin() 0 43 5
A course_code_exists() 0 9 1
F unsubscribe_user() 0 177 23
A get_course_by_category() 0 8 2
F subscribeUser() 0 187 23
B add_course_vote() 0 69 9
A getCourseSettingVariables() 0 64 4
C processHotCourseItem() 0 109 15
A getUserCourseInfo() 0 8 1
A get_coachs_from_course() 0 40 5
A saveCourseConfigurationSetting() 0 51 5
C create_course() 0 65 15
D returnSpecialCourses() 0 123 18
B get_group_list_of_course() 0 41 6
A get_users_count_in_course() 0 59 5
B getCatalogCourseList() 0 43 7
A getCountRegisteredUsersWithCourseExtraField() 0 29 6
A getTeachersFromCourse() 0 43 3
A returnDescriptionButton() 0 33 5

How to fix   Complexity   

Complex Class

Complex classes like CourseManager often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CourseManager, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* For licensing terms, see /license.txt*/
4
5
use Chamilo\CoreBundle\Entity\Course;
6
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
7
use Chamilo\CoreBundle\Entity\SequenceResource;
8
use Chamilo\CoreBundle\Framework\Container;
9
use Chamilo\CoreBundle\Repository\CourseRepository;
10
use Chamilo\CoreBundle\Repository\SequenceResourceRepository;
11
use Chamilo\CoreBundle\ToolChain;
12
use Chamilo\CourseBundle\Component\CourseCopy\CourseBuilder;
13
use Chamilo\CourseBundle\Component\CourseCopy\CourseRestorer;
14
use Chamilo\CourseBundle\Manager\SettingsManager;
15
use ChamiloSession as Session;
16
use Doctrine\ORM\EntityManager;
17
18
/**
19
 * Class CourseManager.
20
 *
21
 * This is the course library for Chamilo.
22
 *
23
 * All main course functions should be placed here.
24
 *
25
 * There are probably some places left with the wrong code.
26
 */
27
class CourseManager
28
{
29
    public 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
    public const USER_SEPARATOR = ' |';
33
    public $columns = [];
34
    public static $em;
35
    public static $toolList;
36
    public static $courseSettingsManager;
37
    private static $manager;
38
39
    /**
40
     * @param EntityManager
41
     */
42
    public static function setEntityManager($em)
43
    {
44
        self::$em = $em;
45
    }
46
47
    /**
48
     * @return EntityManager
49
     */
50
    public static function getEntityManager()
51
    {
52
        return self::$em;
53
    }
54
55
    /**
56
     * @return SettingsManager
57
     */
58
    public static function getCourseSettingsManager()
59
    {
60
        return self::$courseSettingsManager;
61
    }
62
63
    /**
64
     * @param SettingsManager $courseSettingsManager
65
     */
66
    public static function setCourseSettingsManager($courseSettingsManager)
67
    {
68
        self::$courseSettingsManager = $courseSettingsManager;
69
    }
70
71
    /**
72
     * @deprecated
73
     *
74
     * @return CourseRepository
75
     */
76
    public static function getManager()
77
    {
78
        return Container::getCourseRepository();
79
    }
80
81
    /**
82
     * Creates a course.
83
     *
84
     * @param array $params      Columns in the main.course table.
85
     * @param int   $authorId    Optional.
86
     * @param int   $accessUrlId Optional.
87
     *
88
     * @return mixed false if the course was not created, array with the course info
89
     */
90
    public static function create_course($params, $authorId = 0, $accessUrlId = 0)
91
    {
92
        global $_configuration;
93
94
        // Check portal limits
95
        $accessUrlId = !empty($accessUrlId) ? (int) $accessUrlId : api_get_current_access_url_id();
96
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
97
98
        if (isset($_configuration[$accessUrlId]) && is_array($_configuration[$accessUrlId])) {
99
            $return = self::checkCreateCourseAccessUrlParam(
100
                $_configuration,
101
                $accessUrlId,
102
                'hosting_limit_courses',
103
                'PortalCoursesLimitReached'
104
            );
105
            if (false != $return) {
106
                return $return;
107
            }
108
            $return = self::checkCreateCourseAccessUrlParam(
109
                $_configuration,
110
                $accessUrlId,
111
                'hosting_limit_active_courses',
112
                'PortalActiveCoursesLimitReached'
113
            );
114
            if (false != $return) {
115
                return $return;
116
            }
117
        }
118
119
        if (empty($params['title'])) {
120
            return false;
121
        }
122
123
        if (empty($params['wanted_code'])) {
124
            $params['wanted_code'] = $params['title'];
125
            // Check whether the requested course code has already been occupied.
126
            $substring = api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE);
127
            if (false === $substring || empty($substring)) {
128
                return false;
129
            } else {
130
                $params['wanted_code'] = self::generate_course_code($substring);
131
            }
132
        }
133
134
        // Create the course keys
135
        $keys = AddCourse::define_course_keys($params['wanted_code']);
136
        $params['exemplary_content'] = isset($params['exemplary_content']) ? $params['exemplary_content'] : false;
137
138
        if (count($keys)) {
139
            $params['code'] = $keys['currentCourseCode'];
140
            $params['visual_code'] = $keys['currentCourseId'];
141
            $params['directory'] = $keys['currentCourseRepository'];
142
            $courseInfo = api_get_course_info($params['code']);
143
            if (empty($courseInfo)) {
144
                $courseId = AddCourse::register_course($params, $accessUrlId);
145
                $courseInfo = api_get_course_info_by_id($courseId);
146
                if (!empty($courseInfo)) {
147
                    self::fillCourse($courseInfo, $params, $authorId);
148
149
                    return $courseInfo;
150
                }
151
            }
152
        }
153
154
        return false;
155
    }
156
157
    /**
158
     * Returns all the information of a given course code.
159
     *
160
     * @param string $course_code , the course code
161
     *
162
     * @return array with all the fields of the course table
163
     *
164
     * @deprecated Use api_get_course_info() instead
165
     *
166
     * @author Patrick Cool <[email protected]>, Ghent University
167
     * @assert ('') === false
168
     */
169
    public static function get_course_information($course_code)
170
    {
171
        return Database::fetch_array(
172
            Database::query(
173
                "SELECT *, id as real_id FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
174
                WHERE code = '".Database::escape_string($course_code)."'"
175
            ),
176
            'ASSOC'
177
        );
178
    }
179
180
    /**
181
     * Returns a list of courses. Should work with quickform syntax.
182
     *
183
     * @param int    $from               Offset (from the 7th = '6'). Optional.
184
     * @param int    $howmany            Number of results we want. Optional.
185
     * @param int    $orderby            The column we want to order it by. Optional, defaults to first column.
186
     * @param string $orderdirection     The direction of the order (ASC or DESC). Optional, defaults to ASC.
187
     * @param int    $visibility         the visibility of the course, or all by default
188
     * @param string $startwith          If defined, only return results for which the course *title* begins with this string
189
     * @param string $urlId              The Access URL ID, if using multiple URLs
190
     * @param bool   $alsoSearchCode     An extension option to indicate that we also want to search for course codes (not *only* titles)
191
     * @param array  $conditionsLike
192
     * @param array  $onlyThisCourseList
193
     *
194
     * @return array
195
     */
196
    public static function get_courses_list(
197
        $from = 0,
198
        $howmany = 0,
199
        $orderby = 1,
200
        $orderdirection = 'ASC',
201
        $visibility = -1,
202
        $startwith = '',
203
        $urlId = null,
204
        $alsoSearchCode = false,
205
        $conditionsLike = [],
206
        $onlyThisCourseList = []
207
    ) {
208
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
209
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
210
        $sql = "SELECT course.*, course.id as real_id, course_category.code AS category_code
211
                FROM $courseTable course  ";
212
213
        if (!empty($urlId)) {
214
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
215
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
216
        }
217
218
        $sql .= " LEFT JOIN $tblCourseCategory ON course.category_id = course_category.id ";
219
220
        $visibility = (int) $visibility;
221
222
        if (!empty($startwith)) {
223
            $sql .= "WHERE (title LIKE '".Database::escape_string($startwith)."%' ";
224
            if ($alsoSearchCode) {
225
                $sql .= "OR code LIKE '".Database::escape_string($startwith)."%' ";
226
            }
227
            $sql .= ') ';
228
            if (-1 !== $visibility) {
229
                $sql .= " AND visibility = $visibility ";
230
            }
231
        } else {
232
            $sql .= 'WHERE 1 ';
233
            if (-1 !== $visibility) {
234
                $sql .= " AND visibility = $visibility ";
235
            }
236
        }
237
238
        if (!empty($urlId)) {
239
            $urlId = (int) $urlId;
240
            $sql .= " AND access_url_id = $urlId";
241
        }
242
243
        if (!empty($onlyThisCourseList)) {
244
            $onlyThisCourseList = array_map('intval', $onlyThisCourseList);
245
            $onlyThisCourseList = implode("','", $onlyThisCourseList);
246
            $sql .= " AND course.id IN ('$onlyThisCourseList') ";
247
        }
248
249
        $allowedFields = [
250
            'title',
251
            'code',
252
        ];
253
254
        if (count($conditionsLike) > 0) {
255
            $sql .= ' AND ';
256
            $temp_conditions = [];
257
            foreach ($conditionsLike as $field => $value) {
258
                if (!in_array($field, $allowedFields)) {
259
                    continue;
260
                }
261
                $field = Database::escape_string($field);
262
                $value = Database::escape_string($value);
263
                $simple_like = false;
264
                if ($simple_like) {
265
                    $temp_conditions[] = $field." LIKE '$value%'";
266
                } else {
267
                    $temp_conditions[] = $field.' LIKE \'%'.$value.'%\'';
268
                }
269
            }
270
            $condition = ' AND ';
271
            if (!empty($temp_conditions)) {
272
                $sql .= implode(' '.$condition.' ', $temp_conditions);
273
            }
274
        }
275
276
        if (!empty($orderby)) {
277
            $sql .= " ORDER BY ".Database::escape_string($orderby)." ";
278
        } else {
279
            $sql .= ' ORDER BY 1 ';
280
        }
281
282
        if (!in_array($orderdirection, ['ASC', 'DESC'])) {
283
            $sql .= 'ASC';
284
        } else {
285
            $sql .= ('ASC' == $orderdirection ? 'ASC' : 'DESC');
286
        }
287
288
        if (!empty($howmany) && is_int($howmany) and $howmany > 0) {
289
            $sql .= ' LIMIT '.Database::escape_string($howmany);
290
        } else {
291
            $sql .= ' LIMIT 1000000'; //virtually no limit
292
        }
293
        if (!empty($from)) {
294
            $from = intval($from);
295
            $sql .= ' OFFSET '.intval($from);
296
        } else {
297
            $sql .= ' OFFSET 0';
298
        }
299
300
        $data = [];
301
        $res = Database::query($sql);
302
        if (Database::num_rows($res) > 0) {
303
            while ($row = Database::fetch_array($res, 'ASSOC')) {
304
                $data[] = $row;
305
            }
306
        }
307
308
        return $data;
309
    }
310
311
    /**
312
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
313
     *
314
     * @param int $userId
315
     * @param int $courseId
316
     *
317
     * @return int|bool the status of the user in that course (or false if the user is not in that course)
318
     */
319
    public static function getUserInCourseStatus($userId, $courseId)
320
    {
321
        $courseId = (int) $courseId;
322
        $userId = (int) $userId;
323
        if (empty($courseId)) {
324
            return false;
325
        }
326
327
        $result = Database::fetch_array(
328
            Database::query(
329
                "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
330
                WHERE
331
                    c_id  = $courseId AND
332
                    user_id = $userId"
333
            )
334
        );
335
336
        if (empty($result['status'])) {
337
            return false;
338
        }
339
340
        return $result['status'];
341
    }
342
343
    /**
344
     * @param int $userId
345
     * @param int $courseId
346
     *
347
     * @return mixed
348
     */
349
    public static function getUserCourseInfo($userId, $courseId)
350
    {
351
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
352
                WHERE
353
                    c_id  = ".intval($courseId)." AND
354
                    user_id = ".intval($userId);
355
356
        return Database::fetch_array(Database::query($sql));
357
    }
358
359
    /**
360
     * @param int  $userId
361
     * @param int  $courseId
362
     * @param bool $isTutor
363
     *
364
     * @return bool
365
     */
366
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
367
    {
368
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
369
370
        $courseId = (int) $courseId;
371
        $isTutor = (int) $isTutor;
372
373
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
374
			    WHERE
375
				    user_id = ".$userId." AND
376
				    c_id = ".$courseId;
377
378
        $result = Database::query($sql);
379
380
        if (Database::affected_rows($result) > 0) {
381
            return true;
382
        }
383
384
        return false;
385
    }
386
387
    /**
388
     * @param int $userId
389
     * @param int $courseId
390
     *
391
     * @return mixed
392
     */
393
    public static function get_tutor_in_course_status($userId, $courseId)
394
    {
395
        $userId = intval($userId);
396
        $courseId = intval($courseId);
397
        $result = Database::fetch_array(
398
            Database::query(
399
                "SELECT is_tutor
400
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
401
                WHERE
402
                    c_id = $courseId AND
403
                    user_id = $userId"
404
            )
405
        );
406
407
        return $result['is_tutor'];
408
    }
409
410
    /**
411
     * Unsubscribe one or more users from a course.
412
     *
413
     * @param   mixed   user_id or an array with user ids
414
     * @param   string  course code
415
     * @param   int     session id
416
     *
417
     * @return bool
418
     *
419
     * @assert ('', '') === false
420
     */
421
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
422
    {
423
        if (empty($user_id)) {
424
            return false;
425
        }
426
        if (!is_array($user_id)) {
427
            $user_id = [$user_id];
428
        }
429
430
        if (0 == count($user_id)) {
431
            return false;
432
        }
433
434
        if (!empty($session_id)) {
435
            $session_id = (int) $session_id;
436
        } else {
437
            $session_id = api_get_session_id();
438
        }
439
440
        if (empty($course_code)) {
441
            return false;
442
        }
443
444
        $userList = [];
445
        // Cleaning the $user_id variable
446
        if (is_array($user_id)) {
447
            $new_user_id_list = [];
448
            foreach ($user_id as $my_user_id) {
449
                $new_user_id_list[] = (int) $my_user_id;
450
            }
451
            $new_user_id_list = array_filter($new_user_id_list);
452
            $userList = $new_user_id_list;
453
            $user_ids = implode(',', $new_user_id_list);
454
        } else {
455
            $user_ids = (int) $user_id;
456
            $userList[] = $user_id;
457
        }
458
459
        $course_info = api_get_course_info($course_code);
460
        $course_id = $course_info['real_id'];
461
462
        // Unsubscribe user from all groups in the course.
463
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_USER)."
464
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
465
        Database::query($sql);
466
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_GROUP_TUTOR)."
467
                WHERE c_id = $course_id AND user_id IN (".$user_ids.")";
468
        Database::query($sql);
469
470
        // Erase user student publications (works) in the course - by André Boivin
471
        if (!empty($userList)) {
472
            require_once api_get_path(SYS_CODE_PATH).'work/work.lib.php';
473
            foreach ($userList as $userId) {
474
                // Getting all work from user
475
                $workList = getWorkPerUser($userId);
476
                if (!empty($workList)) {
477
                    foreach ($workList as $work) {
478
                        $work = $work['work'];
479
                        // Getting user results
480
                        if (!empty($work->user_results)) {
481
                            foreach ($work->user_results as $workSent) {
482
                                deleteWorkItem($workSent['id'], $course_info);
483
                            }
484
                        }
485
                    }
486
                }
487
            }
488
        }
489
490
        // Unsubscribe user from all blogs in the course.
491
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_REL_USER)."
492
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
493
        Database::query($sql);
494
495
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER)."
496
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
497
        Database::query($sql);
498
499
        // Deleting users in forum_notification and mailqueue course tables
500
        $sql = "DELETE FROM  ".Database::get_course_table(TABLE_FORUM_NOTIFICATION)."
501
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
502
        Database::query($sql);
503
504
        $sql = "DELETE FROM ".Database::get_course_table(TABLE_FORUM_MAIL_QUEUE)."
505
                WHERE c_id = $course_id AND user_id IN ($user_ids)";
506
        Database::query($sql);
507
508
        // Unsubscribe user from the course.
509
        if (!empty($session_id)) {
510
            foreach ($userList as $uid) {
511
                SessionManager::unSubscribeUserFromCourseSession($uid, $course_id, $session_id);
512
513
                // check if a user is register in the session with other course
514
                $sql = "SELECT user_id FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
515
                        WHERE session_id = $session_id AND user_id = $uid";
516
                $rs = Database::query($sql);
517
518
                if (0 == Database::num_rows($rs)) {
519
                    SessionManager::unsubscribe_user_from_session($uid, $session_id);
520
                }
521
            }
522
523
            Event::addEvent(
524
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
525
                LOG_COURSE_CODE,
526
                $course_code,
527
                api_get_utc_datetime(),
528
                $user_id,
529
                $course_id,
530
                $session_id
531
            );
532
        } else {
533
            $sql = "DELETE FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
534
                    WHERE
535
                        user_id IN ($user_ids) AND
536
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
537
                        c_id = $course_id";
538
            Database::query($sql);
539
540
            // add event to system log
541
            $user_id = api_get_user_id();
542
543
            Event::addEvent(
544
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
545
                LOG_COURSE_CODE,
546
                $course_code,
547
                api_get_utc_datetime(),
548
                $user_id,
549
                $course_id
550
            );
551
552
            foreach ($userList as $userId) {
553
                $userInfo = api_get_user_info($userId);
554
                Event::addEvent(
555
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
556
                    LOG_USER_OBJECT,
557
                    $userInfo,
558
                    api_get_utc_datetime(),
559
                    $user_id,
560
                    $course_id
561
                );
562
            }
563
        }
564
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
565
            // Also unlink the course from the users' currently accessible sessions
566
            /** @var Course $course */
567
            $course = Database::getManager()->getRepository('ChamiloCoreBundle:Course')->findOneBy([
568
                'code' => $course_code,
569
            ]);
570
            if (is_null($course)) {
571
                return false;
572
            }
573
            /** @var Chamilo\UserBundle\Entity\User $user */
574
            foreach (UserManager::getRepository()->matching(
575
                Criteria::create()->where(Criteria::expr()->in('id', $userList))
576
            ) as $user) {
577
                foreach ($user->getCurrentlyAccessibleSessions() as $session) {
578
                    $session->removeCourse($course);
579
                    // unsubscribe user from course within this session
580
                    SessionManager::unSubscribeUserFromCourseSession($user->getId(), $course->getId(), $session->getId());
581
                }
582
            }
583
            try {
584
                Database::getManager()->flush();
585
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
586
                Display::addFlash(
587
                    Display::return_message(
588
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
589
                        'warning'
590
                    )
591
                );
592
593
                return false;
594
            }
595
        }
596
597
        return true;
598
    }
599
600
    /**
601
     * @param string $courseCode
602
     * @param int    $status
603
     *
604
     * @return bool
605
     */
606
    public static function autoSubscribeToCourse($courseCode, $status = STUDENT)
607
    {
608
        if (api_is_anonymous()) {
609
            return false;
610
        }
611
612
        $course = Database::getManager()->getRepository('ChamiloCoreBundle:Course')->findOneBy(['code' => $courseCode]);
613
614
        if (null === $course) {
615
            return false;
616
        }
617
618
        $visibility = (int) $course->getVisibility();
619
620
        if (in_array($visibility, [
621
                COURSE_VISIBILITY_CLOSED,
622
                //COURSE_VISIBILITY_REGISTERED,
623
                COURSE_VISIBILITY_HIDDEN,
624
        ])) {
625
            Display::addFlash(
626
                Display::return_message(
627
                    get_lang('SubscribingNotAllowed'),
628
                    'warning'
629
        )
630
            );
631
632
            return false;
633
        }
634
635
        // Private course can allow auto subscription
636
        if (COURSE_VISIBILITY_REGISTERED === $visibility && false === $course->getSubscribe()) {
637
            Display::addFlash(
638
                Display::return_message(
639
                    get_lang('Subscribing not allowed'),
640
                    'warning'
641
                )
642
            );
643
644
            return false;
645
        }
646
647
        $userId = api_get_user_id();
648
649
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
650
            /**
651
             * @var Chamilo\UserBundle\Entity\User
652
             */
653
            $user = UserManager::getRepository()->find($userId);
654
            $sessions = $user->getCurrentlyAccessibleSessions();
655
            if (empty($sessions)) {
656
                // user has no accessible session
657
                if ($user->getStudentSessions()) {
658
                    // user has ancient or future student session(s) but not available now
659
                    Display::addFlash(
660
                        Display::return_message(
661
                            get_lang('CanNotSubscribeToCourseUserSessionExpired'),
662
                            'warning'
663
                        )
664
                    );
665
666
                    return false;
667
                }
668
                // user has no session at all, create one starting now
669
                $numberOfDays = api_get_configuration_value('user_s_session_duration') ?: 3 * 365;
670
                try {
671
                    $duration = new DateInterval(sprintf('P%dD', $numberOfDays));
672
                } catch (Exception $exception) {
673
                    Display::addFlash(
674
                        Display::return_message(
675
                            get_lang('WrongNumberOfDays').': '.$numberOfDays.': '.$exception->getMessage(),
676
                            'warning'
677
                        )
678
                    );
679
680
                    return false;
681
                }
682
                $endDate = new DateTime();
683
                $endDate->add($duration);
684
                $session = new \Chamilo\CoreBundle\Entity\Session();
685
                $session->setName(
686
                    sprintf(get_lang('FirstnameLastnameCourses'), $user->getFirstname(), $user->getLastname())
687
                );
688
                $session->setAccessEndDate($endDate);
689
                $session->setCoachAccessEndDate($endDate);
690
                $session->setDisplayEndDate($endDate);
691
                $session->setSendSubscriptionNotification(false);
692
                $session->setSessionAdminId(api_get_configuration_value('session_automatic_creation_user_id') ?: 1);
693
                $session->addUserInSession(0, $user);
694
                Database::getManager()->persist($session);
695
                try {
696
                    Database::getManager()->flush();
697
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
698
                    Display::addFlash(
699
                        Display::return_message(
700
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
701
                            'warning'
702
                        )
703
                    );
704
705
                    return false;
706
                }
707
                $accessUrlRelSession = new \Chamilo\CoreBundle\Entity\AccessUrlRelSession();
708
                $accessUrlRelSession->setAccessUrlId(api_get_current_access_url_id());
709
                $accessUrlRelSession->setSessionId($session->getId());
710
                Database::getManager()->persist($accessUrlRelSession);
711
                try {
712
                    Database::getManager()->flush();
713
                } catch (\Doctrine\ORM\OptimisticLockException $exception) {
714
                    Display::addFlash(
715
                        Display::return_message(
716
                            get_lang('InternalDatabaseError').': '.$exception->getMessage(),
717
                            'warning'
718
                        )
719
                    );
720
721
                    return false;
722
                }
723
            } else {
724
                // user has at least one accessible session, let's use it
725
                $session = $sessions[0];
726
            }
727
            // add chosen course to the user session
728
            $session->addCourse($course);
729
            Database::getManager()->persist($session);
730
            try {
731
                Database::getManager()->flush();
732
            } catch (\Doctrine\ORM\OptimisticLockException $exception) {
733
                Display::addFlash(
734
                    Display::return_message(
735
                        get_lang('InternalDatabaseError').': '.$exception->getMessage(),
736
                        'warning'
737
                    )
738
                );
739
740
                return false;
741
            }
742
            // subscribe user to course within this session
743
            SessionManager::subscribe_users_to_session_course([$userId], $session->getId(), $course->getCode());
744
745
            return true;
746
        }
747
748
        return self::subscribeUser($userId, $course->getCode(), $status, 0);
749
    }
750
751
    /**
752
     * Subscribe a user to a course. No checks are performed here to see if
753
     * course subscription is allowed.
754
     *
755
     * @param int    $userId
756
     * @param string $courseCode
757
     * @param int    $status                 (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
758
     * @param int    $sessionId
759
     * @param int    $userCourseCategoryId
760
     * @param bool   $checkTeacherPermission
761
     *
762
     * @return bool True on success, false on failure
763
     *
764
     * @assert ('', '') === false
765
     */
766
    public static function subscribeUser(
767
        $userId,
768
        $courseCode,
769
        $status = STUDENT,
770
        $sessionId = 0,
771
        $userCourseCategoryId = 0,
772
        $checkTeacherPermission = true
773
    ) {
774
        $userId = (int) $userId;
775
        $status = (int) $status;
776
777
        if (empty($userId) || empty($courseCode)) {
778
            return false;
779
        }
780
781
        $courseInfo = api_get_course_info($courseCode);
782
783
        if (empty($courseInfo)) {
784
            Display::addFlash(Display::return_message(get_lang('This course doesn\'t exist'), 'warning'));
785
786
            return false;
787
        }
788
789
        $userInfo = api_get_user_info($userId);
790
791
        if (empty($userInfo)) {
792
            Display::addFlash(Display::return_message(get_lang('This user doesn\'t exist'), 'warning'));
793
794
            return false;
795
        }
796
797
        $courseId = $courseInfo['real_id'];
798
        $courseCode = $courseInfo['code'];
799
        $userCourseCategoryId = (int) $userCourseCategoryId;
800
        $sessionId = empty($sessionId) ? api_get_session_id() : (int) $sessionId;
801
        $status = STUDENT === $status || COURSEMANAGER === $status ? $status : STUDENT;
802
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
803
804
        if (!empty($sessionId)) {
805
            SessionManager::subscribe_users_to_session_course(
806
                [$userId],
807
                $sessionId,
808
                $courseCode
809
            );
810
811
            // Add event to the system log
812
            Event::addEvent(
813
                LOG_SUBSCRIBE_USER_TO_COURSE,
814
                LOG_COURSE_CODE,
815
                $courseCode,
816
                api_get_utc_datetime(),
817
                api_get_user_id(),
818
                $courseId,
819
                $sessionId
820
            );
821
            Event::addEvent(
822
                LOG_SUBSCRIBE_USER_TO_COURSE,
823
                LOG_USER_OBJECT,
824
                $userInfo,
825
                api_get_utc_datetime(),
826
                api_get_user_id(),
827
                $courseId,
828
                $sessionId
829
            );
830
831
            return true;
832
        } else {
833
            // Check whether the user has not been already subscribed to the course.
834
            $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
835
                    WHERE
836
                        user_id = $userId AND
837
                        relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
838
                        c_id = $courseId
839
                    ";
840
            if (Database::num_rows(Database::query($sql)) > 0) {
841
                Display::addFlash(Display::return_message(get_lang('Already registered in course'), 'warning'));
842
843
                return false;
844
            }
845
846
            if ($checkTeacherPermission && !api_is_course_admin()) {
847
                // Check in advance whether subscription is allowed or not for this course.
848
                if (SUBSCRIBE_NOT_ALLOWED === (int) $courseInfo['subscribe']) {
849
                    Display::addFlash(Display::return_message(get_lang('SubscriptionNotAllowed'), 'warning'));
850
851
                    return false;
852
                }
853
            }
854
855
            if (STUDENT === $status) {
856
                // Check if max students per course extra field is set
857
                $extraFieldValue = new ExtraFieldValue('course');
858
                $value = $extraFieldValue->get_values_by_handler_and_field_variable($courseId, 'max_subscribed_students');
859
                if (!empty($value) && isset($value['value'])) {
860
                    $maxStudents = $value['value'];
861
                    if ('' !== $maxStudents) {
862
                        $maxStudents = (int) $maxStudents;
863
                        $count = self::get_user_list_from_course_code(
864
                            $courseCode,
865
                            0,
866
                            null,
867
                            null,
868
                            STUDENT,
869
                            true,
870
                            false
871
                        );
872
873
                        if ($count >= $maxStudents) {
874
                            Display::addFlash(Display::return_message(get_lang('The maximum number of student has already been reached, it is not possible to subscribe more student.'), 'warning'));
875
876
                            return false;
877
                        }
878
                    }
879
                }
880
            }
881
882
            $maxSort = api_max_sort_value('0', $userId);
883
            $params = [
884
                'c_id' => $courseId,
885
                'user_id' => $userId,
886
                'status' => $status,
887
                'sort' => $maxSort + 1,
888
                'relation_type' => 0,
889
                'user_course_cat' => (int) $userCourseCategoryId,
890
            ];
891
            $insertId = Database::insert($courseUserTable, $params);
892
893
            if ($insertId) {
894
                Display::addFlash(
895
                    Display::return_message(
896
                        sprintf(
897
                            get_lang('User %s has been registered to course %s'),
898
                            $userInfo['complete_name_with_username'],
899
                            $courseInfo['title']
900
                        )
901
                    )
902
                );
903
904
                $send = api_get_course_setting('email_alert_to_teacher_on_new_user_in_course', $courseInfo);
905
906
                if (1 == $send) {
907
                    self::email_to_tutor(
908
                        $userId,
909
                        $courseInfo['real_id'],
910
                        false
911
                    );
912
                } elseif (2 == $send) {
913
                    self::email_to_tutor(
914
                        $userId,
915
                        $courseInfo['real_id'],
916
                        true
917
                    );
918
                }
919
920
                $subscribe = (int) api_get_course_setting('subscribe_users_to_forum_notifications', $courseInfo);
921
                if (1 === $subscribe) {
922
                    require_once api_get_path(SYS_CODE_PATH).'forum/forumfunction.inc.php';
923
                    $forums = get_forums(0, $courseCode, true, $sessionId);
924
                    foreach ($forums as $forum) {
925
                        $forumId = $forum['iid'];
926
                        set_notification('forum', $forumId, false, $userInfo, $courseInfo);
927
                    }
928
                }
929
930
                // Add event to the system log
931
                Event::addEvent(
932
                    LOG_SUBSCRIBE_USER_TO_COURSE,
933
                    LOG_COURSE_CODE,
934
                    $courseCode,
935
                    api_get_utc_datetime(),
936
                    api_get_user_id(),
937
                    $courseId
938
                );
939
940
                Event::addEvent(
941
                    LOG_SUBSCRIBE_USER_TO_COURSE,
942
                    LOG_USER_OBJECT,
943
                    $userInfo,
944
                    api_get_utc_datetime(),
945
                    api_get_user_id(),
946
                    $courseId
947
                );
948
949
                return true;
950
            }
951
952
            return false;
953
        }
954
    }
955
956
    /**
957
     * Get the course id based on the original id and field name in the
958
     * extra fields. Returns 0 if course was not found.
959
     *
960
     * @param string $original_course_id_value
961
     * @param string $original_course_id_name
962
     *
963
     * @return int Course id
964
     *
965
     * @assert ('', '') === false
966
     */
967
    public static function get_course_code_from_original_id(
968
        $original_course_id_value,
969
        $original_course_id_name
970
    ) {
971
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
972
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
973
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
974
        $original_course_id_value = Database::escape_string($original_course_id_value);
975
        $original_course_id_name = Database::escape_string($original_course_id_name);
976
977
        $sql = "SELECT item_id
978
                FROM $table_field cf
979
                INNER JOIN $t_cfv cfv
980
                ON cfv.field_id=cf.id
981
                WHERE
982
                    variable = '$original_course_id_name' AND
983
                    value = '$original_course_id_value' AND
984
                    cf.extra_field_type = $extraFieldType
985
                ";
986
        $res = Database::query($sql);
987
        $row = Database::fetch_object($res);
988
        if ($row) {
989
            return $row->item_id;
990
        } else {
991
            return 0;
992
        }
993
    }
994
995
    /**
996
     * Gets the course code from the course id. Returns null if course id was not found.
997
     *
998
     * @param int $id Course id
999
     *
1000
     * @return string Course code
1001
     * @assert ('') === false
1002
     */
1003
    public static function get_course_code_from_course_id($id)
1004
    {
1005
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
1006
        $id = intval($id);
1007
        $sql = "SELECT code FROM $table WHERE id = $id ";
1008
        $res = Database::query($sql);
1009
        $row = Database::fetch_object($res);
1010
        if ($row) {
1011
            return $row->code;
1012
        } else {
1013
            return null;
1014
        }
1015
    }
1016
1017
    /**
1018
     * Add the user $userId visibility to the course $courseCode in the catalogue.
1019
     *
1020
     * @author David Nos (https://github.com/dnos)
1021
     *
1022
     * @param int    $userId     the id of the user
1023
     * @param string $courseCode the course code
1024
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
1025
     *
1026
     * @return bool true if added succesfully, false otherwise
1027
     */
1028
    public static function addUserVisibilityToCourseInCatalogue(
1029
        $userId,
1030
        $courseCode,
1031
        $visible = 1
1032
    ) {
1033
        $debug = false;
1034
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1035
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
1036
        $visible = (int) $visible;
1037
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
1038
            return false;
1039
        }
1040
1041
        $courseCode = Database::escape_string($courseCode);
1042
        $courseInfo = api_get_course_info($courseCode);
1043
        $courseId = $courseInfo['real_id'];
1044
1045
        // Check in advance whether the user has already been registered on the platform.
1046
        $sql = "SELECT status FROM ".$userTable." WHERE user_id = $userId ";
1047
        if (0 == Database::num_rows(Database::query($sql))) {
1048
            if ($debug) {
1049
                error_log('The user has not been registered to the platform');
1050
            }
1051
1052
            return false; // The user has not been registered to the platform.
1053
        }
1054
1055
        // Check whether the user has already been registered to the course visibility in the catalogue.
1056
        $sql = "SELECT * FROM $courseUserTable
1057
                WHERE
1058
                    user_id = $userId AND
1059
                    visible = $visible AND
1060
                    c_id = $courseId";
1061
        if (Database::num_rows(Database::query($sql)) > 0) {
1062
            if ($debug) {
1063
                error_log('The user has been already registered to the course visibility in the catalogue');
1064
            }
1065
1066
            return true; // The visibility of the user to the course in the catalogue does already exist.
1067
        }
1068
1069
        // Register the user visibility to course in catalogue.
1070
        $params = [
1071
            'user_id' => $userId,
1072
            'c_id' => $courseId,
1073
            'visible' => $visible,
1074
        ];
1075
        $insertId = Database::insert($courseUserTable, $params);
1076
1077
        return $insertId;
1078
    }
1079
1080
    /**
1081
     * Remove the user $userId visibility to the course $courseCode in the catalogue.
1082
     *
1083
     * @author David Nos (https://github.com/dnos)
1084
     *
1085
     * @param int    $userId     the id of the user
1086
     * @param string $courseCode the course code
1087
     * @param int    $visible    (optional) The course visibility in the catalogue to the user (1=visible, 0=invisible)
1088
     *
1089
     * @return bool true if removed succesfully or register not found, false otherwise
1090
     */
1091
    public static function removeUserVisibilityToCourseInCatalogue(
1092
        $userId,
1093
        $courseCode,
1094
        $visible = 1
1095
    ) {
1096
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
1097
1098
        if (empty($userId) || empty($courseCode) || ($userId != strval(intval($userId)))) {
1099
            return false;
1100
        }
1101
1102
        $courseCode = Database::escape_string($courseCode);
1103
        $courseInfo = api_get_course_info($courseCode);
1104
        $courseId = $courseInfo['real_id'];
1105
1106
        // Check whether the user has already been registered to the course visibility in the catalogue.
1107
        $sql = "SELECT * FROM $courseUserTable
1108
                WHERE
1109
                    user_id = $userId AND
1110
                    visible = $visible AND
1111
                    c_id = $courseId";
1112
        if (Database::num_rows(Database::query($sql)) > 0) {
1113
            $cond = [
1114
                'user_id = ? AND c_id = ? AND visible = ? ' => [
1115
                    $userId,
1116
                    $courseId,
1117
                    $visible,
1118
                ],
1119
            ];
1120
1121
            return Database::delete($courseUserTable, $cond);
1122
        } else {
1123
            return true; // Register does not exist
1124
        }
1125
    }
1126
1127
    /**
1128
     * @param string $code
1129
     *
1130
     * @return bool if there already are one or more courses
1131
     *              with the same code OR visual_code (visualcode), false otherwise
1132
     */
1133
    public static function course_code_exists($code)
1134
    {
1135
        $code = Database::escape_string($code);
1136
        $sql = "SELECT COUNT(*) as number
1137
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
1138
                WHERE code = '$code' OR visual_code = '$code'";
1139
        $result = Database::fetch_array(Database::query($sql));
1140
1141
        return $result['number'] > 0;
1142
    }
1143
1144
    /**
1145
     * @param int    $user_id
1146
     * @param string $startsWith Optional
1147
     *
1148
     * @return array an array with the course info of all the courses (real and virtual)
1149
     *               of which the current user is course admin
1150
     */
1151
    public static function get_course_list_of_user_as_course_admin($user_id, $startsWith = '')
1152
    {
1153
        if ($user_id != strval(intval($user_id))) {
1154
            return [];
1155
        }
1156
1157
        // Definitions database tables and variables
1158
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
1159
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1160
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
1161
        $user_id = intval($user_id);
1162
        $data = [];
1163
1164
        $sql = "SELECT
1165
                    course.code,
1166
                    course.title,
1167
                    course.id,
1168
                    course.id as real_id,
1169
                    course_category.code AS category_code
1170
                FROM $tbl_course_user as course_rel_user
1171
                INNER JOIN $tbl_course as course
1172
                ON course.id = course_rel_user.c_id
1173
                LEFT JOIN $tblCourseCategory ON course.category_id = $tblCourseCategory.id
1174
                WHERE
1175
                    course_rel_user.user_id = $user_id AND
1176
                    course_rel_user.status = 1
1177
        ";
1178
1179
        if (api_get_multiple_access_url()) {
1180
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
1181
            $access_url_id = api_get_current_access_url_id();
1182
            if (-1 != $access_url_id) {
1183
                $sql = "
1184
                    SELECT
1185
                        course.code,
1186
                        course.title,
1187
                        course.id,
1188
                        course.id as real_id
1189
                    FROM $tbl_course_user as course_rel_user
1190
                    INNER JOIN $tbl_course as course
1191
                    ON course.id = course_rel_user.c_id
1192
                    INNER JOIN $tbl_course_rel_access_url course_rel_url
1193
                    ON (course_rel_url.c_id = course.id)
1194
                    WHERE
1195
                        access_url_id = $access_url_id  AND
1196
                        course_rel_user.user_id = $user_id AND
1197
                        course_rel_user.status = 1
1198
                ";
1199
            }
1200
        }
1201
1202
        if (!empty($startsWith)) {
1203
            $startsWith = Database::escape_string($startsWith);
1204
1205
            $sql .= " AND (course.title LIKE '$startsWith%' OR course.code LIKE '$startsWith%')";
1206
        }
1207
1208
        $sql .= ' ORDER BY course.title';
1209
1210
        $result_nb_cours = Database::query($sql);
1211
        if (Database::num_rows($result_nb_cours) > 0) {
1212
            while ($row = Database::fetch_array($result_nb_cours, 'ASSOC')) {
1213
                $data[$row['id']] = $row;
1214
            }
1215
        }
1216
1217
        return $data;
1218
    }
1219
1220
    /**
1221
     * @param int   $userId
1222
     * @param array $courseInfo
1223
     *
1224
     * @return bool|null
1225
     */
1226
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
1227
    {
1228
        $userId = intval($userId);
1229
1230
        if (!api_is_drh()) {
1231
            return false;
1232
        }
1233
1234
        if (empty($courseInfo) || empty($userId)) {
1235
            return false;
1236
        }
1237
1238
        $courseId = intval($courseInfo['real_id']);
1239
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1240
1241
        $sql = "SELECT * FROM $table
1242
                WHERE
1243
                    user_id = $userId AND
1244
                    relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
1245
                    c_id = $courseId";
1246
1247
        $result = Database::fetch_array(Database::query($sql));
1248
1249
        if (!empty($result)) {
1250
            // The user has been registered in this course.
1251
            return true;
1252
        }
1253
    }
1254
1255
    /**
1256
     * Check if user is subscribed inside a course.
1257
     *
1258
     * @param int    $user_id
1259
     * @param string $course_code  , if this parameter is null, it'll check for all courses
1260
     * @param bool   $in_a_session True for checking inside sessions too, by default is not checked
1261
     * @param int    $session_id
1262
     *
1263
     * @return bool $session_id true if the user is registered in the course, false otherwise
1264
     */
1265
    public static function is_user_subscribed_in_course(
1266
        $user_id,
1267
        $course_code = null,
1268
        $in_a_session = false,
1269
        $session_id = 0
1270
    ) {
1271
        $user_id = (int) $user_id;
1272
        $session_id = (int) $session_id;
1273
1274
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
1275
            // with this option activated, only check whether the course is in one of the users' sessions
1276
            $course = Database::getManager()->getRepository('ChamiloCoreBundle:Course')->findOneBy([
1277
                'code' => $course_code,
1278
            ]);
1279
            if (is_null($course)) {
1280
                return false;
1281
            }
1282
            /**
1283
             * @var \Chamilo\UserBundle\Entity\User
1284
             */
1285
            $user = UserManager::getRepository()->find($user_id);
1286
            if (is_null($user)) {
1287
                return false;
1288
            }
1289
            foreach ($user->getStudentSessions() as $session) {
1290
                if ($session->isRelatedToCourse($course)) {
1291
                    return true;
1292
                }
1293
            }
1294
1295
            return false;
1296
        }
1297
1298
        if (empty($session_id)) {
1299
            $session_id = api_get_session_id();
1300
        }
1301
1302
        $condition_course = '';
1303
        if (isset($course_code)) {
1304
            $courseInfo = api_get_course_info($course_code);
1305
            if (empty($courseInfo)) {
1306
                return false;
1307
            }
1308
            $courseId = $courseInfo['real_id'];
1309
            $condition_course = " AND c_id = $courseId";
1310
        }
1311
1312
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1313
                WHERE
1314
                    user_id = $user_id AND
1315
                    relation_type<>".COURSE_RELATION_TYPE_RRHH."
1316
                    $condition_course ";
1317
1318
        $result = Database::fetch_array(Database::query($sql));
1319
1320
        if (!empty($result)) {
1321
            // The user has been registered in this course.
1322
            return true;
1323
        }
1324
1325
        if (!$in_a_session) {
1326
            // The user has not been registered in this course.
1327
            return false;
1328
        }
1329
1330
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1331
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1332
                WHERE user_id = $user_id AND session_id = $session_id $condition_course";
1333
1334
        if (Database::num_rows(Database::query($sql)) > 0) {
1335
            return true;
1336
        }
1337
1338
        $sql = "SELECT 1 FROM $tableSessionCourseUser
1339
                WHERE user_id = $user_id AND session_id = $session_id AND status = 2 $condition_course";
1340
1341
        if (Database::num_rows(Database::query($sql)) > 0) {
1342
            return true;
1343
        }
1344
1345
        $sql = 'SELECT 1 FROM '.Database::get_main_table(TABLE_MAIN_SESSION).
1346
              " WHERE id = $session_id AND id_coach = $user_id";
1347
1348
        if (Database::num_rows(Database::query($sql)) > 0) {
1349
            return true;
1350
        }
1351
1352
        return false;
1353
    }
1354
1355
    /**
1356
     * Is the user a teacher in the given course?
1357
     *
1358
     * @param int    $user_id     , the id (int) of the user
1359
     * @param string $course_code , the course code
1360
     *
1361
     * @return bool if the user is a teacher in the course, false otherwise
1362
     */
1363
    public static function is_course_teacher($user_id, $course_code)
1364
    {
1365
        if ($user_id != strval(intval($user_id))) {
1366
            return false;
1367
        }
1368
1369
        $courseInfo = api_get_course_info($course_code);
1370
        if (empty($courseInfo)) {
1371
            return false;
1372
        }
1373
        $courseId = $courseInfo['real_id'];
1374
        $sql = "SELECT status FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
1375
                WHERE c_id = $courseId AND user_id = $user_id ";
1376
        $result = Database::query($sql);
1377
1378
        if (Database::num_rows($result) > 0) {
1379
            return 1 == Database::result($result, 0, 'status');
1380
        }
1381
1382
        return false;
1383
    }
1384
1385
    /**
1386
     *    Is the user subscribed in the real course or linked courses?
1387
     *
1388
     * @param int the id of the user
1389
     * @param int $courseId
1390
     *
1391
     * @deprecated linked_courses definition doesn't exists
1392
     *
1393
     * @return bool if the user is registered in the real course or linked courses, false otherwise
1394
     */
1395
    public static function is_user_subscribed_in_real_or_linked_course($user_id, $courseId, $session_id = 0)
1396
    {
1397
        if ($user_id != strval(intval($user_id))) {
1398
            return false;
1399
        }
1400
1401
        $courseId = intval($courseId);
1402
        $session_id = intval($session_id);
1403
1404
        if (empty($session_id)) {
1405
            $result = Database::fetch_array(
1406
                Database::query(
1407
                    "SELECT *
1408
                    FROM ".Database::get_main_table(TABLE_MAIN_COURSE)." course
1409
                    LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." course_user
1410
                    ON course.id = course_user.c_id
1411
                    WHERE
1412
                        course_user.user_id = $user_id AND
1413
                        course_user.relation_type<>".COURSE_RELATION_TYPE_RRHH." AND
1414
                        ( course.id = $courseId)"
1415
                )
1416
            );
1417
1418
            return !empty($result);
1419
        }
1420
1421
        // From here we trust session id.
1422
        // Is he/she subscribed to the session's course?
1423
        // A user?
1424
        if (Database::num_rows(Database::query("SELECT user_id
1425
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
1426
                WHERE session_id = $session_id
1427
                AND user_id = $user_id"))
1428
        ) {
1429
            return true;
1430
        }
1431
1432
        // A course coach?
1433
        if (Database::num_rows(Database::query("SELECT user_id
1434
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)."
1435
                WHERE session_id = $session_id
1436
                AND user_id = $user_id AND status = 2
1437
                AND c_id = $courseId"))
1438
        ) {
1439
            return true;
1440
        }
1441
1442
        // A session coach?
1443
        if (Database::num_rows(Database::query("SELECT id_coach
1444
                FROM ".Database::get_main_table(TABLE_MAIN_SESSION)." AS session
1445
                WHERE session.id = $session_id
1446
                AND id_coach = $user_id"))
1447
        ) {
1448
            return true;
1449
        }
1450
1451
        return false;
1452
    }
1453
1454
    /**
1455
     * Return user info array of all users registered in a course
1456
     * This only returns the users that are registered in this actual course, not linked courses.
1457
     *
1458
     * @param string    $course_code
1459
     * @param int       $sessionId
1460
     * @param string    $limit
1461
     * @param string    $order_by         the field to order the users by.
1462
     *                                    Valid values are 'lastname', 'firstname', 'username', 'email', 'official_code' OR a part of a SQL statement
1463
     *                                    that starts with ORDER BY ...
1464
     * @param int|null  $filter_by_status if using the session_id: 0 or 2 (student, coach),
1465
     *                                    if using session_id = 0 STUDENT or COURSEMANAGER
1466
     * @param bool|null $return_count
1467
     * @param bool      $add_reports
1468
     * @param bool      $resumed_report
1469
     * @param array     $extra_field
1470
     * @param array     $courseCodeList
1471
     * @param array     $userIdList
1472
     * @param string    $filterByActive
1473
     * @param array     $sessionIdList
1474
     * @param string    $searchByKeyword
1475
     *
1476
     * @return array|int
1477
     */
1478
    public static function get_user_list_from_course_code(
1479
        $course_code = null,
1480
        $sessionId = 0,
1481
        $limit = null,
1482
        $order_by = null,
1483
        $filter_by_status = null,
1484
        $return_count = null,
1485
        $add_reports = false,
1486
        $resumed_report = false,
1487
        $extra_field = [],
1488
        $courseCodeList = [],
1489
        $userIdList = [],
1490
        $filterByActive = null,
1491
        $sessionIdList = [],
1492
        $searchByKeyword = '',
1493
        $options = []
1494
    ) {
1495
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1496
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1497
1498
        $sessionId = (int) $sessionId;
1499
        $course_code = Database::escape_string($course_code);
1500
        $courseInfo = api_get_course_info($course_code);
1501
        $courseId = 0;
1502
        if (!empty($courseInfo)) {
1503
            $courseId = $courseInfo['real_id'];
1504
        }
1505
1506
        $where = [];
1507
        if (empty($order_by)) {
1508
            $order_by = 'user.lastname, user.firstname';
1509
            if (api_is_western_name_order()) {
1510
                $order_by = 'user.firstname, user.lastname';
1511
            }
1512
        }
1513
1514
        // if the $order_by does not contain 'ORDER BY'
1515
        // we have to check if it is a valid field that can be sorted on
1516
        if (!strstr($order_by, 'ORDER BY')) {
1517
            if (!empty($order_by)) {
1518
                $order_by = "ORDER BY $order_by";
1519
            } else {
1520
                $order_by = '';
1521
            }
1522
        }
1523
1524
        $filter_by_status_condition = null;
1525
        $sqlInjectWhere = '';
1526
        $whereExtraField = '';
1527
        $injectExtraFields = ' , ';
1528
        $sqlInjectJoins = '';
1529
        if (!empty($options)) {
1530
            $extraFieldModel = new ExtraField('user');
1531
            $conditions = $extraFieldModel->parseConditions($options, 'user');
1532
            if (!empty($conditions)) {
1533
                $injectExtraFields = $conditions['inject_extra_fields'];
1534
1535
                if (!empty($injectExtraFields)) {
1536
                    $injectExtraFields = ', '.$injectExtraFields;
1537
                } else {
1538
                    $injectExtraFields = ' , ';
1539
                }
1540
                $sqlInjectJoins = $conditions['inject_joins'];
1541
                $whereExtraField = $conditions['where'];
1542
            }
1543
        }
1544
1545
        if (!empty($sessionId) || !empty($sessionIdList)) {
1546
            $sql = 'SELECT DISTINCT
1547
                        user.id as user_id,
1548
                        user.email,
1549
                        session_course_user.status as status_session,
1550
                        session_id,
1551
                        user.*,
1552
                        course.*,
1553
                        course.id AS c_id
1554
                         '.$injectExtraFields.'
1555
                        session.name as session_name
1556
                    ';
1557
            if ($return_count) {
1558
                $sql = ' SELECT COUNT(user.id) as count';
1559
            }
1560
1561
            $sessionCondition = " session_course_user.session_id = $sessionId";
1562
            if (!empty($sessionIdList)) {
1563
                $sessionIdListToString = implode("','", array_map('intval', $sessionIdList));
1564
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListToString') ";
1565
            }
1566
1567
            $courseCondition = " course.id = $courseId";
1568
            if (!empty($courseCodeList)) {
1569
                $courseCodeListForSession = array_map(['Database', 'escape_string'], $courseCodeList);
1570
                $courseCodeListForSession = implode("','", $courseCodeListForSession);
1571
                $courseCondition = " course.code IN ('$courseCodeListForSession')  ";
1572
            }
1573
1574
            $sql .= ' FROM '.Database::get_main_table(TABLE_MAIN_USER).' as user ';
1575
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." as session_course_user
1576
                      ON
1577
                        user.id = session_course_user.user_id AND
1578
                        $sessionCondition
1579
                        INNER JOIN $course_table course
1580
                        ON session_course_user.c_id = course.id AND
1581
                        $courseCondition
1582
                        INNER JOIN $sessionTable session
1583
                        ON session_course_user.session_id = session.id
1584
                    $sqlInjectJoins
1585
                   ";
1586
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1587
1588
            // 2 = coach
1589
            // 0 = student
1590
            if (isset($filter_by_status)) {
1591
                $filter_by_status = (int) $filter_by_status;
1592
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1593
            }
1594
        } else {
1595
            if ($return_count) {
1596
                $sql = " SELECT COUNT(*) as count";
1597
            } else {
1598
                if (empty($course_code)) {
1599
                    $sql = 'SELECT DISTINCT
1600
                                course.title,
1601
                                course.code,
1602
                                course.id AS c_id,
1603
                                course_rel_user.status as status_rel,
1604
                                user.id as user_id,
1605
                                user.email,
1606
                                course_rel_user.is_tutor
1607
                                '.$injectExtraFields.'
1608
                                user.*  ';
1609
                } else {
1610
                    $sql = 'SELECT DISTINCT
1611
                                course_rel_user.status as status_rel,
1612
                                user.id as user_id,
1613
                                user.email,
1614
                                course_rel_user.is_tutor
1615
                                '.$injectExtraFields.'
1616
                                user.*  ';
1617
                }
1618
            }
1619
1620
            $sql .= " FROM ".Database::get_main_table(TABLE_MAIN_USER)." as user
1621
                      LEFT JOIN ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." as course_rel_user
1622
                      ON
1623
                        user.id = course_rel_user.user_id AND
1624
                        course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1625
                       INNER JOIN $course_table course
1626
                       ON (course_rel_user.c_id = course.id)
1627
                       $sqlInjectJoins
1628
                       ";
1629
1630
            if (!empty($course_code)) {
1631
                $sql .= " AND course_rel_user.c_id = $courseId";
1632
            }
1633
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1634
1635
            if (isset($filter_by_status) && is_numeric($filter_by_status)) {
1636
                $filter_by_status = (int) $filter_by_status;
1637
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1638
            }
1639
        }
1640
1641
        $multiple_access_url = api_get_multiple_access_url();
1642
        if ($multiple_access_url) {
1643
            $sql .= ' LEFT JOIN '.Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER).' au
1644
                      ON (au.user_id = user.id) ';
1645
        }
1646
1647
        $extraFieldWasAdded = false;
1648
        if ($return_count && $resumed_report) {
1649
            foreach ($extra_field as $extraField) {
1650
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1651
                if (!empty($extraFieldInfo)) {
1652
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1653
                    $sql .= " LEFT JOIN $fieldValuesTable as ufv
1654
                            ON (
1655
                                user.id = ufv.item_id AND
1656
                                (field_id = ".$extraFieldInfo['id']." OR field_id IS NULL)
1657
                            )";
1658
                    $extraFieldWasAdded = true;
1659
                }
1660
            }
1661
        }
1662
1663
        $sql .= " WHERE
1664
            $filter_by_status_condition
1665
            ".implode(' OR ', $where);
1666
1667
        if ($multiple_access_url) {
1668
            $current_access_url_id = api_get_current_access_url_id();
1669
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1670
        }
1671
1672
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1673
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1674
        }
1675
1676
        if (!empty($courseCodeList)) {
1677
            $courseCodeList = array_map(['Database', 'escape_string'], $courseCodeList);
1678
            $courseCodeList = implode('","', $courseCodeList);
1679
            if (empty($sessionIdList)) {
1680
                $sql .= ' AND course.code IN ("'.$courseCodeList.'")';
1681
            }
1682
        }
1683
1684
        if (!empty($userIdList)) {
1685
            $userIdList = array_map('intval', $userIdList);
1686
            $userIdList = implode('","', $userIdList);
1687
            $sql .= ' AND user.id IN ("'.$userIdList.'")';
1688
        }
1689
1690
        if (isset($filterByActive)) {
1691
            $filterByActive = (int) $filterByActive;
1692
            $sql .= " AND user.active = $filterByActive";
1693
        }
1694
1695
        if (!empty($searchByKeyword)) {
1696
            $searchByKeyword = Database::escape_string($searchByKeyword);
1697
            $sql .= " AND (
1698
                        user.firstname LIKE '$searchByKeyword' OR
1699
                        user.username LIKE '$searchByKeyword' OR
1700
                        user.lastname LIKE '$searchByKeyword'
1701
                    ) ";
1702
        }
1703
1704
        $sql .= $whereExtraField;
1705
        $sql .= " $order_by $limit";
1706
1707
        $rs = Database::query($sql);
1708
        $users = [];
1709
1710
        $extra_fields = UserManager::get_extra_fields(
1711
            0,
1712
            100,
1713
            null,
1714
            null,
1715
            true,
1716
            true
1717
        );
1718
1719
        $counter = 1;
1720
        $count_rows = Database::num_rows($rs);
1721
1722
        if ($return_count && $resumed_report) {
1723
            return $count_rows;
1724
        }
1725
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1726
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1727
        if ($count_rows) {
1728
            while ($user = Database::fetch_array($rs)) {
1729
                if ($return_count) {
1730
                    return $user['count'];
1731
                }
1732
1733
                $report_info = [];
1734
                $user_info = $user;
1735
                $user_info['status'] = $user['status'];
1736
                if (isset($user['is_tutor'])) {
1737
                    $user_info['is_tutor'] = $user['is_tutor'];
1738
                }
1739
                if (!empty($sessionId)) {
1740
                    $user_info['status_session'] = $user['status_session'];
1741
                }
1742
1743
                $sessionId = isset($user['session_id']) ? $user['session_id'] : 0;
1744
                $course_code = isset($user['code']) ? $user['code'] : null;
1745
                $sessionName = isset($user['session_name']) ? ' ('.$user['session_name'].') ' : '';
1746
1747
                if ($add_reports) {
1748
                    if ($resumed_report) {
1749
                        $extra = [];
1750
                        if (!empty($extra_fields)) {
1751
                            foreach ($extra_fields as $extra) {
1752
                                if (in_array($extra['1'], $extra_field)) {
1753
                                    $user_data = UserManager::get_extra_user_data_by_field(
1754
                                        $user['user_id'],
1755
                                        $extra['1']
1756
                                    );
1757
                                    break;
1758
                                }
1759
                            }
1760
                        }
1761
1762
                        $row_key = '-1';
1763
                        $name = '-';
1764
                        if (!empty($extra)) {
1765
                            if (!empty($user_data[$extra['1']])) {
1766
                                $row_key = $user_data[$extra['1']];
1767
                                $name = $user_data[$extra['1']];
1768
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1769
                            }
1770
                        }
1771
1772
                        if (empty($users[$row_key])) {
1773
                            $users[$row_key] = [];
1774
                        }
1775
1776
                        if (!array_key_exists('training_hours', $users[$row_key])) {
1777
                            $users[$row_key]['training_hours'] = 0;
1778
                        }
1779
1780
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1781
                            $user['user_id'],
1782
                            $courseId,
1783
                            $sessionId
1784
                        );
1785
1786
                        if (!array_key_exists('count_users', $users[$row_key])) {
1787
                            $users[$row_key]['count_users'] = 0;
1788
                        }
1789
1790
                        $users[$row_key]['count_users'] += $counter;
1791
1792
                        $registered_users_with_extra_field = self::getCountRegisteredUsersWithCourseExtraField(
1793
                            $name,
1794
                            $tableExtraField,
1795
                            $table_user_field_value
1796
                        );
1797
1798
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1799
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1800
1801
                        $category = Category:: load(
1802
                            null,
1803
                            null,
1804
                            $course_code,
1805
                            null,
1806
                            null,
1807
                            $sessionId
1808
                        );
1809
1810
                        if (!isset($users[$row_key]['count_certificates'])) {
1811
                            $users[$row_key]['count_certificates'] = 0;
1812
                        }
1813
1814
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1815
                            $users[$row_key]['count_certificates']++;
1816
                        }
1817
1818
                        foreach ($extra_fields as $extra) {
1819
                            if ('ruc' == $extra['1']) {
1820
                                continue;
1821
                            }
1822
1823
                            if (!isset($users[$row_key][$extra['1']])) {
1824
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1825
                                if (!empty($user_data[$extra['1']])) {
1826
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1827
                                }
1828
                            }
1829
                        }
1830
                    } else {
1831
                        $report_info['course'] = $user['title'].$sessionName;
1832
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1833
                        $report_info['email'] = $user['email'];
1834
                        $report_info['time'] = api_time_to_hms(
1835
                            Tracking::get_time_spent_on_the_course(
1836
                                $user['user_id'],
1837
                                empty($user['c_id']) ? $courseId : $user['c_id'],
1838
                                $sessionId
1839
                            )
1840
                        );
1841
1842
                        $category = Category:: load(
1843
                            null,
1844
                            null,
1845
                            $course_code,
1846
                            null,
1847
                            null,
1848
                            $sessionId
1849
                        );
1850
1851
                        $report_info['certificate'] = Display::label(get_lang('No'));
1852
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1853
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1854
                        }
1855
1856
                        $progress = intval(
1857
                            Tracking::get_avg_student_progress(
1858
                                $user['user_id'],
1859
                                $course_code,
1860
                                [],
1861
                                $sessionId
1862
                            )
1863
                        );
1864
1865
                        $report_info['progress_100'] = 100 == $progress ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1866
                        $report_info['progress'] = $progress."%";
1867
1868
                        foreach ($extra_fields as $extra) {
1869
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1870
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1871
                        }
1872
                        $report_info['user_id'] = $user['user_id'];
1873
                        $users[] = $report_info;
1874
                    }
1875
                } else {
1876
                    $users[$user['user_id']] = $user_info;
1877
                }
1878
            }
1879
        }
1880
1881
        return $users;
1882
    }
1883
1884
    /**
1885
     * @param bool  $resumed_report
1886
     * @param array $extra_field
1887
     * @param array $courseCodeList
1888
     * @param array $userIdList
1889
     * @param array $sessionIdList
1890
     * @param array $options
1891
     *
1892
     * @return array|int
1893
     */
1894
    public static function get_count_user_list_from_course_code(
1895
        $resumed_report = false,
1896
        $extra_field = [],
1897
        $courseCodeList = [],
1898
        $userIdList = [],
1899
        $sessionIdList = [],
1900
        $options = []
1901
    ) {
1902
        return self::get_user_list_from_course_code(
1903
            null,
1904
            0,
1905
            null,
1906
            null,
1907
            null,
1908
            true,
1909
            false,
1910
            $resumed_report,
1911
            $extra_field,
1912
            $courseCodeList,
1913
            $userIdList,
1914
            null,
1915
            $sessionIdList,
1916
            null,
1917
            $options
1918
        );
1919
    }
1920
1921
    /**
1922
     * Gets subscribed users in a course or in a course/session.
1923
     *
1924
     * @param string $course_code
1925
     * @param int    $session_id
1926
     *
1927
     * @return int
1928
     */
1929
    public static function get_users_count_in_course(
1930
        $course_code,
1931
        $session_id = 0,
1932
        $status = null
1933
    ) {
1934
        // variable initialisation
1935
        $session_id = (int) $session_id;
1936
        $course_code = Database::escape_string($course_code);
1937
        $tblUser = Database::get_main_table(TABLE_MAIN_USER);
1938
        $tblSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1939
        $tblCourseUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1940
        $tblUrlUser = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER);
1941
1942
        $courseInfo = api_get_course_info($course_code);
1943
        $courseId = $courseInfo['real_id'];
1944
1945
        $sql = "
1946
            SELECT DISTINCT count(user.id) as count
1947
            FROM $tblUser as user
1948
        ";
1949
        $where = [];
1950
        if (!empty($session_id)) {
1951
            $sql .= "
1952
                LEFT JOIN $tblSessionCourseUser as session_course_user
1953
                ON user.id = session_course_user.user_id
1954
                    AND session_course_user.c_id = $courseId
1955
                    AND session_course_user.session_id = $session_id
1956
            ";
1957
1958
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1959
        } else {
1960
            $sql .= "
1961
                LEFT JOIN $tblCourseUser as course_rel_user
1962
                    ON user.id = course_rel_user.user_id
1963
                    AND course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH."
1964
                    AND course_rel_user.c_id = $courseId
1965
            ";
1966
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1967
        }
1968
1969
        $multiple_access_url = api_get_multiple_access_url();
1970
        if ($multiple_access_url) {
1971
            $sql .= " LEFT JOIN $tblUrlUser au ON (au.user_id = user.id) ";
1972
        }
1973
1974
        $sql .= ' WHERE '.implode(' OR ', $where);
1975
1976
        if ($multiple_access_url) {
1977
            $current_access_url_id = api_get_current_access_url_id();
1978
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1979
        }
1980
        $rs = Database::query($sql);
1981
        $count = 0;
1982
        if (Database::num_rows($rs)) {
1983
            $user = Database::fetch_array($rs);
1984
            $count = $user['count'];
1985
        }
1986
1987
        return $count;
1988
    }
1989
1990
    /**
1991
     * Get a list of coaches of a course and a session.
1992
     *
1993
     * @param string $course_code
1994
     * @param int    $session_id
1995
     * @param bool   $addGeneralCoach
1996
     *
1997
     * @return array List of users
1998
     */
1999
    public static function get_coach_list_from_course_code(
2000
        $course_code,
2001
        $session_id,
2002
        $addGeneralCoach = true
2003
    ) {
2004
        if (empty($course_code) || empty($session_id)) {
2005
            return [];
2006
        }
2007
2008
        $course_code = Database::escape_string($course_code);
2009
        $courseInfo = api_get_course_info($course_code);
2010
        $courseId = $courseInfo['real_id'];
2011
        $session_id = (int) $session_id;
2012
        $users = [];
2013
2014
        // We get the coach for the given course in a given session.
2015
        $sql = 'SELECT user_id FROM '.Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER).
2016
               " WHERE session_id = $session_id AND c_id = $courseId AND status = 2";
2017
        $rs = Database::query($sql);
2018
        while ($user = Database::fetch_array($rs)) {
2019
            $userInfo = api_get_user_info($user['user_id']);
2020
            if ($userInfo) {
2021
                $users[$user['user_id']] = $userInfo;
2022
            }
2023
        }
2024
2025
        if ($addGeneralCoach) {
2026
            $table = Database::get_main_table(TABLE_MAIN_SESSION);
2027
            // We get the session coach.
2028
            $sql = "SELECT id_coach FROM $table WHERE id = $session_id";
2029
            $rs = Database::query($sql);
2030
            $session_id_coach = Database::result($rs, 0, 'id_coach');
2031
            if (is_int($session_id_coach)) {
2032
                $userInfo = api_get_user_info($session_id_coach);
2033
                if ($userInfo) {
2034
                    $users[$session_id_coach] = $userInfo;
2035
                }
2036
            }
2037
        }
2038
2039
        return $users;
2040
    }
2041
2042
    /**
2043
     *  Return user info array of all users registered in a course
2044
     *  This only returns the users that are registered in this actual course, not linked courses.
2045
     *
2046
     * @param string $course_code
2047
     * @param bool   $with_session
2048
     * @param int    $sessionId
2049
     * @param string $date_from
2050
     * @param string $date_to
2051
     * @param bool   $includeInvitedUsers Whether include the invited users
2052
     * @param int    $groupId
2053
     * @param bool   $getCount
2054
     * @param int    $start
2055
     * @param int    $limit
2056
     *
2057
     * @return array with user id
2058
     */
2059
    public static function get_student_list_from_course_code(
2060
        $course_code,
2061
        $with_session = false,
2062
        $sessionId = 0,
2063
        $date_from = null,
2064
        $date_to = null,
2065
        $includeInvitedUsers = true,
2066
        $groupId = 0,
2067
        $getCount = false,
2068
        $start = 0,
2069
        $limit = 0
2070
    ) {
2071
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
2072
        $sessionId = (int) $sessionId;
2073
        $courseInfo = api_get_course_info($course_code);
2074
        if (empty($courseInfo)) {
2075
            return [];
2076
        }
2077
        $courseId = $courseInfo['real_id'];
2078
        $students = [];
2079
2080
        $limitCondition = '';
2081
        if (isset($start) && isset($limit) && !empty($limit)) {
2082
            $start = (int) $start;
2083
            $limit = (int) $limit;
2084
            $limitCondition = " LIMIT $start, $limit";
2085
        }
2086
2087
        $select = '*';
2088
        if ($getCount) {
2089
            $select = 'count(u.id) as count';
2090
        }
2091
2092
        if (empty($sessionId)) {
2093
            if (empty($groupId)) {
2094
                // students directly subscribed to the course
2095
                $sql = "SELECT $select
2096
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2097
                        INNER JOIN $userTable u
2098
                        ON cu.user_id = u.id
2099
                        WHERE c_id = $courseId AND cu.status = ".STUDENT;
2100
2101
                if (!$includeInvitedUsers) {
2102
                    $sql .= " AND u.status != ".INVITEE;
2103
                }
2104
                $sql .= $limitCondition;
2105
                $rs = Database::query($sql);
2106
2107
                if ($getCount) {
2108
                    $row = Database::fetch_array($rs);
2109
2110
                    return (int) $row['count'];
2111
                }
2112
2113
                while ($student = Database::fetch_array($rs)) {
2114
                    $students[$student['user_id']] = $student;
2115
                }
2116
            } else {
2117
                $students = GroupManager::get_users(
2118
                    $groupId,
2119
                    false,
2120
                    $start,
2121
                    $limit,
2122
                    $getCount,
2123
                    $courseInfo['real_id']
2124
                );
2125
                $students = array_flip($students);
2126
            }
2127
        }
2128
2129
        // students subscribed to the course through a session
2130
        if ($with_session) {
2131
            $joinSession = '';
2132
            //Session creation date
2133
            if (!empty($date_from) && !empty($date_to)) {
2134
                $joinSession = "INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s";
2135
            }
2136
2137
            $sql = "SELECT $select
2138
                      FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
2139
                      $joinSession
2140
                      INNER JOIN $userTable u
2141
                      ON scu.user_id = u.id
2142
                      WHERE scu.c_id = $courseId AND scu.status <> 2";
2143
2144
            if (!empty($date_from) && !empty($date_to)) {
2145
                $date_from = Database::escape_string($date_from);
2146
                $date_to = Database::escape_string($date_to);
2147
                $sql .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
2148
            }
2149
2150
            if ($sessionId != 0) {
2151
                $sql .= " AND scu.session_id = $sessionId";
2152
            }
2153
2154
            if (!$includeInvitedUsers) {
2155
                $sql .= " AND u.status != ".INVITEE;
2156
            }
2157
            $sql .= $limitCondition;
2158
2159
            $rs = Database::query($sql);
2160
2161
            if ($getCount) {
2162
                $row = Database::fetch_array($rs);
2163
2164
                return (int) $row['count'];
2165
            }
2166
2167
            while ($student = Database::fetch_array($rs)) {
2168
                $students[$student['user_id']] = $student;
2169
            }
2170
        }
2171
2172
        return $students;
2173
    }
2174
2175
    /**
2176
     * Return user info array of all teacher-users registered in a course
2177
     * This only returns the users that are registered in this actual course, not linked courses.
2178
     *
2179
     * @param string $course_code
2180
     *
2181
     * @return array with user id
2182
     */
2183
    public static function get_teacher_list_from_course_code($course_code)
2184
    {
2185
        $courseInfo = api_get_course_info($course_code);
2186
        $courseId = $courseInfo['real_id'];
2187
        if (empty($courseId)) {
2188
            return false;
2189
        }
2190
2191
        $sql = "SELECT DISTINCT
2192
                    u.id as user_id,
2193
                    u.lastname,
2194
                    u.firstname,
2195
                    u.email,
2196
                    u.username,
2197
                    u.status
2198
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2199
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2200
                ON (cu.user_id = u.id)
2201
                WHERE
2202
                    cu.c_id = $courseId AND
2203
                    cu.status = 1 ";
2204
        $rs = Database::query($sql);
2205
        $teachers = [];
2206
        while ($teacher = Database::fetch_array($rs)) {
2207
            $teachers[$teacher['user_id']] = $teacher;
2208
        }
2209
2210
        return $teachers;
2211
    }
2212
2213
    /**
2214
     * Return user info array of all teacher-users registered in a course
2215
     * This only returns the users that are registered in this actual course, not linked courses.
2216
     *
2217
     * @param int  $courseId
2218
     * @param bool $loadAvatars
2219
     *
2220
     * @return array with user id
2221
     */
2222
    public static function getTeachersFromCourse($courseId, $loadAvatars = true)
2223
    {
2224
        $courseId = (int) $courseId;
2225
2226
        if (empty($courseId)) {
2227
            return false;
2228
        }
2229
2230
        $sql = "SELECT DISTINCT
2231
                    u.id as user_id,
2232
                    u.lastname,
2233
                    u.firstname,
2234
                    u.email,
2235
                    u.username,
2236
                    u.status
2237
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
2238
                INNER JOIN ".Database::get_main_table(TABLE_MAIN_USER)." u
2239
                ON (cu.user_id = u.id)
2240
                WHERE
2241
                    cu.c_id = $courseId AND
2242
                    cu.status = 1 ";
2243
        $rs = Database::query($sql);
2244
        $listTeachers = [];
2245
        $teachers = [];
2246
        $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&course_id='.$courseId;
2247
        while ($teacher = Database::fetch_array($rs)) {
2248
            $teachers['id'] = $teacher['user_id'];
2249
            $teachers['lastname'] = $teacher['lastname'];
2250
            $teachers['firstname'] = $teacher['firstname'];
2251
            $teachers['email'] = $teacher['email'];
2252
            $teachers['username'] = $teacher['username'];
2253
            $teachers['status'] = $teacher['status'];
2254
            $teachers['fullname'] = api_get_person_name($teacher['firstname'], $teacher['lastname']);
2255
            $teachers['avatar'] = '';
2256
            /*if ($loadAvatars) {
2257
                $userPicture = UserManager::getUserPicture($teacher['user_id'], USER_IMAGE_SIZE_SMALL);
2258
                $teachers['avatar'] = $userPicture;
2259
            }*/
2260
            $teachers['url'] = $url.'&user_id='.$teacher['user_id'];
2261
            $listTeachers[] = $teachers;
2262
        }
2263
2264
        return $listTeachers;
2265
    }
2266
2267
    /**
2268
     * Returns a string list of teachers assigned to the given course.
2269
     *
2270
     * @param string $course_code
2271
     * @param string $separator           between teachers names
2272
     * @param bool   $add_link_to_profile Whether to add a link to the teacher's profile
2273
     * @param bool   $orderList
2274
     *
2275
     * @return string List of teachers teaching the course
2276
     */
2277
    public static function getTeacherListFromCourseCodeToString(
2278
        $course_code,
2279
        $separator = self::USER_SEPARATOR,
2280
        $add_link_to_profile = false,
2281
        $orderList = false
2282
    ) {
2283
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
2284
        $html = '';
2285
        $list = [];
2286
        if (!empty($teacher_list)) {
2287
            foreach ($teacher_list as $teacher) {
2288
                $teacher_name = api_get_person_name(
2289
                    $teacher['firstname'],
2290
                    $teacher['lastname']
2291
                );
2292
                if ($add_link_to_profile) {
2293
                    $url = api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$teacher['user_id'];
2294
                    $teacher_name = Display::url(
2295
                        $teacher_name,
2296
                        $url,
2297
                        [
2298
                            'class' => 'ajax',
2299
                            'data-title' => $teacher_name,
2300
                        ]
2301
                    );
2302
                }
2303
                $list[] = $teacher_name;
2304
            }
2305
2306
            if (!empty($list)) {
2307
                if (true === $orderList) {
2308
                    $html .= '<ul class="user-teacher">';
2309
                    foreach ($list as $teacher) {
2310
                        $html .= '<li>';
2311
                        $html .= Display::return_icon('teacher.png', '', null, ICON_SIZE_TINY);
2312
                        $html .= ' '.$teacher;
2313
                        $html .= '</li>';
2314
                    }
2315
                    $html .= '</ul>';
2316
                } else {
2317
                    $html .= array_to_string($list, $separator);
2318
                }
2319
            }
2320
        }
2321
2322
        return $html;
2323
    }
2324
2325
    /**
2326
     * This function returns information about coachs from a course in session.
2327
     *
2328
     * @param int $session_id
2329
     * @param int $courseId
2330
     *
2331
     * @return array containing user_id, lastname, firstname, username
2332
     */
2333
    public static function get_coachs_from_course($session_id = 0, $courseId = 0)
2334
    {
2335
        if (!empty($session_id)) {
2336
            $session_id = intval($session_id);
2337
        } else {
2338
            $session_id = api_get_session_id();
2339
        }
2340
2341
        if (!empty($courseId)) {
2342
            $courseId = intval($courseId);
2343
        } else {
2344
            $courseId = api_get_course_int_id();
2345
        }
2346
2347
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2348
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2349
2350
        $sql = "SELECT DISTINCT
2351
                    u.id as user_id,
2352
                    u.lastname,
2353
                    u.firstname,
2354
                    u.username
2355
                FROM $tbl_user u
2356
                INNER JOIN $tbl_session_course_user scu
2357
                ON (u.id = scu.user_id)
2358
                WHERE
2359
                    scu.session_id = $session_id AND
2360
                    scu.c_id = $courseId AND
2361
                    scu.status = 2";
2362
        $rs = Database::query($sql);
2363
2364
        $coaches = [];
2365
        if (Database::num_rows($rs) > 0) {
2366
            while ($row = Database::fetch_array($rs)) {
2367
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
2368
                $coaches[] = $row + ['full_name' => $completeName];
2369
            }
2370
        }
2371
2372
        return $coaches;
2373
    }
2374
2375
    /**
2376
     * @param int    $session_id
2377
     * @param int    $courseId
2378
     * @param string $separator
2379
     * @param bool   $add_link_to_profile
2380
     * @param bool   $orderList
2381
     *
2382
     * @return string
2383
     */
2384
    public static function get_coachs_from_course_to_string(
2385
        $session_id = 0,
2386
        $courseId = 0,
2387
        $separator = self::USER_SEPARATOR,
2388
        $add_link_to_profile = false,
2389
        $orderList = false
2390
    ) {
2391
        $coachList = self::get_coachs_from_course($session_id, $courseId);
2392
        $course_coachs = [];
2393
        if (!empty($coachList)) {
2394
            foreach ($coachList as $coach_course) {
2395
                $coach_name = $coach_course['full_name'];
2396
                if ($add_link_to_profile) {
2397
                    $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;
2398
                    $coach_name = Display::url(
2399
                        $coach_name,
2400
                        $url,
2401
                        [
2402
                            'class' => 'ajax',
2403
                            'data-title' => $coach_name,
2404
                        ]
2405
                    );
2406
                }
2407
                $course_coachs[] = $coach_name;
2408
            }
2409
        }
2410
2411
        $html = '';
2412
        if (!empty($course_coachs)) {
2413
            if (true === $orderList) {
2414
                $html .= '<ul class="user-coachs">';
2415
                foreach ($course_coachs as $coachs) {
2416
                    $html .= Display::tag(
2417
                        'li',
2418
                        Display::return_icon(
2419
                            'teacher.png',
2420
                            get_lang('Coach'),
2421
                            null,
2422
                            ICON_SIZE_TINY
2423
                        ).' '.$coachs
2424
                    );
2425
                }
2426
                $html .= '</ul>';
2427
            } else {
2428
                $html = array_to_string($course_coachs, $separator);
2429
            }
2430
        }
2431
2432
        return $html;
2433
    }
2434
2435
    /**
2436
     * Get the list of groups from the course.
2437
     *
2438
     * @param string $course_code
2439
     * @param int    $session_id         Session ID (optional)
2440
     * @param int    $in_get_empty_group get empty groups (optional)
2441
     *
2442
     * @return array List of groups info
2443
     */
2444
    public static function get_group_list_of_course(
2445
        $course_code,
2446
        $session_id = 0,
2447
        $in_get_empty_group = 0
2448
    ) {
2449
        $course_info = api_get_course_info($course_code);
2450
2451
        if (empty($course_info)) {
2452
            return [];
2453
        }
2454
        $course_id = $course_info['real_id'];
2455
2456
        if (empty($course_id)) {
2457
            return [];
2458
        }
2459
2460
        0 != $session_id ? $session_condition = ' WHERE g.session_id IN(1,'.intval($session_id).')' : $session_condition = ' WHERE g.session_id = 0';
2461
        if (0 == $in_get_empty_group) {
2462
            // get only groups that are not empty
2463
            $sql = "SELECT DISTINCT g.id, g.iid, g.name
2464
                    FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2465
                    INNER JOIN ".Database::get_course_table(TABLE_GROUP_USER)." gu
2466
                    ON (g.id = gu.group_id AND g.c_id = $course_id AND gu.c_id = $course_id)
2467
                    $session_condition
2468
                    ORDER BY g.name";
2469
        } else {
2470
            // get all groups even if they are empty
2471
            $sql = "SELECT g.id, g.name, g.iid
2472
                    FROM ".Database::get_course_table(TABLE_GROUP)." AS g
2473
                    $session_condition
2474
                    AND c_id = $course_id";
2475
        }
2476
2477
        $result = Database::query($sql);
2478
        $groupList = [];
2479
        while ($groupData = Database::fetch_array($result)) {
2480
            $groupData['userNb'] = GroupManager::number_of_students($groupData['id'], $course_id);
2481
            $groupList[$groupData['iid']] = $groupData;
2482
        }
2483
2484
        return $groupList;
2485
    }
2486
2487
    /**
2488
     * Delete a course
2489
     * This function deletes a whole course-area from the platform. When the
2490
     * given course is a virtual course, the database and directory will not be
2491
     * deleted.
2492
     * When the given course is a real course, also all virtual courses refering
2493
     * to the given course will be deleted.
2494
     * Considering the fact that we remove all traces of the course in the main
2495
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2496
     * so that a new course created with this code would not use the remains of an older
2497
     * course.
2498
     *
2499
     * @param string $code The code of the course to delete
2500
     *
2501
     * @todo When deleting a virtual course: unsubscribe users from that virtual
2502
     * course from the groups in the real course if they are not subscribed in
2503
     * that real course.
2504
     */
2505
    public static function delete_course($code)
2506
    {
2507
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2508
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2509
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2510
        $table_course_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
2511
        $table_course_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
2512
        $table_course_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
2513
2514
        $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
2515
        $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2516
        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2517
        $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
2518
        $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2519
        $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2520
        $table_stats_online = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
2521
        $table_stats_downloads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
2522
        $table_stats_links = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
2523
        $table_stats_uploads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
2524
2525
        if (empty($code)) {
2526
            return false;
2527
        }
2528
2529
        $course = api_get_course_info($code);
2530
2531
        if (empty($course)) {
2532
            return false;
2533
        }
2534
2535
        $codeFiltered = $course['code'];
2536
        $courseId = $course['real_id'];
2537
        $courseEntity = api_get_course_entity($courseId);
2538
2539
        /** @var SequenceResourceRepository $repo */
2540
        $repo = Database::getManager()->getRepository('ChamiloCoreBundle:SequenceResource');
2541
        $sequenceResource = $repo->findRequirementForResource(
2542
            $courseId,
2543
            SequenceResource::COURSE_TYPE
2544
        );
2545
2546
        if ($sequenceResource) {
2547
            Display::addFlash(
2548
                Display::return_message(
2549
                    get_lang('ThereIsASequenceResourceLinkedToThisCourseYouNeedToDeleteItFirst'),
2550
                    'error'
2551
                )
2552
            );
2553
2554
            return false;
2555
        }
2556
2557
        $count = 0;
2558
        if (api_is_multiple_url_enabled()) {
2559
            $url_id = 1;
2560
            if (-1 != api_get_current_access_url_id()) {
2561
                $url_id = api_get_current_access_url_id();
2562
            }
2563
            UrlManager::delete_url_rel_course($courseId, $url_id);
2564
            $count = UrlManager::getCountUrlRelCourse($courseId);
2565
        }
2566
2567
        if (0 === $count) {
2568
            self::create_database_dump($code);
2569
2570
            // Cleaning group categories
2571
            $groupCategories = GroupManager::get_categories($course['code']);
2572
            if (!empty($groupCategories)) {
2573
                foreach ($groupCategories as $category) {
2574
                    GroupManager::delete_category($category['id'], $course['code']);
2575
                }
2576
            }
2577
2578
            // Cleaning groups
2579
            $groups = GroupManager::get_groups($courseId);
2580
            if (!empty($groups)) {
2581
                foreach ($groups as $group) {
2582
                    GroupManager::deleteGroup($group, $course['code']);
2583
                }
2584
            }
2585
2586
            $course_tables = AddCourse::get_course_tables();
2587
            // Cleaning c_x tables
2588
            if (!empty($courseId)) {
2589
                foreach ($course_tables as $table) {
2590
                    if ('document' === $table) {
2591
                        // Table document will be deleted by Doctrine.
2592
                        continue;
2593
                    }
2594
                    $table = Database::get_course_table($table);
2595
                    $sql = "DELETE FROM $table WHERE c_id = $courseId ";
2596
                    Database::query($sql);
2597
                }
2598
            }
2599
2600
            /*$course_dir = api_get_path(SYS_COURSE_PATH).$course['directory'];
2601
            $archive_dir = api_get_path(SYS_ARCHIVE_PATH).$course['directory'].'_'.time();
2602
            if (is_dir($course_dir)) {
2603
                rename($course_dir, $archive_dir);
2604
            }*/
2605
2606
            Category::deleteFromCourse($courseEntity);
2607
2608
            // Unsubscribe all users from the course
2609
            $sql = "DELETE FROM $table_course_user WHERE c_id = $courseId";
2610
            Database::query($sql);
2611
            // Delete the course from the sessions tables
2612
            $sql = "DELETE FROM $table_session_course WHERE c_id = $courseId";
2613
            Database::query($sql);
2614
            $sql = "DELETE FROM $table_session_course_user WHERE c_id = $courseId";
2615
            Database::query($sql);
2616
2617
            // Delete from Course - URL
2618
            // Already deleted because of entities.
2619
            //$sql = "DELETE FROM $table_course_rel_url WHERE c_id = $courseId";
2620
            //Database::query($sql);
2621
2622
            $sql = "SELECT survey_id FROM $table_course_survey WHERE course_code = '$codeFiltered'";
2623
            $result_surveys = Database::query($sql);
2624
            while ($surveys = Database::fetch_array($result_surveys)) {
2625
                $survey_id = $surveys[0]; //int
2626
                $sql = "DELETE FROM $table_course_survey_question WHERE survey_id = $survey_id";
2627
                Database::query($sql);
2628
                $sql = "DELETE FROM $table_course_survey_question_option WHERE survey_id = $survey_id";
2629
                Database::query($sql);
2630
                $sql = "DELETE FROM $table_course_survey WHERE survey_id = $survey_id";
2631
                Database::query($sql);
2632
            }
2633
2634
            // Delete the course from the stats tables
2635
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2636
            Database::query($sql);
2637
            $sql = "DELETE FROM $table_stats_attempt WHERE c_id = $courseId";
2638
            Database::query($sql);
2639
            $sql = "DELETE FROM $table_stats_exercises WHERE c_id = $courseId";
2640
            Database::query($sql);
2641
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2642
            Database::query($sql);
2643
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2644
            Database::query($sql);
2645
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2646
            Database::query($sql);
2647
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2648
            Database::query($sql);
2649
            // Do not delete rows from track_e_default as these include course
2650
            // creation and other important things that do not take much space
2651
            // but give information on the course history
2652
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2653
            //Database::query($sql);
2654
            $sql = "DELETE FROM $table_stats_downloads WHERE c_id = $courseId";
2655
            Database::query($sql);
2656
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2657
            Database::query($sql);
2658
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2659
            Database::query($sql);
2660
2661
            // Update ticket
2662
            $table = Database::get_main_table(TABLE_TICKET_TICKET);
2663
            $sql = "UPDATE $table SET course_id = NULL WHERE course_id = $courseId";
2664
            Database::query($sql);
2665
2666
            $repo->deleteResource(
2667
                $courseId,
2668
                SequenceResource::COURSE_TYPE
2669
            );
2670
2671
            // Class
2672
            $table = Database::get_main_table(TABLE_USERGROUP_REL_COURSE);
2673
            $sql = "DELETE FROM $table
2674
                    WHERE course_id = $courseId";
2675
            Database::query($sql);
2676
2677
            // Skills
2678
            $table = Database::get_main_table(TABLE_MAIN_SKILL_REL_USER);
2679
            $argumentation = Database::escape_string(sprintf(get_lang('This skill was obtained through course %s which has been removed since then.'), $course['code']));
2680
            $sql = "UPDATE $table SET course_id = NULL, session_id = NULL, argumentation = '$argumentation'
2681
                    WHERE course_id = $courseId";
2682
            Database::query($sql);
2683
2684
            $sql = "DELETE FROM skill_rel_course WHERE c_id = $courseId";
2685
            Database::query($sql);
2686
2687
            // Deletes all groups, group-users, group-tutors information
2688
            // To prevent fK mix up on some tables
2689
            GroupManager::deleteAllGroupsFromCourse($courseId);
2690
2691
            $appPlugin = new AppPlugin();
2692
            $appPlugin->performActionsWhenDeletingItem('course', $courseId);
2693
2694
            // Delete the course from the database
2695
            $repo = Container::getCourseRepository();
2696
            $repo->deleteCourse($courseEntity);
2697
2698
            // delete extra course fields
2699
            $extraFieldValues = new ExtraFieldValue('course');
2700
            $extraFieldValues->deleteValuesByItem($courseId);
2701
2702
            // Add event to system log
2703
            Event::addEvent(
2704
                LOG_COURSE_DELETE,
2705
                LOG_COURSE_CODE,
2706
                $code,
2707
                api_get_utc_datetime(),
2708
                api_get_user_id(),
2709
                $courseId
2710
            );
2711
2712
            return true;
2713
        }
2714
    }
2715
2716
    /**
2717
     * Creates a file called mysql_dump.sql in the course folder.
2718
     *
2719
     * @param string $course_code The code of the course
2720
     *
2721
     * @todo Implementation for single database
2722
     */
2723
    public static function create_database_dump($course_code)
2724
    {
2725
        return false;
2726
        $sql_dump = '';
0 ignored issues
show
Unused Code introduced by
$sql_dump = '' is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
2727
        $course_code = Database::escape_string($course_code);
2728
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
2729
        $sql = "SELECT * FROM $table_course WHERE code = '$course_code'";
2730
        $res = Database::query($sql);
2731
        $course = Database::fetch_array($res);
2732
2733
        $course_tables = AddCourse::get_course_tables();
2734
2735
        if (!empty($course['id'])) {
2736
            //Cleaning c_x tables
2737
            foreach ($course_tables as $table) {
2738
                $table = Database::get_course_table($table);
2739
                $sql = "SELECT * FROM $table WHERE c_id = {$course['id']} ";
2740
                $res_table = Database::query($sql);
2741
2742
                while ($row = Database::fetch_array($res_table, 'ASSOC')) {
2743
                    $row_to_save = [];
2744
                    foreach ($row as $key => $value) {
2745
                        $row_to_save[$key] = $key."='".Database::escape_string($row[$key])."'";
2746
                    }
2747
                    $sql_dump .= "\nINSERT INTO $table SET ".implode(', ', $row_to_save).';';
2748
                }
2749
            }
2750
        }
2751
2752
        if (is_dir(api_get_path(SYS_COURSE_PATH).$course['directory'])) {
2753
            $file_name = api_get_path(SYS_COURSE_PATH).$course['directory'].'/mysql_dump.sql';
2754
            $handle = fopen($file_name, 'a+');
2755
            if (false !== $handle) {
2756
                fwrite($handle, $sql_dump);
2757
                fclose($handle);
2758
            } else {
2759
                //TODO trigger exception in a try-catch
2760
            }
2761
        }
2762
    }
2763
2764
    /**
2765
     * Sort courses for a specific user ??
2766
     *
2767
     * @param int    $user_id     User ID
2768
     * @param string $course_code Course code
2769
     *
2770
     * @return int Minimum course order
2771
     *
2772
     * @todo Review documentation
2773
     */
2774
    public static function userCourseSort($user_id, $course_code)
2775
    {
2776
        if ($user_id != strval(intval($user_id))) {
2777
            return false;
2778
        }
2779
2780
        $course_code = Database::escape_string($course_code);
2781
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2782
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2783
2784
        $course_title = Database::result(
2785
            Database::query(
2786
                "SELECT title FROM $TABLECOURSE WHERE code = '$course_code'"
2787
            ),
2788
            0,
2789
            0
2790
        );
2791
        if (false === $course_title) {
2792
            $course_title = '';
2793
        }
2794
2795
        $sql = "SELECT course.code as code, course.title as title, cu.sort as sort
2796
                FROM $TABLECOURSUSER as cu, $TABLECOURSE as course
2797
                WHERE   course.id = cu.c_id AND user_id = $user_id AND
2798
                        cu.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2799
                        user_course_cat = 0
2800
                ORDER BY cu.sort";
2801
        $result = Database::query($sql);
2802
2803
        $course_title_precedent = '';
2804
        $counter = 0;
2805
        $course_found = false;
2806
        $course_sort = 1;
2807
2808
        if (Database::num_rows($result) > 0) {
2809
            while ($courses = Database::fetch_array($result)) {
2810
                if ('' == $course_title_precedent) {
2811
                    $course_title_precedent = $courses['title'];
2812
                }
2813
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2814
                    $course_found = true;
2815
                    if (!empty($courses['sort'])) {
2816
                        $course_sort = $courses['sort'];
2817
                    }
2818
                    if ($counter == 0) {
2819
                        $sql = "UPDATE $TABLECOURSUSER
2820
                                SET sort = sort+1
2821
                                WHERE
2822
                                    user_id= $user_id AND
2823
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH."
2824
                                    AND user_course_cat = 0
2825
                                    AND sort > $course_sort";
2826
                        $course_sort++;
2827
                    } else {
2828
                        $sql = "UPDATE $TABLECOURSUSER SET sort = sort+1
2829
                                WHERE
2830
                                    user_id= $user_id AND
2831
                                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
2832
                                    user_course_cat = 0 AND
2833
                                    sort >= $course_sort";
2834
                    }
2835
                    Database::query($sql);
2836
                    break;
2837
                } else {
2838
                    $course_title_precedent = $courses['title'];
2839
                }
2840
                $counter++;
2841
            }
2842
2843
            // We must register the course in the beginning of the list
2844
            if (!$course_found) {
2845
                $course_sort = Database::result(
2846
                    Database::query(
2847
                        'SELECT min(sort) as min_sort FROM '.$TABLECOURSUSER.' WHERE user_id = "'.$user_id.'" AND user_course_cat="0"'
2848
                    ),
2849
                    0,
2850
                    0
2851
                );
2852
                Database::query("UPDATE $TABLECOURSUSER SET sort = sort+1 WHERE user_id = $user_id AND user_course_cat = 0");
2853
            }
2854
        }
2855
2856
        return $course_sort;
2857
    }
2858
2859
    /**
2860
     * check if course exists.
2861
     *
2862
     * @param string $courseCode
2863
     *
2864
     * @return int if exists, false else
2865
     */
2866
    public static function course_exists($courseCode)
2867
    {
2868
        $courseCode = Database::escape_string($courseCode);
2869
        $sql = "SELECT 1 FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
2870
                WHERE code = '$courseCode'";
2871
2872
        return Database::num_rows(Database::query($sql));
2873
    }
2874
2875
    /**
2876
     * Send an email to tutor after the auth-suscription of a student in your course.
2877
     *
2878
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2879
     *
2880
     * @param int    $user_id            the id of the user
2881
     * @param string $courseId           the course code
2882
     * @param bool   $send_to_tutor_also
2883
     *
2884
     * @return false|null we return the message that is displayed when the action is successful
2885
     */
2886
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2887
    {
2888
        $user_id = (int) $user_id;
2889
        $courseId = (int) $courseId;
2890
        $information = api_get_course_info_by_id($courseId);
2891
        $course_code = $information['code'];
2892
        $student = api_get_user_info($user_id);
2893
2894
        $name_course = $information['title'];
2895
        $sql = "SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)."
2896
                WHERE c_id = $courseId";
2897
2898
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2899
        //if ($send_to_tutor_also = true)
2900
        // Proposed change:
2901
        if ($send_to_tutor_also) {
2902
            $sql .= ' AND is_tutor = 1';
2903
        } else {
2904
            $sql .= ' AND status = 1';
2905
        }
2906
2907
        $result = Database::query($sql);
2908
        while ($row = Database::fetch_array($result)) {
2909
            $tutor = api_get_user_info($row['user_id']);
2910
            $emailto = $tutor['email'];
2911
            $emailsubject = get_lang('New user in the course').': '.$name_course;
2912
            $emailbody = get_lang('Dear').': '.api_get_person_name($tutor['firstname'], $tutor['lastname'])."\n";
2913
            $emailbody .= get_lang('MessageNew user in the course').': '.$name_course."\n";
2914
            $emailbody .= get_lang('Username').': '.$student['username']."\n";
2915
            if (api_is_western_name_order()) {
2916
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2917
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2918
            } else {
2919
                $emailbody .= get_lang('Last name').': '.$student['lastname']."\n";
2920
                $emailbody .= get_lang('First name').': '.$student['firstname']."\n";
2921
            }
2922
            $emailbody .= get_lang('e-mail').': <a href="mailto:'.$student['email'].'">'.$student['email']."</a>\n\n";
2923
            $recipient_name = api_get_person_name(
2924
                $tutor['firstname'],
2925
                $tutor['lastname'],
2926
                null,
2927
                PERSON_NAME_EMAIL_ADDRESS
2928
            );
2929
            $sender_name = api_get_person_name(
2930
                api_get_setting('administratorName'),
2931
                api_get_setting('administratorSurname'),
2932
                null,
2933
                PERSON_NAME_EMAIL_ADDRESS
2934
            );
2935
            $email_admin = api_get_setting('emailAdministrator');
2936
2937
            $additionalParameters = [
2938
                'smsType' => SmsPlugin::NEW_USER_SUBSCRIBED_COURSE,
2939
                'userId' => $tutor['user_id'],
2940
                'userUsername' => $student['username'],
2941
                'courseCode' => $course_code,
2942
            ];
2943
            api_mail_html(
2944
                $recipient_name,
2945
                $emailto,
2946
                $emailsubject,
2947
                $emailbody,
2948
                $sender_name,
2949
                $email_admin,
2950
                null,
2951
                null,
2952
                null,
2953
                $additionalParameters
2954
            );
2955
        }
2956
    }
2957
2958
    /**
2959
     * @return array
2960
     */
2961
    public static function get_special_course_list()
2962
    {
2963
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
2964
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
2965
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
2966
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2967
2968
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2969
2970
        $courseList = [];
2971
        // get course list auto-register
2972
2973
        $sql = "SELECT id FROM $tbl_course_field
2974
                WHERE extra_field_type = $extraFieldType AND
2975
                variable = 'special_course'";
2976
        $result = Database::query($sql);
2977
        $courseList = [];
2978
2979
        if (Database::num_rows($result) > 0) {
2980
            $row = Database::fetch_assoc($result);
2981
            // Get list of special courses (appear to all)
2982
            // Note: The value is better indexed as string, so
2983
            // using '1' instead of integer is more efficient
2984
            $sql = "SELECT DISTINCT(item_id) as cid
2985
                FROM $tbl_course_field_value
2986
                WHERE field_id = ".$row['id']." AND value = '1'";
2987
            $result = Database::query($sql);
2988
            while ($row = Database::fetch_assoc($result)) {
2989
                $courseList[] = $row['cid'];
2990
            }
2991
            if (count($courseList) < 1) {
2992
                return $courseList;
2993
            }
2994
            if (api_get_multiple_access_url()) {
2995
                //we filter the courses by the active URL
2996
                $coursesSelect = '';
2997
                if (count($courseList) == 1) {
2998
                    $coursesSelect = $courseList[0];
2999
                } else {
3000
                    $coursesSelect = implode(',', $courseList);
3001
                }
3002
                $access_url_id = api_get_current_access_url_id();
3003
                if ($access_url_id != -1) {
3004
                    $sql = "SELECT c_id FROM $tbl_url_course
3005
                            WHERE access_url_id = $access_url_id
3006
                            AND c_id IN ($coursesSelect)";
3007
                    $result = Database::query($sql);
3008
                    while ($row = Database::fetch_assoc($result)) {
3009
                        $courseList[] = $row['c_id'];
3010
                    }
3011
                }
3012
            }
3013
        }
3014
3015
        return $courseList;
3016
    }
3017
3018
    /**
3019
     * Get the course codes that have been restricted in the catalogue, and if byUserId is set
3020
     * then the courses that the user is allowed or not to see in catalogue.
3021
     *
3022
     * @param bool $allowed  Either if the courses have some users that are or are not allowed to see in catalogue
3023
     * @param int  $byUserId if the courses are or are not allowed to see to the user
3024
     *
3025
     * @return array Course codes allowed or not to see in catalogue by some user or the user
3026
     */
3027
    public static function getCatalogCourseList($allowed = true, $byUserId = -1)
3028
    {
3029
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
3030
        $tblCourseRelUserCatalogue = Database::get_main_table(TABLE_MAIN_COURSE_CATALOGUE_USER);
3031
        $visibility = $allowed ? 1 : 0;
3032
3033
        // Restriction by user id
3034
        $currentUserRestriction = '';
3035
        if ($byUserId > 0) {
3036
            $byUserId = (int) $byUserId;
3037
            $currentUserRestriction = " AND tcruc.user_id = $byUserId ";
3038
        }
3039
3040
        //we filter the courses from the URL
3041
        $joinAccessUrl = '';
3042
        $whereAccessUrl = '';
3043
        if (api_get_multiple_access_url()) {
3044
            $accessUrlId = api_get_current_access_url_id();
3045
            if (-1 != $accessUrlId) {
3046
                $tblUrlCourse = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3047
                $joinAccessUrl = "LEFT JOIN $tblUrlCourse url_rel_course
3048
                                  ON url_rel_course.c_id = c.id ";
3049
                $whereAccessUrl = " AND access_url_id = $accessUrlId ";
3050
            }
3051
        }
3052
3053
        // get course list auto-register
3054
        $sql = "SELECT DISTINCT(c.code)
3055
                FROM $tblCourseRelUserCatalogue tcruc
3056
                INNER JOIN $courseTable c
3057
                ON (c.id = tcruc.c_id) $joinAccessUrl
3058
                WHERE tcruc.visible = $visibility $currentUserRestriction $whereAccessUrl";
3059
3060
        $result = Database::query($sql);
3061
        $courseList = [];
3062
3063
        if (Database::num_rows($result) > 0) {
3064
            while ($resultRow = Database::fetch_array($result)) {
3065
                $courseList[] = $resultRow['code'];
3066
            }
3067
        }
3068
3069
        return $courseList;
3070
    }
3071
3072
    /**
3073
     * Get list of courses for a given user.
3074
     *
3075
     * @param int   $user_id
3076
     * @param bool  $include_sessions                   Whether to include courses from session or not
3077
     * @param bool  $adminGetsAllCourses                If the user is platform admin,
3078
     *                                                  whether he gets all the courses or just his. Note: This does *not* include all sessions
3079
     * @param bool  $loadSpecialCourses
3080
     * @param array $skipCourseList                     List of course ids to skip
3081
     * @param bool  $useUserLanguageFilterIfAvailable
3082
     * @param bool  $showCoursesSessionWithDifferentKey
3083
     *
3084
     * @return array List of codes and db name
3085
     *
3086
     * @author isaac flores paz
3087
     */
3088
    public static function get_courses_list_by_user_id(
3089
        $user_id,
3090
        $include_sessions = false,
3091
        $adminGetsAllCourses = false,
3092
        $loadSpecialCourses = true,
3093
        $skipCourseList = [],
3094
        $useUserLanguageFilterIfAvailable = true,
3095
        $showCoursesSessionWithDifferentKey = false
3096
    ) {
3097
        $user_id = intval($user_id);
3098
        $urlId = api_get_current_access_url_id();
3099
        $course_list = [];
3100
        $codes = [];
3101
3102
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3103
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3104
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3105
        $tableCourseUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3106
        $tblCourseCategory = Database::get_main_table(TABLE_MAIN_CATEGORY);
3107
3108
        $languageCondition = '';
3109
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3110
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3111
            $userInfo = api_get_user_info(api_get_user_id());
3112
            if (!empty($userInfo['language'])) {
3113
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
3114
            }
3115
        }
3116
3117
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
3118
            // get the whole courses list
3119
            $sql = "SELECT DISTINCT(course.code), course.id as real_id, course.title
3120
                    FROM $tbl_course course
3121
                    INNER JOIN $tableCourseUrl url
3122
                    ON (course.id = url.c_id)
3123
                    WHERE
3124
                        url.access_url_id = $urlId
3125
                        $languageCondition
3126
                ";
3127
        } else {
3128
            $withSpecialCourses = $withoutSpecialCourses = '';
3129
3130
            if ($loadSpecialCourses) {
3131
                $specialCourseList = self::get_special_course_list();
3132
3133
                if (!empty($specialCourseList)) {
3134
                    $specialCourseToString = '"'.implode('","', $specialCourseList).'"';
3135
                    $withSpecialCourses = ' AND course.id IN ('.$specialCourseToString.')';
3136
                    $withoutSpecialCourses = ' AND course.id NOT IN ('.$specialCourseToString.')';
3137
                }
3138
3139
                if (!empty($withSpecialCourses)) {
3140
                    $sql = "SELECT DISTINCT (course.code),
3141
                            course.id as real_id,
3142
                            course_category.code AS category,
3143
                            course.title
3144
                            FROM $tbl_course_user course_rel_user
3145
                            LEFT JOIN $tbl_course course
3146
                            ON course.id = course_rel_user.c_id
3147
                            LEFT JOIN $tblCourseCategory ON course_category.id = course.category_id
3148
                            LEFT JOIN $tbl_user_course_category user_course_category
3149
                            ON course_rel_user.user_course_cat = user_course_category.id
3150
                            INNER JOIN $tableCourseUrl url
3151
                            ON (course.id = url.c_id)
3152
                            WHERE url.access_url_id = $urlId
3153
                            $withSpecialCourses
3154
                            $languageCondition
3155
                            GROUP BY course.code
3156
                            ORDER BY user_course_category.sort, course.title, course_rel_user.sort ASC
3157
                    ";
3158
                    $result = Database::query($sql);
3159
                    if (Database::num_rows($result) > 0) {
3160
                        while ($result_row = Database::fetch_array($result, 'ASSOC')) {
3161
                            $result_row['special_course'] = 1;
3162
                            $course_list[] = $result_row;
3163
                            $codes[] = $result_row['real_id'];
3164
                        }
3165
                    }
3166
                }
3167
            }
3168
3169
            // get course list not auto-register. Use Distinct to avoid multiple
3170
            // entries when a course is assigned to a HRD (DRH) as watcher
3171
            $sql = "SELECT
3172
                        DISTINCT(course.code),
3173
                        course.id as real_id,
3174
                        course.category_id AS category,
3175
                        course.title
3176
                    FROM $tbl_course course
3177
                    INNER JOIN $tbl_course_user cru
3178
                    ON (course.id = cru.c_id)
3179
                    INNER JOIN $tableCourseUrl url
3180
                    ON (course.id = url.c_id)
3181
                    WHERE
3182
                        url.access_url_id = $urlId AND
3183
                        cru.user_id = $user_id
3184
                        $withoutSpecialCourses
3185
                        $languageCondition
3186
                    ORDER BY course.title
3187
                    ";
3188
        }
3189
        $result = Database::query($sql);
3190
3191
        if (Database::num_rows($result)) {
3192
            while ($row = Database::fetch_array($result, 'ASSOC')) {
3193
                if (!empty($skipCourseList)) {
3194
                    if (in_array($row['real_id'], $skipCourseList)) {
3195
                        continue;
3196
                    }
3197
                }
3198
                $course_list[] = $row;
3199
                $codes[] = $row['real_id'];
3200
            }
3201
        }
3202
3203
        if (true === $include_sessions) {
3204
            $sql = "SELECT DISTINCT (c.code),
3205
                        c.id as real_id,
3206
                        c.category_code AS category,
3207
                        s.id as session_id,
3208
                        s.name as session_name
3209
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER)." scu
3210
                    INNER JOIN $tbl_course c
3211
                    ON (scu.c_id = c.id)
3212
                    INNER JOIN ".Database::get_main_table(TABLE_MAIN_SESSION)." s
3213
                    ON (s.id = scu.session_id)
3214
                    WHERE user_id = $user_id ";
3215
            $r = Database::query($sql);
3216
            while ($row = Database::fetch_array($r, 'ASSOC')) {
3217
                if (!empty($skipCourseList)) {
3218
                    if (in_array($row['real_id'], $skipCourseList)) {
3219
                        continue;
3220
                    }
3221
                }
3222
3223
                if ($showCoursesSessionWithDifferentKey) {
3224
                    $course_list[] = $row;
3225
                } else {
3226
                    if (!in_array($row['real_id'], $codes)) {
3227
                        $course_list[] = $row;
3228
                    }
3229
                }
3230
            }
3231
        }
3232
3233
        return $course_list;
3234
    }
3235
3236
    /**
3237
     * Get course ID from a given course directory name.
3238
     *
3239
     * @param string $path Course directory (without any slash)
3240
     *
3241
     * @return string Course code, or false if not found
3242
     */
3243
    public static function getCourseCodeFromDirectory($path)
3244
    {
3245
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
3246
        $res = Database::query("SELECT code FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
3247
                WHERE directory LIKE BINARY '$path'");
3248
        if (false === $res) {
3249
            return false;
3250
        }
3251
        if (1 != Database::num_rows($res)) {
3252
            return false;
3253
        }
3254
        $row = Database::fetch_array($res);
3255
3256
        return $row['code'];
3257
    }
3258
3259
    /**
3260
     * Get course code(s) from visual code.
3261
     *
3262
     * @deprecated
3263
     *
3264
     * @param   string  Visual code
3265
     *
3266
     * @return array List of codes for the given visual code
3267
     */
3268
    public static function get_courses_info_from_visual_code($code)
3269
    {
3270
        $result = [];
3271
        $sql_result = Database::query("SELECT * FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
3272
                WHERE visual_code = '".Database::escape_string($code)."'");
3273
        while ($virtual_course = Database::fetch_array($sql_result)) {
3274
            $result[] = $virtual_course;
3275
        }
3276
3277
        return $result;
3278
    }
3279
3280
    /**
3281
     * Creates a new extra field for a given course.
3282
     *
3283
     * @param string $variable    Field's internal variable name
3284
     * @param int    $fieldType   Field's type
3285
     * @param string $displayText Field's language var name
3286
     * @param string $default     Optional. The default value
3287
     *
3288
     * @return int New extra field ID
3289
     */
3290
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default = '')
3291
    {
3292
        $extraField = new ExtraField('course');
3293
        $params = [
3294
            'variable' => $variable,
3295
            'field_type' => $fieldType,
3296
            'display_text' => $displayText,
3297
            'default_value' => $default,
3298
        ];
3299
3300
        return $extraField->save($params);
3301
    }
3302
3303
    /**
3304
     * Update course attributes. Will only update attributes with a non-empty value.
3305
     * Note that you NEED to check that your attributes are valid before using this function.
3306
     *
3307
     * @param int Course id
3308
     * @param array Associative array with field names as keys and field values as values
3309
     *
3310
     * @return Doctrine\DBAL\Driver\Statement|null True if update was successful, false otherwise
3311
     */
3312
    public static function update_attributes($id, $attributes)
3313
    {
3314
        $id = (int) $id;
3315
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3316
        $sql = "UPDATE $table SET ";
3317
        $i = 0;
3318
        foreach ($attributes as $name => $value) {
3319
            if ('' != $value) {
3320
                if ($i > 0) {
3321
                    $sql .= ", ";
3322
                }
3323
                $sql .= " $name = '".Database::escape_string($value)."'";
3324
                $i++;
3325
            }
3326
        }
3327
        $sql .= " WHERE id = $id";
3328
3329
        return Database::query($sql);
3330
    }
3331
3332
    /**
3333
     * Update an extra field value for a given course.
3334
     *
3335
     * @param string $course_code Course code
3336
     * @param string $variable    Field variable name
3337
     * @param string $value       Optional. Default field value
3338
     *
3339
     * @return bool|int An integer when register a new extra field. And boolean when update the extrafield
3340
     */
3341
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
3342
    {
3343
        $courseInfo = api_get_course_info($course_code);
3344
        $courseId = $courseInfo['real_id'];
3345
3346
        $extraFieldValues = new ExtraFieldValue('course');
3347
        $params = [
3348
            'item_id' => $courseId,
3349
            'variable' => $variable,
3350
            'value' => $value,
3351
        ];
3352
3353
        return $extraFieldValues->save($params);
3354
    }
3355
3356
    /**
3357
     * @param int $sessionId
3358
     *
3359
     * @return mixed
3360
     */
3361
    public static function get_session_category_id_by_session_id($sessionId)
3362
    {
3363
        if (empty($sessionId)) {
3364
            return [];
3365
        }
3366
        $sessionId = intval($sessionId);
3367
        $sql = 'SELECT sc.id session_category
3368
                FROM '.Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY).' sc
3369
                INNER JOIN '.Database::get_main_table(TABLE_MAIN_SESSION).' s
3370
                ON sc.id = s.session_category_id
3371
                WHERE s.id = '.$sessionId;
3372
3373
        return Database::result(
3374
            Database::query($sql),
3375
            0,
3376
            'session_category'
3377
        );
3378
    }
3379
3380
    /**
3381
     * Gets the value of a course extra field. Returns null if it was not found.
3382
     *
3383
     * @param string $variable Name of the extra field
3384
     * @param string $code     Course code
3385
     *
3386
     * @return string Value
3387
     */
3388
    public static function get_course_extra_field_value($variable, $code)
3389
    {
3390
        $courseInfo = api_get_course_info($code);
3391
        $courseId = $courseInfo['real_id'];
3392
3393
        $extraFieldValues = new ExtraFieldValue('course');
3394
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($courseId, $variable);
3395
        if (!empty($result['value'])) {
3396
            return $result['value'];
3397
        }
3398
3399
        return null;
3400
    }
3401
3402
    /**
3403
     * Gets extra field value data and formatted values of a course
3404
     * for extra fields listed in configuration.php in my_course_course_extrafields_to_be_presented
3405
     * (array of variables as value of key 'fields').
3406
     *
3407
     * @param $courseId  int The numeric identifier of the course
3408
     *
3409
     * @return array of data and formatted values as returned by ExtraField::getDataAndFormattedValues
3410
     */
3411
    public static function getExtraFieldsToBePresented($courseId)
3412
    {
3413
        $extraFields = [];
3414
        $fields = api_get_configuration_sub_value('my_course_course_extrafields_to_be_presented/fields');
3415
        if (!empty($fields) && is_array($fields)) {
3416
            $extraFieldManager = new ExtraField('course');
3417
            $dataAndFormattedValues = $extraFieldManager->getDataAndFormattedValues($courseId);
3418
            foreach ($fields as $variable) {
3419
                foreach ($dataAndFormattedValues as $value) {
3420
                    if ($value['variable'] === $variable && !empty($value['value'])) {
3421
                        $extraFields[] = $value;
3422
                    }
3423
                }
3424
            }
3425
        }
3426
3427
        return $extraFields;
3428
    }
3429
3430
    /**
3431
     * Lists details of the course description.
3432
     *
3433
     * @param array        The course description
3434
     * @param string    The encoding
3435
     * @param bool        If true is displayed if false is hidden
3436
     *
3437
     * @return string The course description in html
3438
     */
3439
    public static function get_details_course_description_html(
3440
        $descriptions,
3441
        $charset,
3442
        $action_show = true
3443
    ) {
3444
        $data = null;
3445
        if (isset($descriptions) && count($descriptions) > 0) {
3446
            foreach ($descriptions as $description) {
3447
                $data .= '<div class="sectiontitle">';
3448
                if (api_is_allowed_to_edit() && $action_show) {
3449
                    //delete
3450
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&action=delete&description_id='.$description->id.'" onclick="javascript:if(!confirm(\''.addslashes(api_htmlentities(
3451
                        get_lang('Please confirm your choice'),
3452
                                ENT_QUOTES,
3453
                        $charset
3454
                    )).'\')) return false;">';
3455
                    $data .= Display::return_icon(
3456
                        'delete.gif',
3457
                        get_lang('Delete'),
3458
                        ['style' => 'vertical-align:middle;float:right;']
3459
                    );
3460
                    $data .= '</a> ';
3461
                    //edit
3462
                    $data .= '<a href="'.api_get_self().'?'.api_get_cidreq().'&description_id='.$description->id.'">';
3463
                    $data .= Display::return_icon(
3464
                        'edit.png',
3465
                        get_lang('Edit'),
3466
                        ['style' => 'vertical-align:middle;float:right; padding-right:4px;'],
3467
                        ICON_SIZE_SMALL
3468
                    );
3469
                    $data .= '</a> ';
3470
                }
3471
                $data .= $description->title;
3472
                $data .= '</div>';
3473
                $data .= '<div class="sectioncomment">';
3474
                $data .= Security::remove_XSS($description->content);
3475
                $data .= '</div>';
3476
            }
3477
        } else {
3478
            $data .= '<em>'.get_lang('There is no course description so far.').'</em>';
3479
        }
3480
3481
        return $data;
3482
    }
3483
3484
    /**
3485
     * Returns the details of a course category.
3486
     *
3487
     * @param string $code Category code
3488
     *
3489
     * @return array Course category
3490
     */
3491
    public static function get_course_category($code)
3492
    {
3493
        $table = Database::get_main_table(TABLE_MAIN_CATEGORY);
3494
        $code = Database::escape_string($code);
3495
        $sql = "SELECT * FROM $table WHERE code = '$code'";
3496
3497
        return Database::fetch_array(Database::query($sql));
3498
    }
3499
3500
    /**
3501
     * Subscribes courses to human resource manager (Dashboard feature).
3502
     *
3503
     * @param int   $hr_manager_id Human Resource Manager id
3504
     * @param array $courses_list  Courses code
3505
     *
3506
     * @return int
3507
     */
3508
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
3509
    {
3510
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3511
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3512
3513
        $hr_manager_id = intval($hr_manager_id);
3514
        $affected_rows = 0;
3515
3516
        //Deleting assigned courses to hrm_id
3517
        if (api_is_multiple_url_enabled()) {
3518
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
3519
                    INNER JOIN $tbl_course_rel_access_url a
3520
                    ON (a.c_id = s.c_id)
3521
                    WHERE
3522
                        user_id = $hr_manager_id AND
3523
                        relation_type = ".COURSE_RELATION_TYPE_RRHH." AND
3524
                        access_url_id = ".api_get_current_access_url_id();
3525
        } else {
3526
            $sql = "SELECT c_id FROM $tbl_course_rel_user
3527
                    WHERE user_id = $hr_manager_id AND relation_type = ".COURSE_RELATION_TYPE_RRHH;
3528
        }
3529
        $result = Database::query($sql);
3530
        if (Database::num_rows($result) > 0) {
3531
            while ($row = Database::fetch_array($result)) {
3532
                $sql = "DELETE FROM $tbl_course_rel_user
3533
                        WHERE
3534
                            c_id = {$row['c_id']} AND
3535
                            user_id = $hr_manager_id AND
3536
                            relation_type = ".COURSE_RELATION_TYPE_RRHH;
3537
                Database::query($sql);
3538
            }
3539
        }
3540
3541
        // inserting new courses list
3542
        if (is_array($courses_list)) {
3543
            foreach ($courses_list as $course_code) {
3544
                $courseInfo = api_get_course_info($course_code);
3545
                $courseId = $courseInfo['real_id'];
3546
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
3547
                        VALUES($courseId, $hr_manager_id, ".DRH.", ".COURSE_RELATION_TYPE_RRHH.")";
3548
                $result = Database::query($sql);
3549
                if (Database::affected_rows($result)) {
3550
                    $affected_rows++;
3551
                }
3552
            }
3553
        }
3554
3555
        return $affected_rows;
3556
    }
3557
3558
    /**
3559
     * get courses followed by human resources manager.
3560
     *
3561
     * @param int    $user_id
3562
     * @param int    $status
3563
     * @param int    $from
3564
     * @param int    $limit
3565
     * @param string $column
3566
     * @param string $direction
3567
     * @param bool   $getCount
3568
     *
3569
     * @return array courses
3570
     */
3571
    public static function get_courses_followed_by_drh(
3572
        $user_id,
3573
        $status = DRH,
3574
        $from = null,
3575
        $limit = null,
3576
        $column = null,
3577
        $direction = null,
3578
        $getCount = false
3579
    ) {
3580
        return self::getCoursesFollowedByUser(
3581
            $user_id,
3582
            $status,
3583
            $from,
3584
            $limit,
3585
            $column,
3586
            $direction,
3587
            $getCount
3588
        );
3589
    }
3590
3591
    /**
3592
     * get courses followed by user.
3593
     *
3594
     * @param int    $user_id
3595
     * @param int    $status
3596
     * @param int    $from
3597
     * @param int    $limit
3598
     * @param string $column
3599
     * @param string $direction
3600
     * @param bool   $getCount
3601
     * @param string $keyword
3602
     * @param int    $sessionId
3603
     * @param bool   $showAllAssignedCourses
3604
     *
3605
     * @return array courses
3606
     */
3607
    public static function getCoursesFollowedByUser(
3608
        $user_id,
3609
        $status = null,
3610
        $from = null,
3611
        $limit = null,
3612
        $column = null,
3613
        $direction = null,
3614
        $getCount = false,
3615
        $keyword = null,
3616
        $sessionId = 0,
3617
        $showAllAssignedCourses = false
3618
    ) {
3619
        // Database Table Definitions
3620
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3621
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3622
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3623
        $sessionId = (int) $sessionId;
3624
        $user_id = (int) $user_id;
3625
        $select = "SELECT DISTINCT c.*, c.id as real_id ";
3626
3627
        if ($getCount) {
3628
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3629
        }
3630
3631
        $whereConditions = '';
3632
        switch ($status) {
3633
            case COURSEMANAGER:
3634
                $whereConditions .= " AND cru.user_id = $user_id";
3635
                if (!$showAllAssignedCourses) {
3636
                    $whereConditions .= " AND cru.status = ".COURSEMANAGER;
3637
                } else {
3638
                    $whereConditions .= " AND relation_type = ".COURSE_RELATION_TYPE_COURSE_MANAGER;
3639
                }
3640
                break;
3641
            case DRH:
3642
                $whereConditions .= " AND
3643
                    cru.user_id = $user_id AND
3644
                    cru.status = ".DRH." AND
3645
                    relation_type = '".COURSE_RELATION_TYPE_RRHH."'
3646
                ";
3647
                break;
3648
        }
3649
3650
        $keywordCondition = null;
3651
        if (!empty($keyword)) {
3652
            $keyword = Database::escape_string($keyword);
3653
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3654
        }
3655
3656
        $orderBy = null;
3657
        $extraInnerJoin = null;
3658
3659
        if (!empty($sessionId)) {
3660
            if (COURSEMANAGER == $status) {
3661
                // Teacher of course or teacher inside session
3662
                $whereConditions = " AND (cru.status = ".COURSEMANAGER." OR srcru.status = 2) ";
3663
            }
3664
            $courseList = SessionManager::get_course_list_by_session_id($sessionId);
3665
            if (!empty($courseList)) {
3666
                $courseListToString = implode("','", array_keys($courseList));
3667
                $whereConditions .= " AND c.id IN ('".$courseListToString."')";
3668
            }
3669
            $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3670
            $tableSessionRelCourseRelUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
3671
            $orderBy = ' ORDER BY position';
3672
            $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3673
                                ON (c.id = src.c_id AND src.session_id = $sessionId)
3674
                                INNER JOIN $tableSessionRelCourseRelUser srcru
3675
                                ON (src.session_id = srcru.session_id AND srcru.c_id = src.c_id)
3676
                            ";
3677
        }
3678
3679
        $whereConditions .= $keywordCondition;
3680
        $sql = "$select
3681
                FROM $tbl_course c
3682
                INNER JOIN $tbl_course_rel_user cru
3683
                ON (cru.c_id = c.id)
3684
                INNER JOIN $tbl_course_rel_access_url a
3685
                ON (a.c_id = c.id)
3686
                $extraInnerJoin
3687
                WHERE
3688
                    access_url_id = ".api_get_current_access_url_id()."
3689
                    $whereConditions
3690
                $orderBy
3691
                ";
3692
        if (isset($from) && isset($limit)) {
3693
            $from = intval($from);
3694
            $limit = intval($limit);
3695
            $sql .= " LIMIT $from, $limit";
3696
        }
3697
3698
        $result = Database::query($sql);
3699
3700
        if ($getCount) {
3701
            $row = Database::fetch_array($result);
3702
3703
            return $row['count'];
3704
        }
3705
3706
        $courses = [];
3707
        if (Database::num_rows($result) > 0) {
3708
            while ($row = Database::fetch_array($result)) {
3709
                $courses[$row['code']] = $row;
3710
            }
3711
        }
3712
3713
        return $courses;
3714
    }
3715
3716
    /**
3717
     * check if a course is special (autoregister).
3718
     *
3719
     * @param int $courseId
3720
     *
3721
     * @return bool
3722
     */
3723
    public static function isSpecialCourse($courseId)
3724
    {
3725
        $extraFieldValue = new ExtraFieldValue('course');
3726
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3727
            $courseId,
3728
            'special_course'
3729
        );
3730
3731
        if (!empty($result)) {
3732
            if (1 == $result['value']) {
3733
                return true;
3734
            }
3735
        }
3736
3737
        return false;
3738
    }
3739
3740
    /**
3741
     * Display special courses (and only these) as several HTML divs of class userportal-course-item.
3742
     *
3743
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3744
     * in the sense that any user clicking them is registered as a student
3745
     *
3746
     * @param int  $user_id                          User id
3747
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3748
     * @param bool $useUserLanguageFilterIfAvailable
3749
     *
3750
     * @return array
3751
     */
3752
    public static function returnSpecialCourses(
3753
        $user_id,
3754
        $load_dirs = false,
3755
        $useUserLanguageFilterIfAvailable = true
3756
    ) {
3757
        $user_id = (int) $user_id;
3758
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
3759
        $specialCourseList = self::get_special_course_list();
3760
3761
        if (empty($specialCourseList)) {
3762
            return [];
3763
        }
3764
3765
        // Filter by language
3766
        $languageCondition = '';
3767
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
3768
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
3769
            $userInfo = api_get_user_info(api_get_user_id());
3770
            if (!empty($userInfo['language'])) {
3771
                $languageCondition = " AND course_language = '".$userInfo['language']."' ";
3772
            }
3773
        }
3774
3775
        $sql = "SELECT
3776
                    id,
3777
                    code,
3778
                    subscribe subscr,
3779
                    unsubscribe unsubscr
3780
                FROM $table
3781
                WHERE
3782
                    id IN ('".implode("','", $specialCourseList)."')
3783
                    $languageCondition
3784
                GROUP BY code";
3785
3786
        $rs_special_course = Database::query($sql);
3787
        $number_of_courses = Database::num_rows($rs_special_course);
3788
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3789
3790
        $courseList = [];
3791
        if ($number_of_courses > 0) {
3792
            while ($course = Database::fetch_array($rs_special_course)) {
3793
                $course_info = api_get_course_info($course['code']);
3794
                $courseId = $course_info['real_id'];
3795
                if (COURSE_VISIBILITY_HIDDEN == $course_info['visibility']) {
3796
                    continue;
3797
                }
3798
3799
                $params = [];
3800
                //Param (course_code) needed to get the student info in page "My courses"
3801
                $params['course_code'] = $course['code'];
3802
                $params['code'] = $course['code'];
3803
                // Get notifications.
3804
                $course_info['id_session'] = null;
3805
                $courseUserInfo = self::getUserCourseInfo($user_id, $courseId);
3806
3807
                if (empty($courseUserInfo)) {
3808
                    $course_info['status'] = STUDENT;
3809
                } else {
3810
                    $course_info['status'] = $courseUserInfo['status'];
3811
                }
3812
                $show_notification = !api_get_configuration_value('hide_course_notification')
3813
                    ? Display::show_notification($course_info)
3814
                    : '';
3815
                $params['edit_actions'] = '';
3816
                $params['document'] = '';
3817
                if (api_is_platform_admin()) {
3818
                    $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'];
3819
                    if ($load_dirs) {
3820
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3821
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3822
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3823
                    }
3824
                } else {
3825
                    if (COURSE_VISIBILITY_CLOSED != $course_info['visibility'] && $load_dirs) {
3826
                        $params['document'] = '<a id="document_preview_'.$courseId.'_0" class="document_preview btn btn-outline-secondary btn-sm" href="javascript:void(0);">'
3827
                           .Display::returnFontAwesomeIcon('folder-open').'</a>';
3828
                        $params['document'] .= Display::div('', ['id' => 'document_result_'.$courseId.'_0', 'class' => 'document_preview_container']);
3829
                    }
3830
                }
3831
3832
                $params['visibility'] = $course_info['visibility'];
3833
                $params['status'] = $course_info['status'];
3834
                $params['category'] = $course_info['categoryName'];
3835
                $params['category_code'] = $course_info['categoryCode'];
3836
                $params['icon'] = Display::return_icon(
3837
                    'drawing-pin.png',
3838
                    null,
3839
                    null,
3840
                    ICON_SIZE_LARGE,
3841
                    null
3842
                );
3843
3844
                if ('true' == api_get_setting('display_coursecode_in_courselist')) {
3845
                    $params['code_course'] = '('.$course_info['visual_code'].')';
3846
                }
3847
3848
                $params['title'] = $course_info['title'];
3849
                $params['title_cut'] = $course_info['title'];
3850
                $params['link'] = $course_info['course_public_url'].'?sid=0&autoreg=1';
3851
                if ('true' === api_get_setting('display_teacher_in_courselist')) {
3852
                    $params['teachers'] = self::getTeachersFromCourse(
3853
                        $courseId,
3854
                        true
3855
                    );
3856
                }
3857
3858
                $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
3859
3860
                if ($showCustomIcon === 'true') {
3861
                    $params['thumbnails'] = $course_info['course_image'];
3862
                    $params['image'] = $course_info['course_image_large'];
3863
                }
3864
3865
                if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
3866
                    $params['notifications'] = $show_notification;
3867
                }
3868
3869
                $params['is_special_course'] = true;
3870
                $courseList[] = $params;
3871
            }
3872
        }
3873
3874
        return $courseList;
3875
    }
3876
3877
    /**
3878
     * Display courses (without special courses) as several HTML divs
3879
     * of course categories, as class userportal-catalog-item.
3880
     *
3881
     * @uses \displayCoursesInCategory() to display the courses themselves
3882
     *
3883
     * @param int  $user_id
3884
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3885
     * @param bool $useUserLanguageFilterIfAvailable
3886
     *
3887
     * @return array
3888
     */
3889
    public static function returnCourses(
3890
        $user_id,
3891
        $load_dirs = false,
3892
        $useUserLanguageFilterIfAvailable = true
3893
    ) {
3894
        $user_id = (int) $user_id;
3895
        if (empty($user_id)) {
3896
            $user_id = api_get_user_id();
3897
        }
3898
        // Step 1: We get all the categories of the user
3899
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3900
        $sql = "SELECT * FROM $table
3901
                WHERE user_id = $user_id
3902
                ORDER BY sort ASC";
3903
3904
        $result = Database::query($sql);
3905
        $listItems = [
3906
            'in_category' => [],
3907
            'not_category' => [],
3908
        ];
3909
        $collapsable = api_get_configuration_value('allow_user_course_category_collapsable');
3910
        $stok = Security::get_existing_token();
3911
        while ($row = Database::fetch_array($result)) {
3912
            // We simply display the title of the category.
3913
            $courseInCategory = self::returnCoursesCategories(
3914
                $row['id'],
3915
                $load_dirs,
3916
                $user_id,
3917
                $useUserLanguageFilterIfAvailable
3918
            );
3919
3920
            $collapsed = 0;
3921
            $collapsableLink = '';
3922
            if ($collapsable) {
3923
                $url = api_get_path(WEB_CODE_PATH).
3924
                    'auth/sort_my_courses.php?categoryid='.$row['id'].'&sec_token='.$stok.'&redirect=home';
3925
                $collapsed = isset($row['collapsed']) && $row['collapsed'] ? 1 : 0;
3926
                if (0 === $collapsed) {
3927
                    $collapsableLink = Display::url(
3928
                        '<i class="fa fa-folder-open"></i>',
3929
                        $url.'&action=set_collapsable&option=1'
3930
                    );
3931
                } else {
3932
                    $collapsableLink = Display::url(
3933
                        '<i class="fa fa-folder"></i>',
3934
                        $url.'&action=set_collapsable&option=0'
3935
                    );
3936
                }
3937
            }
3938
3939
            $params = [
3940
                'id_category' => $row['id'],
3941
                'title_category' => $row['title'],
3942
                'collapsed' => $collapsed,
3943
                'collapsable_link' => $collapsableLink,
3944
                'courses' => $courseInCategory,
3945
            ];
3946
            $listItems['in_category'][] = $params;
3947
        }
3948
3949
        // Step 2: We display the course without a user category.
3950
        $coursesNotCategory = self::returnCoursesCategories(
3951
            0,
3952
            $load_dirs,
3953
            $user_id,
3954
            $useUserLanguageFilterIfAvailable
3955
        );
3956
3957
        if ($coursesNotCategory) {
3958
            $listItems['not_category'] = $coursesNotCategory;
3959
        }
3960
3961
        return $listItems;
3962
    }
3963
3964
    /**
3965
     *  Display courses inside a category (without special courses) as HTML dics of
3966
     *  class userportal-course-item.
3967
     *
3968
     * @param int  $user_category_id                 User category id
3969
     * @param bool $load_dirs                        Whether to show the document quick-loader or not
3970
     * @param int  $user_id
3971
     * @param bool $useUserLanguageFilterIfAvailable
3972
     *
3973
     * @return array
3974
     */
3975
    public static function returnCoursesCategories(
3976
        $user_category_id,
3977
        $load_dirs = false,
3978
        $user_id = 0,
3979
        $useUserLanguageFilterIfAvailable = true
3980
    ) {
3981
        $user_id = $user_id ? (int) $user_id : api_get_user_id();
3982
        $user_category_id = (int) $user_category_id;
3983
3984
        // Table definitions
3985
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
3986
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3987
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3988
        $current_url_id = api_get_current_access_url_id();
3989
3990
        // Get course list auto-register
3991
        $special_course_list = self::get_special_course_list();
3992
        $without_special_courses = '';
3993
        if (!empty($special_course_list)) {
3994
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
3995
        }
3996
3997
        $userCategoryCondition = " (course_rel_user.user_course_cat = $user_category_id) ";
3998
        if (empty($user_category_id)) {
3999
            $userCategoryCondition = ' (course_rel_user.user_course_cat = 0 OR course_rel_user.user_course_cat IS NULL) ';
4000
        }
4001
4002
        $languageCondition = '';
4003
        $onlyInUserLanguage = api_get_configuration_value('my_courses_show_courses_in_user_language_only');
4004
        if ($useUserLanguageFilterIfAvailable && $onlyInUserLanguage) {
4005
            $userInfo = api_get_user_info(api_get_user_id());
4006
            if (!empty($userInfo['language'])) {
4007
                $languageCondition = " AND course.course_language = '".$userInfo['language']."' ";
4008
            }
4009
        }
4010
4011
        $sql = "SELECT DISTINCT
4012
                    course.id,
4013
                    course_rel_user.status status,
4014
                    course.code as course_code,
4015
                    user_course_cat,
4016
                    course_rel_user.sort
4017
                FROM $TABLECOURS course
4018
                INNER JOIN $TABLECOURSUSER course_rel_user
4019
                ON (course.id = course_rel_user.c_id)
4020
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
4021
                ON (url.c_id = course.id)
4022
                WHERE
4023
                    course_rel_user.user_id = $user_id AND
4024
                    $userCategoryCondition
4025
                    $without_special_courses
4026
                    $languageCondition
4027
                ";
4028
        // If multiple URL access mode is enabled, only fetch courses
4029
        // corresponding to the current URL.
4030
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
4031
            $sql .= " AND access_url_id = $current_url_id";
4032
        }
4033
        // Use user's classification for courses (if any).
4034
        $sql .= ' ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC';
4035
        $result = Database::query($sql);
4036
4037
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
4038
        // Browse through all courses.
4039
        $courseAdded = [];
4040
        $courseList = [];
4041
4042
        while ($row = Database::fetch_array($result)) {
4043
            $course_info = api_get_course_info_by_id($row['id']);
4044
            if (empty($course_info)) {
4045
                continue;
4046
            }
4047
4048
            if (isset($course_info['visibility']) &&
4049
                COURSE_VISIBILITY_HIDDEN == $course_info['visibility']
4050
            ) {
4051
                continue;
4052
            }
4053
4054
            // Skip if already in list
4055
            if (in_array($course_info['real_id'], $courseAdded)) {
4056
                continue;
4057
            }
4058
            $course_info['id_session'] = null;
4059
            $course_info['status'] = $row['status'];
4060
            // For each course, get if there is any notification icon to show
4061
            // (something that would have changed since the user's last visit).
4062
            $showNotification = !api_get_configuration_value('hide_course_notification')
4063
                ? Display::show_notification($course_info)
4064
                : '';
4065
            $iconName = basename($course_info['course_image']);
4066
4067
            $params = [];
4068
            //Param (course_code) needed to get the student process
4069
            $params['course_code'] = $row['course_code'];
4070
            $params['code'] = $row['course_code'];
4071
4072
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
4073
                $params['thumbnails'] = $course_info['course_image'];
4074
                $params['image'] = $course_info['course_image_large'];
4075
            }
4076
4077
            $thumbnails = null;
4078
            $image = null;
4079
            if ('true' === $showCustomIcon && 'course.png' != $iconName) {
4080
                $thumbnails = $course_info['course_image'];
4081
                $image = $course_info['course_image_large'];
4082
            } else {
4083
                $image = Display::return_icon(
4084
                    'session_default.png',
4085
                    null,
4086
                    null,
4087
                    null,
4088
                    null,
4089
                    true
4090
                );
4091
            }
4092
4093
            $params['course_id'] = $course_info['real_id'];
4094
            $params['edit_actions'] = '';
4095
            $params['document'] = '';
4096
            if (api_is_platform_admin()) {
4097
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course_info['real_id'];
4098
                if ($load_dirs) {
4099
                    $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
4100
                               .Display::returnFontAwesomeIcon('folder-open').'</a>';
4101
                    $params['document'] .= Display::div(
4102
                        '',
4103
                        [
4104
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
4105
                            'class' => 'document_preview_container',
4106
                        ]
4107
                    );
4108
                }
4109
            }
4110
            if ($load_dirs) {
4111
                $params['document'] = '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview btn btn-default btn-sm" href="javascript:void(0);">'
4112
                    .Display::returnFontAwesomeIcon('folder-open').'</a>';
4113
                $params['document'] .= Display::div(
4114
                    '',
4115
                    [
4116
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
4117
                        'class' => 'document_preview_container',
4118
                    ]
4119
                );
4120
            }
4121
4122
            $courseUrl = $course_info['course_public_url'].'?sid=0';
4123
            $teachers = [];
4124
            if ('true' === api_get_setting('display_teacher_in_courselist')) {
4125
                $teachers = self::getTeachersFromCourse(
4126
                    $course_info['real_id'],
4127
                    true
4128
                );
4129
            }
4130
4131
            $params['status'] = $row['status'];
4132
            if ('true' === api_get_setting('display_coursecode_in_courselist')) {
4133
                $params['code_course'] = '('.$course_info['visual_code'].') ';
4134
            }
4135
4136
            $params['current_user_is_teacher'] = false;
4137
            /** @var array $teacher */
4138
            foreach ($teachers as $teacher) {
4139
                if ($teacher['id'] != $user_id) {
4140
                    continue;
4141
                }
4142
                $params['current_user_is_teacher'] = true;
4143
            }
4144
4145
            $params['visibility'] = $course_info['visibility'];
4146
            $params['link'] = $courseUrl;
4147
            $params['thumbnails'] = $thumbnails;
4148
            $params['image'] = $image;
4149
            $params['title'] = $course_info['title'];
4150
            $params['title_cut'] = $params['title'];
4151
            $params['category'] = $course_info['categoryName'];
4152
            $params['category_code'] = $course_info['categoryCode'];
4153
            $params['teachers'] = $teachers;
4154
            $params['extrafields'] = CourseManager::getExtraFieldsToBePresented($course_info['real_id']);
4155
            $params['real_id'] = $course_info['real_id'];
4156
4157
            if (api_get_configuration_value('enable_unsubscribe_button_on_my_course_page')
4158
                && '1' === $course_info['unsubscribe']
4159
            ) {
4160
                $params['unregister_button'] = CoursesAndSessionsCatalog::return_unregister_button(
4161
                    $course_info,
4162
                    Security::get_existing_token(),
4163
                    '',
4164
                    ''
4165
                );
4166
            }
4167
4168
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
4169
                $params['notifications'] = $showNotification;
4170
            }
4171
            $courseAdded[] = $course_info['real_id'];
4172
            $courseList[] = $params;
4173
        }
4174
4175
        return $courseList;
4176
    }
4177
4178
    /**
4179
     * Retrieves the user defined course categories.
4180
     *
4181
     * @param int $userId
4182
     *
4183
     * @return array
4184
     */
4185
    public static function get_user_course_categories($userId = 0)
4186
    {
4187
        $userId = empty($userId) ? api_get_user_id() : (int) $userId;
4188
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
4189
        $sql = "SELECT * FROM $table
4190
                WHERE user_id = $userId
4191
                ORDER BY sort ASC
4192
                ";
4193
        $result = Database::query($sql);
4194
        $output = [];
4195
        while ($row = Database::fetch_array($result, 'ASSOC')) {
4196
            $output[$row['id']] = $row;
4197
        }
4198
4199
        return $output;
4200
    }
4201
4202
    /**
4203
     * Return an array the user_category id and title for the course $courseId for user $userId.
4204
     *
4205
     * @param $userId
4206
     * @param $courseId
4207
     *
4208
     * @return array
4209
     */
4210
    public static function getUserCourseCategoryForCourse($userId, $courseId)
4211
    {
4212
        $tblCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4213
        $tblUserCategory = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
4214
        $courseId = intval($courseId);
4215
        $userId = intval($userId);
4216
4217
        $sql = "SELECT user_course_cat, title
4218
                FROM $tblCourseRelUser cru
4219
                LEFT JOIN $tblUserCategory ucc
4220
                ON cru.user_course_cat = ucc.id
4221
                WHERE
4222
                    cru.user_id = $userId AND c_id = $courseId ";
4223
4224
        $res = Database::query($sql);
4225
4226
        $data = [];
4227
        if (Database::num_rows($res) > 0) {
4228
            $data = Database::fetch_assoc($res);
4229
        }
4230
4231
        return $data;
4232
    }
4233
4234
    /**
4235
     * Get the course id based on the original id and field name in the extra fields.
4236
     * Returns 0 if course was not found.
4237
     *
4238
     * @param string $value    Original course code
4239
     * @param string $variable Original field name
4240
     *
4241
     * @return array
4242
     */
4243
    public static function getCourseInfoFromOriginalId($value, $variable)
4244
    {
4245
        $extraFieldValue = new ExtraFieldValue('course');
4246
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
4247
            $variable,
4248
            $value
4249
        );
4250
4251
        if (!empty($result)) {
4252
            $courseInfo = api_get_course_info_by_id($result['item_id']);
4253
4254
            return $courseInfo;
4255
        }
4256
4257
        return [];
4258
    }
4259
4260
    /**
4261
     * Display code for one specific course a logged in user is subscribed to.
4262
     * Shows a link to the course, what's new icons...
4263
     *
4264
     * $my_course['d'] - course directory
4265
     * $my_course['i'] - course title
4266
     * $my_course['c'] - visual course code
4267
     * $my_course['k']  - system course code
4268
     *
4269
     * @param   array       Course details
4270
     * @param   int     Session ID
4271
     * @param   string      CSS class to apply to course entry
4272
     * @param   bool     Whether the session is supposedly accessible now
4273
     * (not in the case it has passed and is in invisible/unaccessible mode)
4274
     * @param bool      Whether to show the document quick-loader or not
4275
     *
4276
     * @return string The HTML to be printed for the course entry
4277
     *
4278
     * @version 1.0.3
4279
     *
4280
     * @todo refactor into different functions for database calls | logic | display
4281
     * @todo replace single-character $my_course['d'] indices
4282
     * @todo move code for what's new icons to a separate function to clear things up
4283
     * @todo add a parameter user_id so that it is possible to show the
4284
     * courselist of other users (=generalisation).
4285
     * This will prevent having to write a new function for this.
4286
     */
4287
    public static function get_logged_user_course_html(
4288
        $course,
4289
        $session_id = 0,
4290
        $class = 'courses',
4291
        $session_accessible = true,
4292
        $load_dirs = false
4293
    ) {
4294
        $now = date('Y-m-d h:i:s');
4295
        $user_id = api_get_user_id();
4296
        $course_info = api_get_course_info_by_id($course['real_id']);
4297
        $course_visibility = (int) $course_info['visibility'];
4298
4299
        if (COURSE_VISIBILITY_HIDDEN === $course_visibility) {
4300
            return '';
4301
        }
4302
4303
        $userInCourseStatus = self::getUserInCourseStatus($user_id, $course_info['real_id']);
4304
        $course_info['status'] = empty($session_id) ? $userInCourseStatus : STUDENT;
4305
        $course_info['id_session'] = $session_id;
4306
4307
        $is_coach = api_is_coach($session_id, $course_info['real_id']);
4308
4309
        // Display course entry.
4310
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
4311
        $session_url = '';
4312
        $params = [];
4313
        $params['icon'] = Display::return_icon(
4314
            'session.png',
4315
            null,
4316
            [],
4317
            ICON_SIZE_LARGE,
4318
            null,
4319
            true
4320
        );
4321
        $params['real_id'] = $course_info['real_id'];
4322
        $params['visibility'] = $course_info['visibility'];
4323
4324
        // Display the "what's new" icons
4325
        $notifications = '';
4326
        if (
4327
            (COURSE_VISIBILITY_CLOSED != $course_visibility && COURSE_VISIBILITY_HIDDEN != $course_visibility) ||
4328
            !api_get_configuration_value('hide_course_notification')
4329
        ) {
4330
            $notifications .= Display::show_notification($course_info);
4331
        }
4332
4333
        if ($session_accessible) {
4334
            if (COURSE_VISIBILITY_CLOSED != $course_visibility ||
4335
                COURSEMANAGER == $userInCourseStatus
4336
            ) {
4337
                if (empty($course_info['id_session'])) {
4338
                    $course_info['id_session'] = 0;
4339
                }
4340
4341
                $sessionCourseAvailable = false;
4342
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
4343
4344
                if (in_array(
4345
                    $sessionCourseStatus,
4346
                    [SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE]
4347
                )) {
4348
                    $sessionCourseAvailable = true;
4349
                }
4350
4351
                if (COURSEMANAGER === $userInCourseStatus || $sessionCourseAvailable) {
4352
                    $session_url = $course_info['course_public_url'].'?sid='.$course_info['id_session'];
4353
                    $session_title = '<a title="'.$course_info['name'].'" href="'.$session_url.'">'.
4354
                        $course_info['name'].'</a>'.$notifications;
4355
                } else {
4356
                    $session_title = $course_info['name'];
4357
                }
4358
            } else {
4359
                $session_title =
4360
                    $course_info['name'].' '.
4361
                    Display::tag('span', get_lang('(the course is currently closed)'), ['class' => 'item_closed']);
4362
            }
4363
        } else {
4364
            $session_title = $course_info['name'];
4365
        }
4366
4367
        $thumbnails = null;
4368
        $image = null;
4369
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
4370
        $iconName = basename($course_info['course_image']);
4371
4372
        if ('true' === $showCustomIcon && 'course.png' != $iconName) {
4373
            $thumbnails = $course_info['course_image'];
4374
            $image = $course_info['course_image_large'];
4375
        } else {
4376
            $image = Display::return_icon(
4377
                'session_default.png',
4378
                null,
4379
                null,
4380
                null,
4381
                null,
4382
                true
4383
            );
4384
        }
4385
        $params['thumbnails'] = $thumbnails;
4386
        $params['image'] = $image;
4387
        $params['html_image'] = '';
4388
        if (!empty($thumbnails)) {
4389
            $params['html_image'] = Display::img($thumbnails, $course_info['name'], ['class' => 'img-responsive']);
4390
        } else {
4391
            $params['html_image'] = Display::return_icon(
4392
                'session.png',
4393
                $course_info['name'],
4394
                ['class' => 'img-responsive'],
4395
                ICON_SIZE_LARGE,
4396
                $course_info['name']
4397
            );
4398
        }
4399
        $params['link'] = $session_url;
4400
        $entityManager = Database::getManager();
4401
        /** @var SequenceResourceRepository $repo */
4402
        $repo = $entityManager->getRepository('ChamiloCoreBundle:SequenceResource');
4403
4404
        $sequences = $repo->getRequirements($course_info['real_id'], SequenceResource::COURSE_TYPE);
4405
        $sequenceList = $repo->checkRequirementsForUser($sequences, SequenceResource::COURSE_TYPE, $user_id);
4406
        $completed = $repo->checkSequenceAreCompleted($sequenceList);
4407
        //var_dump($course_info['real_id'], $completed);
4408
        $params['completed'] = $completed;
4409
        $params['requirements'] = '';
4410
4411
        if ($sequences && false === $completed) {
4412
            $hasRequirements = false;
4413
            foreach ($sequences as $sequence) {
4414
                if (!empty($sequence['requirements'])) {
4415
                    $hasRequirements = true;
4416
                    break;
4417
                }
4418
            }
4419
            if ($hasRequirements) {
4420
                $params['requirements'] = CoursesAndSessionsCatalog::getRequirements(
4421
                    $course_info['real_id'],
4422
                    SequenceResource::COURSE_TYPE,
4423
                    false,
4424
                    false
4425
                );
4426
            }
4427
        }
4428
4429
        $params['title'] = $session_title;
4430
        $params['name'] = $course_info['name'];
4431
        $params['edit_actions'] = '';
4432
        $params['document'] = '';
4433
        $params['category'] = $course_info['categoryName'];
4434
4435
        if (COURSE_VISIBILITY_CLOSED != $course_visibility &&
4436
            COURSE_VISIBILITY_HIDDEN != $course_visibility
4437
        ) {
4438
            if (api_is_platform_admin()) {
4439
                $params['edit_actions'] .= api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course_info['real_id'];
4440
                if ($load_dirs) {
4441
                    $params['document'] .= '<a
4442
                        id="document_preview_'.$course_info['real_id'].'_'.$course_info['id_session'].'"
4443
                        class="document_preview btn btn-default btn-sm"
4444
                        href="javascript:void(0);">'.
4445
                        Display::returnFontAwesomeIcon('folder-open').'</a>';
4446
                    $params['document'] .= Display::div('', [
4447
                        'id' => 'document_result_'.$course_info['real_id'].'_'.$course_info['id_session'],
4448
                        'class' => 'document_preview_container',
4449
                    ]);
4450
                }
4451
            }
4452
        }
4453
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
4454
            $teacher_list = self::getTeachersFromCourse(
4455
                $course_info['real_id'],
4456
                true
4457
            );
4458
            $course_coachs = self::get_coachs_from_course(
4459
                $course_info['id_session'],
4460
                $course_info['real_id']
4461
            );
4462
            $params['teachers'] = $teacher_list;
4463
4464
            if ((STUDENT == $course_info['status'] && !empty($course_info['id_session'])) ||
4465
                ($is_coach && COURSEMANAGER != $course_info['status'])
4466
            ) {
4467
                $params['coaches'] = $course_coachs;
4468
            }
4469
        }
4470
        $special = isset($course['special_course']) ? true : false;
4471
        $params['title'] = $session_title;
4472
        $params['special'] = $special;
4473
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
4474
            $params['visual_code'] = '('.$course_info['visual_code'].')';
4475
        }
4476
        $params['extra'] = '';
4477
        $html = $params;
4478
4479
        $session_category_id = null;
4480
        if (1) {
4481
            $session = '';
4482
            $active = false;
4483
            if (!empty($course_info['id_session'])) {
4484
                $session = api_get_session_info($course_info['id_session']);
4485
                $sessionCoachName = '';
4486
                if (!empty($session['id_coach'])) {
4487
                    $coachInfo = api_get_user_info($session['id_coach']);
4488
                    $sessionCoachName = $coachInfo['complete_name'];
4489
                }
4490
4491
                $session_category_id = self::get_session_category_id_by_session_id($course_info['id_session']);
4492
4493
                if (
4494
                    '0000-00-00 00:00:00' === $session['access_start_date'] || empty($session['access_start_date']) ||
4495
                    '0000-00-00' === $session['access_start_date']
4496
                ) {
4497
                    $session['dates'] = '';
4498
                    if ('true' === api_get_setting('show_session_coach')) {
4499
                        $session['coach'] = get_lang('General coach').': '.$sessionCoachName;
4500
                    }
4501
                    $active = true;
4502
                } else {
4503
                    $session['dates'] = ' - '.
4504
                        get_lang('From').' '.$session['access_start_date'].' '.
4505
                        get_lang('To').' '.$session['access_end_date'];
4506
                    if ('true' === api_get_setting('show_session_coach')) {
4507
                        $session['coach'] = get_lang('General coach').': '.$sessionCoachName;
4508
                    }
4509
                    $date_start = $session['access_start_date'];
4510
                    $date_end = $session['access_end_date'];
4511
                    $active = !$date_end ? ($date_start <= $now) : ($date_start <= $now && $date_end >= $now);
4512
                }
4513
            }
4514
            $user_course_category = '';
4515
            if (isset($course_info['user_course_cat'])) {
4516
                $user_course_category = $course_info['user_course_cat'];
4517
            }
4518
            $output = [
4519
                $user_course_category,
4520
                $html,
4521
                $course_info['id_session'],
4522
                $session,
4523
                'active' => $active,
4524
                'session_category_id' => $session_category_id,
4525
            ];
4526
4527
            if (Skill::isAllowed($user_id, false)) {
4528
                $em = Database::getManager();
4529
                $objUser = api_get_user_entity($user_id);
4530
                /** @var Course $objCourse */
4531
                $objCourse = $em->find('ChamiloCoreBundle:Course', $course['real_id']);
4532
                $objSession = $em->find('ChamiloCoreBundle:Session', $session_id);
4533
4534
                $skill = $em->getRepository('ChamiloCoreBundle:Skill')->getLastByUser($objUser, $objCourse, $objSession);
4535
4536
                $output['skill'] = null;
4537
                if ($skill) {
4538
                    $output['skill']['name'] = $skill->getName();
4539
                    $output['skill']['icon'] = $skill->getIcon();
4540
                }
4541
            }
4542
        } else {
4543
            $output = [$course_info['user_course_cat'], $html];
4544
        }
4545
4546
        return $output;
4547
    }
4548
4549
    /**
4550
     * @param string $source_course_code
4551
     * @param int    $source_session_id
4552
     * @param string $destination_course_code
4553
     * @param int    $destination_session_id
4554
     * @param array  $params
4555
     *
4556
     * @return bool
4557
     */
4558
    public static function copy_course(
4559
        $source_course_code,
4560
        $source_session_id,
4561
        $destination_course_code,
4562
        $destination_session_id,
4563
        $params = []
4564
    ) {
4565
        $course_info = api_get_course_info($source_course_code);
4566
4567
        if (!empty($course_info)) {
4568
            $cb = new CourseBuilder('', $course_info);
4569
            $course = $cb->build($source_session_id, $source_course_code, true);
4570
            $course_restorer = new CourseRestorer($course);
4571
            $course_restorer->skip_content = $params;
4572
            $course_restorer->restore(
4573
                $destination_course_code,
4574
                $destination_session_id,
4575
                true,
4576
                true
4577
            );
4578
4579
            return true;
4580
        }
4581
4582
        return false;
4583
    }
4584
4585
    /**
4586
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code.
4587
     *
4588
     * @param string $new_title new course title
4589
     * @param string source course code
4590
     * @param int source session id
4591
     * @param int destination session id
4592
     * @param array $params
4593
     *
4594
     * @return array
4595
     */
4596
    public static function copy_course_simple(
4597
        $new_title,
4598
        $source_course_code,
4599
        $source_session_id = 0,
4600
        $destination_session_id = 0,
4601
        $params = []
4602
    ) {
4603
        $source_course_info = api_get_course_info($source_course_code);
4604
        if (!empty($source_course_info)) {
4605
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4606
            if ($new_course_code) {
4607
                $new_course_info = self::create_course(
4608
                    $new_title,
4609
                    $new_course_code,
4610
                    false
4611
                );
4612
                if (!empty($new_course_info['code'])) {
4613
                    $result = self::copy_course(
4614
                        $source_course_code,
4615
                        $source_session_id,
4616
                        $new_course_info['code'],
4617
                        $destination_session_id,
4618
                        $params
4619
                    );
4620
                    if ($result) {
4621
                        return $new_course_info;
4622
                    }
4623
                }
4624
            }
4625
        }
4626
4627
        return false;
4628
    }
4629
4630
    /**
4631
     * Creates a new course code based in a given code.
4632
     *
4633
     * @param string    wanted code
4634
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return: course3</code>
4635
     * if the course code doest not exist in the DB the same course code will be returned
4636
     *
4637
     * @return string wanted unused code
4638
     */
4639
    public static function generate_nice_next_course_code($wanted_code)
4640
    {
4641
        $course_code_ok = !self::course_code_exists($wanted_code);
4642
        if (!$course_code_ok) {
4643
            $wanted_code = self::generate_course_code($wanted_code);
4644
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4645
            $wanted_code = Database::escape_string($wanted_code);
4646
            $sql = "SELECT count(id) as count
4647
                    FROM $table
4648
                    WHERE code LIKE '$wanted_code%'";
4649
            $result = Database::query($sql);
4650
            if (Database::num_rows($result) > 0) {
4651
                $row = Database::fetch_array($result);
4652
                $count = $row['count'] + 1;
4653
                $wanted_code = $wanted_code.'_'.$count;
4654
                $result = api_get_course_info($wanted_code);
4655
                if (empty($result)) {
4656
                    return $wanted_code;
4657
                }
4658
            }
4659
4660
            return false;
4661
        }
4662
4663
        return $wanted_code;
4664
    }
4665
4666
    /**
4667
     * Gets the status of the users agreement in a course course-session.
4668
     *
4669
     * @param int    $user_id
4670
     * @param string $course_code
4671
     * @param int    $session_id
4672
     *
4673
     * @return bool
4674
     */
4675
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = 0)
4676
    {
4677
        $user_id = (int) $user_id;
4678
        $session_id = (int) $session_id;
4679
        $course_code = Database::escape_string($course_code);
4680
4681
        $courseInfo = api_get_course_info($course_code);
4682
        $courseId = $courseInfo['real_id'];
4683
4684
        // Course legal
4685
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4686
4687
        if ('true' == $enabled) {
4688
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4689
            $plugin = CourseLegalPlugin::create();
4690
4691
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4692
        }
4693
4694
        if (empty($session_id)) {
4695
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4696
            $sql = "SELECT legal_agreement FROM $table
4697
                    WHERE user_id = $user_id AND c_id = $courseId ";
4698
            $result = Database::query($sql);
4699
            if (Database::num_rows($result) > 0) {
4700
                $result = Database::fetch_array($result);
4701
                if (1 == $result['legal_agreement']) {
4702
                    return true;
4703
                }
4704
            }
4705
4706
            return false;
4707
        } else {
4708
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4709
            $sql = "SELECT legal_agreement FROM $table
4710
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4711
            $result = Database::query($sql);
4712
            if (Database::num_rows($result) > 0) {
4713
                $result = Database::fetch_array($result);
4714
                if (1 == $result['legal_agreement']) {
4715
                    return true;
4716
                }
4717
            }
4718
4719
            return false;
4720
        }
4721
    }
4722
4723
    /**
4724
     * Saves the user-course legal agreement.
4725
     *
4726
     * @param   int user id
4727
     * @param   string course code
4728
     * @param   int session id
4729
     *
4730
     * @return bool
4731
     */
4732
    public static function save_user_legal($user_id, $courseInfo, $session_id = 0)
4733
    {
4734
        if (empty($courseInfo)) {
4735
            return false;
4736
        }
4737
        $course_code = $courseInfo['code'];
4738
4739
        // Course plugin legal
4740
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4741
        if ('true' == $enabled) {
4742
            require_once api_get_path(SYS_PLUGIN_PATH).'courselegal/config.php';
4743
            $plugin = CourseLegalPlugin::create();
4744
4745
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4746
        }
4747
4748
        $user_id = (int) $user_id;
4749
        $session_id = (int) $session_id;
4750
        $courseId = $courseInfo['real_id'];
4751
4752
        if (empty($session_id)) {
4753
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4754
            $sql = "UPDATE $table SET legal_agreement = '1'
4755
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4756
            Database::query($sql);
4757
        } else {
4758
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4759
            $sql = "UPDATE  $table SET legal_agreement = '1'
4760
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4761
            Database::query($sql);
4762
        }
4763
4764
        return true;
4765
    }
4766
4767
    /**
4768
     * @param int $user_id
4769
     * @param int $course_id
4770
     * @param int $session_id
4771
     * @param int $url_id
4772
     *
4773
     * @return bool
4774
     */
4775
    public static function get_user_course_vote($user_id, $course_id, $session_id = 0, $url_id = 0)
4776
    {
4777
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4778
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4779
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4780
        $user_id = intval($user_id);
4781
4782
        if (empty($user_id)) {
4783
            return false;
4784
        }
4785
4786
        $params = [
4787
            'user_id' => $user_id,
4788
            'c_id' => $course_id,
4789
            'session_id' => $session_id,
4790
            'url_id' => $url_id,
4791
        ];
4792
4793
        $result = Database::select(
4794
            'vote',
4795
            $table_user_course_vote,
4796
            [
4797
                'where' => [
4798
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params,
4799
                ],
4800
            ],
4801
            'first'
4802
        );
4803
        if (!empty($result)) {
4804
            return $result['vote'];
4805
        }
4806
4807
        return false;
4808
    }
4809
4810
    /**
4811
     * @param int $course_id
4812
     * @param int $session_id
4813
     * @param int $url_id
4814
     *
4815
     * @return array
4816
     */
4817
    public static function get_course_ranking(
4818
        $course_id,
4819
        $session_id = 0,
4820
        $url_id = 0
4821
    ) {
4822
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4823
4824
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4825
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4826
        $now = api_get_utc_datetime();
4827
4828
        $params = [
4829
            'c_id' => $course_id,
4830
            'session_id' => $session_id,
4831
            'url_id' => $url_id,
4832
            'creation_date' => $now,
4833
        ];
4834
4835
        $result = Database::select(
4836
            'c_id, accesses, total_score, users',
4837
            $table_course_ranking,
4838
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4839
            'first'
4840
        );
4841
4842
        $point_average_in_percentage = 0;
4843
        $point_average_in_star = 0;
4844
        $users_who_voted = 0;
4845
4846
        if (!empty($result['users'])) {
4847
            $users_who_voted = $result['users'];
4848
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4849
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4850
        }
4851
4852
        $result['user_vote'] = false;
4853
        if (!api_is_anonymous()) {
4854
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4855
        }
4856
4857
        $result['point_average'] = $point_average_in_percentage;
4858
        $result['point_average_star'] = $point_average_in_star;
4859
        $result['users_who_voted'] = $users_who_voted;
4860
4861
        return $result;
4862
    }
4863
4864
    /**
4865
     * Updates the course ranking.
4866
     *
4867
     * @param int   course id
4868
     * @param int $session_id
4869
     * @param int    url id
4870
     * @param $points_to_add
4871
     * @param bool $add_access
4872
     * @param bool $add_user
4873
     *
4874
     * @return array
4875
     */
4876
    public static function update_course_ranking(
4877
        $course_id = 0,
4878
        $session_id = 0,
4879
        $url_id = 0,
4880
        $points_to_add = null,
4881
        $add_access = true,
4882
        $add_user = true
4883
    ) {
4884
        // Course catalog stats modifications see #4191
4885
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4886
        $now = api_get_utc_datetime();
4887
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4888
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4889
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4890
4891
        $params = [
4892
            'c_id' => $course_id,
4893
            'session_id' => $session_id,
4894
            'url_id' => $url_id,
4895
            'creation_date' => $now,
4896
            'total_score' => 0,
4897
            'users' => 0,
4898
        ];
4899
4900
        $result = Database::select(
4901
            'id, accesses, total_score, users',
4902
            $table_course_ranking,
4903
            ['where' => ['c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4904
            'first'
4905
        );
4906
4907
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4908
        if (empty($result)) {
4909
            if ($add_access) {
4910
                $params['accesses'] = 1;
4911
            }
4912
            //The votes and users are empty
4913
            if (isset($points_to_add) && !empty($points_to_add)) {
4914
                $params['total_score'] = intval($points_to_add);
4915
            }
4916
            if ($add_user) {
4917
                $params['users'] = 1;
4918
            }
4919
            $result = Database::insert($table_course_ranking, $params);
4920
        } else {
4921
            $my_params = [];
4922
4923
            if ($add_access) {
4924
                $my_params['accesses'] = intval($result['accesses']) + 1;
4925
            }
4926
            if (isset($points_to_add) && !empty($points_to_add)) {
4927
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4928
            }
4929
            if ($add_user) {
4930
                $my_params['users'] = $result['users'] + 1;
4931
            }
4932
4933
            if (!empty($my_params)) {
4934
                $result = Database::update(
4935
                    $table_course_ranking,
4936
                    $my_params,
4937
                    ['c_id = ? AND session_id = ? AND url_id = ?' => $params]
4938
                );
4939
            }
4940
        }
4941
4942
        return $result;
4943
    }
4944
4945
    /**
4946
     * Add user vote to a course.
4947
     *
4948
     * @param   int user id
4949
     * @param   int vote [1..5]
4950
     * @param   int course id
4951
     * @param   int session id
4952
     * @param   int url id (access_url_id)
4953
     *
4954
     * @return false|string 'added', 'updated' or 'nothing'
4955
     */
4956
    public static function add_course_vote(
4957
        $user_id,
4958
        $vote,
4959
        $course_id,
4960
        $session_id = 0,
4961
        $url_id = 0
4962
    ) {
4963
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4964
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4965
4966
        if (empty($course_id) || empty($user_id)) {
4967
            return false;
4968
        }
4969
4970
        if (!in_array($vote, [1, 2, 3, 4, 5])) {
4971
            return false;
4972
        }
4973
4974
        $session_id = empty($session_id) ? api_get_session_id() : intval($session_id);
4975
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4976
        $vote = intval($vote);
4977
4978
        $params = [
4979
            'user_id' => intval($user_id),
4980
            'c_id' => $course_id,
4981
            'session_id' => $session_id,
4982
            'url_id' => $url_id,
4983
            'vote' => $vote,
4984
        ];
4985
4986
        $action_done = 'nothing';
4987
        $result = Database::select(
4988
            'id, vote',
4989
            $table_user_course_vote,
4990
            ['where' => ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]],
4991
            'first'
4992
        );
4993
4994
        if (empty($result)) {
4995
            Database::insert($table_user_course_vote, $params);
4996
            $points_to_add = $vote;
4997
            $add_user = true;
4998
            $action_done = 'added';
4999
        } else {
5000
            $my_params = ['vote' => $vote];
5001
            $points_to_add = $vote - $result['vote'];
5002
            $add_user = false;
5003
5004
            Database::update(
5005
                $table_user_course_vote,
5006
                $my_params,
5007
                ['user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params]
5008
            );
5009
            $action_done = 'updated';
5010
        }
5011
5012
        // Current points
5013
        if (!empty($points_to_add)) {
5014
            self::update_course_ranking(
5015
                $course_id,
5016
                $session_id,
5017
                $url_id,
5018
                $points_to_add,
5019
                false,
5020
                $add_user
5021
            );
5022
        }
5023
5024
        return $action_done;
5025
    }
5026
5027
    /**
5028
     * Remove course ranking + user votes.
5029
     *
5030
     * @param int $course_id
5031
     * @param int $session_id
5032
     * @param int $url_id
5033
     */
5034
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
5035
    {
5036
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
5037
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
5038
5039
        if (!empty($course_id) && isset($session_id)) {
5040
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
5041
            $params = [
5042
                'c_id' => $course_id,
5043
                'session_id' => $session_id,
5044
                'url_id' => $url_id,
5045
            ];
5046
            Database::delete($table_course_ranking, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
5047
            Database::delete($table_user_course_vote, ['c_id = ? AND session_id = ? AND url_id = ?' => $params]);
5048
        }
5049
    }
5050
5051
    /**
5052
     * Returns an array with the hottest courses.
5053
     *
5054
     * @param int $days  number of days
5055
     * @param int $limit number of hottest courses
5056
     *
5057
     * @return array
5058
     */
5059
    public static function return_hot_courses($days = 30, $limit = 6)
5060
    {
5061
        if (api_is_invitee()) {
5062
            return [];
5063
        }
5064
5065
        $limit = (int) $limit;
5066
        $userId = api_get_user_id();
5067
5068
        // Getting my courses
5069
        $my_course_list = self::get_courses_list_by_user_id($userId);
5070
5071
        $codeList = [];
5072
        foreach ($my_course_list as $course) {
5073
            $codeList[$course['real_id']] = $course['real_id'];
5074
        }
5075
5076
        if (api_is_drh()) {
5077
            $courses = self::get_courses_followed_by_drh($userId);
5078
            foreach ($courses as $course) {
5079
                $codeList[$course['real_id']] = $course['real_id'];
5080
            }
5081
        }
5082
5083
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5084
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5085
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5086
        $urlId = api_get_current_access_url_id();
5087
        //$table_course_access table uses the now() and interval ...
5088
        $now = api_get_utc_datetime();
5089
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
5090
                FROM $table_course c
5091
                INNER JOIN $table_course_access a
5092
                ON (c.id = a.c_id)
5093
                INNER JOIN $table_course_url u
5094
                ON u.c_id = c.id
5095
                WHERE
5096
                    u.access_url_id = $urlId AND
5097
                    login_course_date <= '$now' AND
5098
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
5099
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
5100
                    visibility <> ".COURSE_VISIBILITY_HIDDEN."
5101
                GROUP BY a.c_id
5102
                ORDER BY course_count DESC
5103
                LIMIT $limit
5104
            ";
5105
5106
        $result = Database::query($sql);
5107
        $courses = [];
5108
        if (Database::num_rows($result)) {
5109
            $courses = Database::store_result($result, 'ASSOC');
5110
            $courses = self::processHotCourseItem($courses, $codeList);
5111
        }
5112
5113
        return $courses;
5114
    }
5115
5116
    /**
5117
     * Returns an array with the "hand picked" popular courses.
5118
     * Courses only appear in this list if their extra field 'popular_courses'
5119
     * has been selected in the admin page of the course.
5120
     *
5121
     * @return array
5122
     */
5123
    public static function returnPopularCoursesHandPicked()
5124
    {
5125
        if (api_is_invitee()) {
5126
            return [];
5127
        }
5128
5129
        $userId = api_get_user_id();
5130
5131
        // Getting my courses
5132
        $my_course_list = self::get_courses_list_by_user_id($userId);
5133
5134
        $codeList = [];
5135
        foreach ($my_course_list as $course) {
5136
            $codeList[$course['real_id']] = $course['real_id'];
5137
        }
5138
5139
        if (api_is_drh()) {
5140
            $courses = self::get_courses_followed_by_drh($userId);
5141
            foreach ($courses as $course) {
5142
                $codeList[$course['real_id']] = $course['real_id'];
5143
            }
5144
        }
5145
5146
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5147
        $tbl_course_field = Database::get_main_table(TABLE_EXTRA_FIELD);
5148
        $tbl_course_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
5149
5150
        //we filter the courses from the URL
5151
        $join_access_url = $where_access_url = '';
5152
        if (api_get_multiple_access_url()) {
5153
            $access_url_id = api_get_current_access_url_id();
5154
            if ($access_url_id != -1) {
5155
                $tbl_url_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5156
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
5157
                ON url_rel_course.c_id = tcfv.item_id ";
5158
                $where_access_url = " AND access_url_id = $access_url_id ";
5159
            }
5160
        }
5161
5162
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
5163
5164
        // get course list auto-register
5165
        $sql = "SELECT DISTINCT(c.id) AS c_id
5166
                FROM $tbl_course_field_value tcfv
5167
                INNER JOIN $tbl_course_field tcf
5168
                ON tcfv.field_id =  tcf.id $join_access_url
5169
                INNER JOIN $courseTable c
5170
                ON (c.id = tcfv.item_id)
5171
                WHERE
5172
                    tcf.extra_field_type = $extraFieldType AND
5173
                    tcf.variable = 'popular_courses' AND
5174
                    tcfv.value = 1 AND
5175
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
5176
                    visibility <> ".COURSE_VISIBILITY_HIDDEN." $where_access_url";
5177
5178
        $result = Database::query($sql);
5179
        $courses = [];
5180
        if (Database::num_rows($result)) {
5181
            $courses = Database::store_result($result, 'ASSOC');
5182
            $courses = self::processHotCourseItem($courses, $codeList);
5183
        }
5184
5185
        return $courses;
5186
    }
5187
5188
    /**
5189
     * @param array $courses
5190
     * @param array $codeList
5191
     *
5192
     * @return mixed
5193
     */
5194
    public static function processHotCourseItem($courses, $codeList = [])
5195
    {
5196
        $hotCourses = [];
5197
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
5198
        $stok = Security::get_existing_token();
5199
        $user_id = api_get_user_id();
5200
5201
        foreach ($courses as $courseId) {
5202
            $course_info = api_get_course_info_by_id($courseId['c_id']);
5203
            $courseCode = $course_info['code'];
5204
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
5205
            $my_course = $course_info;
5206
            $my_course['go_to_course_button'] = '';
5207
            $my_course['register_button'] = '';
5208
5209
            $access_link = self::get_access_link_by_user(
5210
                $user_id,
5211
                $course_info,
5212
                $codeList
5213
            );
5214
5215
            $userRegisteredInCourse = self::is_user_subscribed_in_course($user_id, $course_info['code']);
5216
            $userRegisteredInCourseAsTeacher = self::is_course_teacher($user_id, $course_info['code']);
5217
            $userRegistered = $userRegisteredInCourse && $userRegisteredInCourseAsTeacher;
5218
            $my_course['is_course_student'] = $userRegisteredInCourse;
5219
            $my_course['is_course_teacher'] = $userRegisteredInCourseAsTeacher;
5220
            $my_course['is_registered'] = $userRegistered;
5221
            $my_course['title_cut'] = cut($course_info['title'], 45);
5222
5223
            // Course visibility
5224
            if ($access_link && in_array('register', $access_link)) {
5225
                $my_course['register_button'] = Display::url(
5226
                    get_lang('Subscribe').' '.
5227
                    Display::returnFontAwesomeIcon('sign-in'),
5228
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].
5229
                     '/index.php?action=subscribe&sec_token='.$stok,
5230
                    [
5231
                        'class' => 'btn btn-success btn-sm',
5232
                        'title' => get_lang('Subscribe'),
5233
                        'aria-label' => get_lang('Subscribe'),
5234
                    ]
5235
                );
5236
            }
5237
5238
            if ($access_link && in_array('enter', $access_link) ||
5239
                COURSE_VISIBILITY_OPEN_WORLD == $course_info['visibility']
5240
            ) {
5241
                $my_course['go_to_course_button'] = Display::url(
5242
                    get_lang('Go to the course').' '.
5243
                    Display::returnFontAwesomeIcon('share'),
5244
                    api_get_path(WEB_COURSE_PATH).$course_info['path'].'/index.php',
5245
                    [
5246
                        'class' => 'btn btn-default btn-sm',
5247
                        'title' => get_lang('Go to the course'),
5248
                        'aria-label' => get_lang('Go to the course'),
5249
                    ]
5250
                );
5251
            }
5252
5253
            if ($access_link && in_array('unsubscribe', $access_link)) {
5254
                $my_course['unsubscribe_button'] = Display::url(
5255
                    get_lang('Unsubscribe').' '.
5256
                    Display::returnFontAwesomeIcon('sign-out'),
5257
                    api_get_path(WEB_CODE_PATH).'auth/courses.php?action=unsubscribe&unsubscribe='.$courseCode
5258
                    .'&sec_token='.$stok.'&category_code='.$categoryCode,
5259
                    [
5260
                        'class' => 'btn btn-danger btn-sm',
5261
                        'title' => get_lang('Unsubscribe'),
5262
                        'aria-label' => get_lang('Unsubscribe'),
5263
                    ]
5264
                );
5265
            }
5266
5267
            // start buycourse validation
5268
            // display the course price and buy button if the buycourses plugin is enabled and this course is configured
5269
            $plugin = BuyCoursesPlugin::create();
5270
            $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
5271
                $course_info['real_id'],
5272
                BuyCoursesPlugin::PRODUCT_TYPE_COURSE
5273
            );
5274
            if ($isThisCourseInSale) {
5275
                // set the price label
5276
                $my_course['price'] = $isThisCourseInSale['html'];
5277
                // set the Buy button instead register.
5278
                if ($isThisCourseInSale['verificator'] && !empty($my_course['register_button'])) {
5279
                    $my_course['register_button'] = $plugin->returnBuyCourseButton(
5280
                        $course_info['real_id'],
5281
                        BuyCoursesPlugin::PRODUCT_TYPE_COURSE
5282
                    );
5283
                }
5284
            }
5285
            // end buycourse validation
5286
5287
            // Description
5288
            $my_course['description_button'] = self::returnDescriptionButton($course_info);
5289
            $my_course['teachers'] = self::getTeachersFromCourse($course_info['real_id'], true);
5290
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
5291
            $my_course['rating_html'] = '';
5292
            if (false === api_get_configuration_value('hide_course_rating')) {
5293
                $my_course['rating_html'] = Display::return_rating_system(
5294
                    'star_'.$course_info['real_id'],
5295
                    $ajax_url.'&course_id='.$course_info['real_id'],
5296
                    $point_info
5297
                );
5298
            }
5299
            $hotCourses[] = $my_course;
5300
        }
5301
5302
        return $hotCourses;
5303
    }
5304
5305
    public function totalSubscribedUsersInCourses($urlId)
5306
    {
5307
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5308
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5309
        $courseUsers = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5310
5311
        $urlId = (int) $urlId;
5312
5313
        $sql = "SELECT count(cu.user_id) count
5314
                FROM $courseUsers cu
5315
                INNER JOIN $table_course_rel_access_url u
5316
                ON cu.c_id = u.c_id
5317
                WHERE
5318
                    relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
5319
                    u.access_url_id = $urlId AND
5320
                    visibility <> ".COURSE_VISIBILITY_CLOSED." AND
5321
                    visibility <> ".COURSE_VISIBILITY_HIDDEN."
5322
                     ";
5323
5324
        $res = Database::query($sql);
5325
        $row = Database::fetch_array($res);
5326
5327
        return $row['count'];
5328
    }
5329
5330
    /**
5331
     * Get courses count.
5332
     *
5333
     * @param int $access_url_id Access URL ID (optional)
5334
     * @param int $visibility
5335
     *
5336
     * @return int Number of courses
5337
     */
5338
    public static function count_courses($access_url_id = null, $visibility = null)
5339
    {
5340
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5341
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5342
        $sql = "SELECT count(c.id) FROM $table_course c";
5343
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
5344
            $sql .= ", $table_course_rel_access_url u
5345
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
5346
            if (!empty($visibility)) {
5347
                $visibility = intval($visibility);
5348
                $sql .= " AND visibility = $visibility ";
5349
            }
5350
        } else {
5351
            if (!empty($visibility)) {
5352
                $visibility = intval($visibility);
5353
                $sql .= " WHERE visibility = $visibility ";
5354
            }
5355
        }
5356
5357
        $res = Database::query($sql);
5358
        $row = Database::fetch_row($res);
5359
5360
        return $row[0];
5361
    }
5362
5363
    /**
5364
     * Get active courses count.
5365
     * Active = all courses except the ones with hidden visibility.
5366
     *
5367
     * @param int $urlId Access URL ID (optional)
5368
     *
5369
     * @return int Number of courses
5370
     */
5371
    public static function countActiveCourses($urlId = null)
5372
    {
5373
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
5374
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5375
        $sql = "SELECT count(c.id) FROM $table_course c";
5376
        if (!empty($urlId)) {
5377
            $urlId = (int) $urlId;
5378
            $sql .= ", $table_course_rel_access_url u
5379
                    WHERE
5380
                        c.id = u.c_id AND
5381
                        u.access_url_id = $urlId AND
5382
                        visibility <> ".COURSE_VISIBILITY_HIDDEN;
5383
        } else {
5384
            $sql .= " WHERE visibility <> ".COURSE_VISIBILITY_HIDDEN;
5385
        }
5386
        $res = Database::query($sql);
5387
        $row = Database::fetch_row($res);
5388
5389
        return $row[0];
5390
    }
5391
5392
    /**
5393
     * Returns the SQL conditions to filter course only visible by the user in the catalogue.
5394
     *
5395
     * @param string $courseTableAlias Alias of the course table
5396
     * @param bool   $hideClosed       Whether to hide closed and hidden courses
5397
     *
5398
     * @return string SQL conditions
5399
     */
5400
    public static function getCourseVisibilitySQLCondition(
5401
        $courseTableAlias,
5402
        $hideClosed = false
5403
    ) {
5404
        $visibilityCondition = '';
5405
        $hidePrivate = api_get_setting('course_catalog_hide_private');
5406
        if ('true' === $hidePrivate) {
5407
            $visibilityCondition .= " AND $courseTableAlias.visibility <> ".COURSE_VISIBILITY_REGISTERED;
5408
        }
5409
        if ($hideClosed) {
5410
            $visibilityCondition .= " AND $courseTableAlias.visibility NOT IN (".COURSE_VISIBILITY_CLOSED.','.COURSE_VISIBILITY_HIDDEN.')';
5411
        }
5412
5413
        // Check if course have users allowed to see it in the catalogue, then show only if current user is allowed to see it
5414
        $currentUserId = api_get_user_id();
5415
        $restrictedCourses = self::getCatalogCourseList(true);
5416
        $allowedCoursesToCurrentUser = self::getCatalogCourseList(true, $currentUserId);
5417
        if (!empty($restrictedCourses)) {
5418
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5419
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code IN ("'.implode('","', $allowedCoursesToCurrentUser).'"))';
5420
        }
5421
5422
        // Check if course have users denied to see it in the catalogue, then show only if current user is not denied to see it
5423
        $restrictedCourses = self::getCatalogCourseList(false);
5424
        $notAllowedCoursesToCurrentUser = self::getCatalogCourseList(false, $currentUserId);
5425
        if (!empty($restrictedCourses)) {
5426
            $visibilityCondition .= ' AND ('.$courseTableAlias.'.code NOT IN ("'.implode('","', $restrictedCourses).'")';
5427
            $visibilityCondition .= ' OR '.$courseTableAlias.'.code NOT IN ("'.implode('","', $notAllowedCoursesToCurrentUser).'"))';
5428
        }
5429
5430
        return $visibilityCondition;
5431
    }
5432
5433
    /**
5434
     * Return a link to go to the course, validating the visibility of the
5435
     * course and the user status.
5436
     *
5437
     * @param int $uid User ID
5438
     * @param array Course details array
5439
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
5440
     *
5441
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
5442
     */
5443
    public static function get_access_link_by_user($uid, $course, $user_courses = [])
5444
    {
5445
        if (empty($uid) || empty($course)) {
5446
            return false;
5447
        }
5448
5449
        if (empty($user_courses)) {
5450
            // get the array of courses to which the user is subscribed
5451
            $user_courses = self::get_courses_list_by_user_id($uid);
5452
            foreach ($user_courses as $k => $v) {
5453
                $user_courses[$k] = $v['real_id'];
5454
            }
5455
        }
5456
5457
        if (!isset($course['real_id']) && empty($course['real_id'])) {
5458
            $course = api_get_course_info($course['code']);
5459
        }
5460
5461
        if (COURSE_VISIBILITY_HIDDEN == $course['visibility']) {
5462
            return [];
5463
        }
5464
5465
        $is_admin = api_is_platform_admin_by_id($uid);
5466
        $options = [];
5467
        // Register button
5468
        if (!api_is_anonymous($uid) &&
5469
            (
5470
            (COURSE_VISIBILITY_OPEN_WORLD == $course['visibility'] || COURSE_VISIBILITY_OPEN_PLATFORM == $course['visibility'])
5471
                //$course['visibility'] == COURSE_VISIBILITY_REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
5472
            ) &&
5473
            SUBSCRIBE_ALLOWED == $course['subscribe'] &&
5474
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
5475
        ) {
5476
            $options[] = 'register';
5477
        }
5478
5479
        $isLogin = !api_is_anonymous();
5480
5481
        // Go To Course button (only if admin, if course public or if student already subscribed)
5482
        if ($is_admin ||
5483
            COURSE_VISIBILITY_OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5484
            ($isLogin && COURSE_VISIBILITY_OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5485
            (in_array($course['real_id'], $user_courses) && COURSE_VISIBILITY_CLOSED != $course['visibility'])
5486
        ) {
5487
            $options[] = 'enter';
5488
        }
5489
5490
        if ($is_admin ||
5491
            COURSE_VISIBILITY_OPEN_WORLD == $course['visibility'] && empty($course['registration_code']) ||
5492
            ($isLogin && COURSE_VISIBILITY_OPEN_PLATFORM == $course['visibility'] && empty($course['registration_code'])) ||
5493
            (in_array($course['real_id'], $user_courses) && COURSE_VISIBILITY_CLOSED != $course['visibility'])
5494
        ) {
5495
            $options[] = 'enter';
5496
        }
5497
5498
        if (COURSE_VISIBILITY_HIDDEN != $course['visibility'] &&
5499
            empty($course['registration_code']) &&
5500
            UNSUBSCRIBE_ALLOWED == $course['unsubscribe'] &&
5501
            $isLogin &&
5502
            in_array($course['real_id'], $user_courses)
5503
        ) {
5504
            $options[] = 'unsubscribe';
5505
        }
5506
5507
        return $options;
5508
    }
5509
5510
    /**
5511
     * @param array          $courseInfo
5512
     * @param array          $teachers
5513
     * @param bool           $deleteTeachersNotInList
5514
     * @param bool           $editTeacherInSessions
5515
     * @param bool           $deleteSessionTeacherNotInList
5516
     * @param array          $teacherBackup
5517
     * @param Monolog\Logger $logger
5518
     *
5519
     * @return false|null
5520
     */
5521
    public static function updateTeachers(
5522
        $courseInfo,
5523
        $teachers,
5524
        $deleteTeachersNotInList = true,
5525
        $editTeacherInSessions = false,
5526
        $deleteSessionTeacherNotInList = false,
5527
        $teacherBackup = [],
5528
        $logger = null
5529
    ) {
5530
        if (!is_array($teachers)) {
5531
            $teachers = [$teachers];
5532
        }
5533
5534
        if (empty($courseInfo) || !isset($courseInfo['real_id'])) {
5535
            return false;
5536
        }
5537
5538
        $teachers = array_filter($teachers);
5539
        $courseId = $courseInfo['real_id'];
5540
        $course_code = $courseInfo['code'];
5541
5542
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5543
        $alreadyAddedTeachers = self::get_teacher_list_from_course_code($course_code);
5544
5545
        if ($deleteTeachersNotInList) {
5546
            // Delete only teacher relations that doesn't match the selected teachers
5547
            $cond = null;
5548
            if (count($teachers) > 0) {
5549
                foreach ($teachers as $key) {
5550
                    $key = Database::escape_string($key);
5551
                    $cond .= " AND user_id <> '".$key."'";
5552
                }
5553
            }
5554
5555
            // Recover user categories
5556
            $sql = "SELECT * FROM $course_user_table
5557
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5558
            $result = Database::query($sql);
5559
            if (Database::num_rows($result)) {
5560
                $teachersToDelete = Database::store_result($result, 'ASSOC');
5561
                foreach ($teachersToDelete as $data) {
5562
                    $userId = $data['user_id'];
5563
                    $teacherBackup[$userId][$course_code] = $data;
5564
                }
5565
            }
5566
5567
            $sql = "DELETE FROM $course_user_table
5568
                    WHERE c_id = $courseId AND status = 1 AND relation_type = 0 ".$cond;
5569
5570
            Database::query($sql);
5571
        }
5572
5573
        if (count($teachers) > 0) {
5574
            foreach ($teachers as $userId) {
5575
                $userId = intval($userId);
5576
                // We check if the teacher is already subscribed in this course
5577
                $sql = "SELECT 1 FROM $course_user_table
5578
                        WHERE user_id = $userId AND c_id = $courseId";
5579
                $result = Database::query($sql);
5580
                if (Database::num_rows($result)) {
5581
                    $sql = "UPDATE $course_user_table
5582
                            SET status = 1
5583
                            WHERE c_id = $courseId AND user_id = $userId ";
5584
                } else {
5585
                    $userCourseCategory = '0';
5586
                    if (isset($teacherBackup[$userId]) &&
5587
                        isset($teacherBackup[$userId][$course_code])
5588
                    ) {
5589
                        $courseUserData = $teacherBackup[$userId][$course_code];
5590
                        $userCourseCategory = $courseUserData['user_course_cat'];
5591
                        if ($logger) {
5592
                            $logger->addInfo("Recovering user_course_cat: $userCourseCategory");
5593
                        }
5594
                    }
5595
5596
                    $sql = "INSERT INTO $course_user_table SET
5597
                            c_id = $courseId,
5598
                            user_id = $userId,
5599
                            status = 1,
5600
                            is_tutor = 0,
5601
                            sort = 0,
5602
                            relation_type = 0,
5603
                            user_course_cat = $userCourseCategory
5604
                    ";
5605
                }
5606
                Database::query($sql);
5607
            }
5608
        }
5609
5610
        if ($editTeacherInSessions) {
5611
            $sessions = SessionManager::get_session_by_course($courseId);
5612
            if (!empty($sessions)) {
5613
                if ($logger) {
5614
                    $logger->addInfo("Edit teachers in sessions");
5615
                }
5616
                foreach ($sessions as $session) {
5617
                    $sessionId = $session['id'];
5618
                    // Remove old and add new
5619
                    if ($deleteSessionTeacherNotInList) {
5620
                        foreach ($teachers as $userId) {
5621
                            if ($logger) {
5622
                                $logger->addInfo("Set coach #$userId in session #$sessionId of course #$courseId ");
5623
                            }
5624
                            SessionManager::set_coach_to_course_session(
5625
                                $userId,
5626
                                $sessionId,
5627
                                $courseId
5628
                            );
5629
                        }
5630
5631
                        $teachersToDelete = [];
5632
                        if (!empty($alreadyAddedTeachers)) {
5633
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
5634
                        }
5635
5636
                        if (!empty($teachersToDelete)) {
5637
                            foreach ($teachersToDelete as $userId) {
5638
                                if ($logger) {
5639
                                    $logger->addInfo("Delete coach #$userId in session #$sessionId of course #$courseId ");
5640
                                }
5641
                                SessionManager::set_coach_to_course_session(
5642
                                    $userId,
5643
                                    $sessionId,
5644
                                    $courseId,
5645
                                    true
5646
                                );
5647
                            }
5648
                        }
5649
                    } else {
5650
                        // Add new teachers only
5651
                        foreach ($teachers as $userId) {
5652
                            if ($logger) {
5653
                                $logger->addInfo("Add coach #$userId in session #$sessionId of course #$courseId ");
5654
                            }
5655
                            SessionManager::set_coach_to_course_session(
5656
                                $userId,
5657
                                $sessionId,
5658
                                $courseId
5659
                            );
5660
                        }
5661
                    }
5662
                }
5663
            }
5664
        }
5665
    }
5666
5667
    /**
5668
     * Course available settings variables see c_course_setting table.
5669
     *
5670
     * @return array
5671
     */
5672
    public static function getCourseSettingVariables(AppPlugin $appPlugin)
5673
    {
5674
        $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
5675
        $courseSettings = [
5676
            // Get allow_learning_path_theme from table
5677
            'allow_learning_path_theme',
5678
            // Get allow_open_chat_window from table
5679
            'allow_open_chat_window',
5680
            'allow_public_certificates',
5681
            // Get allow_user_edit_agenda from table
5682
            'allow_user_edit_agenda',
5683
            // Get allow_user_edit_announcement from table
5684
            'allow_user_edit_announcement',
5685
            // Get allow_user_image_forum from table
5686
            'allow_user_image_forum',
5687
            //Get allow show user list
5688
            'allow_user_view_user_list',
5689
            // Get course_theme from table
5690
            'course_theme',
5691
            //Get allow show user list
5692
            'display_info_advance_inside_homecourse',
5693
            'documents_default_visibility',
5694
            // Get send_mail_setting (work)from table
5695
            'email_alert_manager_on_new_doc',
5696
            // Get send_mail_setting (work)from table
5697
            'email_alert_manager_on_new_quiz',
5698
            // Get send_mail_setting (dropbox) from table
5699
            'email_alert_on_new_doc_dropbox',
5700
            'email_alert_students_on_new_homework',
5701
            // Get send_mail_setting (auth)from table
5702
            'email_alert_to_teacher_on_new_user_in_course',
5703
            'enable_lp_auto_launch',
5704
            'enable_exercise_auto_launch',
5705
            'enable_document_auto_launch',
5706
            'pdf_export_watermark_text',
5707
            'show_system_folders',
5708
            'exercise_invisible_in_session',
5709
            'enable_forum_auto_launch',
5710
            'show_course_in_user_language',
5711
            'email_to_teachers_on_new_work_feedback',
5712
            'student_delete_own_publication',
5713
            'hide_forum_notifications',
5714
            'quiz_question_limit_per_day',
5715
            'subscribe_users_to_forum_notifications',
5716
        ];
5717
5718
        $courseModels = ExerciseLib::getScoreModels();
5719
        if (!empty($courseModels)) {
5720
            $courseSettings[] = 'score_model_id';
5721
        }
5722
5723
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5724
        if ('true' === $allowLPReturnLink) {
5725
            $courseSettings[] = 'lp_return_link';
5726
        }
5727
5728
        if (!empty($pluginCourseSettings)) {
5729
            $courseSettings = array_merge(
5730
                $courseSettings,
5731
                $pluginCourseSettings
5732
            );
5733
        }
5734
5735
        return $courseSettings;
5736
    }
5737
5738
    /**
5739
     * @param string       $variable
5740
     * @param string|array $value
5741
     * @param int          $courseId
5742
     *
5743
     * @return bool
5744
     */
5745
    public static function saveCourseConfigurationSetting(AppPlugin $appPlugin, $variable, $value, $courseId)
5746
    {
5747
        $settingList = self::getCourseSettingVariables($appPlugin);
5748
5749
        if (!in_array($variable, $settingList)) {
5750
            return false;
5751
        }
5752
5753
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5754
5755
        if (is_array($value)) {
5756
            $value = implode(',', $value);
5757
        }
5758
5759
        $settingFromDatabase = self::getCourseSetting($variable, $courseId);
5760
5761
        if (!empty($settingFromDatabase)) {
5762
            // Update
5763
            Database::update(
5764
                $courseSettingTable,
5765
                ['value' => $value],
5766
                ['variable = ? AND c_id = ?' => [$variable, $courseId]]
5767
            );
5768
5769
            if ($settingFromDatabase['value'] != $value) {
5770
                Event::addEvent(
5771
                    LOG_COURSE_SETTINGS_CHANGED,
5772
                    $variable,
5773
                    $settingFromDatabase['value']." -> $value"
5774
                );
5775
            }
5776
        } else {
5777
            // Create
5778
            Database::insert(
5779
                $courseSettingTable,
5780
                [
5781
                    'title' => $variable,
5782
                    'value' => $value,
5783
                    'c_id' => $courseId,
5784
                    'variable' => $variable,
5785
                ]
5786
            );
5787
5788
            Event::addEvent(
5789
                LOG_COURSE_SETTINGS_CHANGED,
5790
                $variable,
5791
                $value
5792
            );
5793
        }
5794
5795
        return true;
5796
    }
5797
5798
    /**
5799
     * Get course setting.
5800
     *
5801
     * @param string $variable
5802
     * @param int    $courseId
5803
     *
5804
     * @return array
5805
     */
5806
    public static function getCourseSetting($variable, $courseId)
5807
    {
5808
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5809
        $courseId = (int) $courseId;
5810
        $variable = Database::escape_string($variable);
5811
        $sql = "SELECT variable, value FROM $courseSetting
5812
                WHERE c_id = $courseId AND variable = '$variable'";
5813
        $result = Database::query($sql);
5814
5815
        return Database::fetch_array($result);
5816
    }
5817
5818
    public static function saveSettingChanges($courseInfo, $params)
5819
    {
5820
        if (empty($courseInfo) || empty($params)) {
5821
            return false;
5822
        }
5823
5824
        $userId = api_get_user_id();
5825
        $now = api_get_utc_datetime();
5826
5827
        foreach ($params as $name => $value) {
5828
            $emptyValue = ' - ';
5829
            if (isset($courseInfo[$name]) && $courseInfo[$name] != $value) {
5830
                if ('' !== $courseInfo[$name]) {
5831
                    $emptyValue = $courseInfo[$name];
5832
                }
5833
5834
                $changedTo = $emptyValue.' -> '.$value;
5835
5836
                Event::addEvent(
5837
                    LOG_COURSE_SETTINGS_CHANGED,
5838
                    $name,
5839
                    $changedTo,
5840
                    $now,
5841
                    $userId,
5842
                    $courseInfo['real_id']
5843
                );
5844
            }
5845
        }
5846
5847
        return true;
5848
    }
5849
5850
    /**
5851
     * Get information from the track_e_course_access table.
5852
     *
5853
     * @param int    $courseId
5854
     * @param int    $sessionId
5855
     * @param string $startDate
5856
     * @param string $endDate
5857
     *
5858
     * @return array
5859
     */
5860
    public static function getCourseAccessPerCourseAndSession(
5861
        $courseId,
5862
        $sessionId,
5863
        $startDate,
5864
        $endDate
5865
    ) {
5866
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5867
        $courseId = (int) $courseId;
5868
        $sessionId = (int) $sessionId;
5869
        $startDate = Database::escape_string($startDate);
5870
        $endDate = Database::escape_string($endDate);
5871
5872
        $sql = "SELECT * FROM $table
5873
                WHERE
5874
                    c_id = $courseId AND
5875
                    session_id = $sessionId AND
5876
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5877
                ";
5878
5879
        $result = Database::query($sql);
5880
5881
        return Database::store_result($result);
5882
    }
5883
5884
    /**
5885
     * Get login information from the track_e_course_access table, for any
5886
     * course in the given session.
5887
     *
5888
     * @param int $sessionId
5889
     * @param int $userId
5890
     *
5891
     * @return array
5892
     */
5893
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5894
    {
5895
        $sessionId = (int) $sessionId;
5896
        $userId = (int) $userId;
5897
5898
        $table = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5899
        $sql = "SELECT * FROM $table
5900
                WHERE session_id = $sessionId AND user_id = $userId
5901
                ORDER BY login_course_date ASC
5902
                LIMIT 1";
5903
5904
        $result = Database::query($sql);
5905
        $courseAccess = [];
5906
        if (Database::num_rows($result)) {
5907
            $courseAccess = Database::fetch_array($result, 'ASSOC');
5908
        }
5909
5910
        return $courseAccess;
5911
    }
5912
5913
    /**
5914
     * @param int  $courseId
5915
     * @param int  $sessionId
5916
     * @param bool $getAllSessions
5917
     *
5918
     * @return mixed
5919
     */
5920
    public static function getCountForum(
5921
        $courseId,
5922
        $sessionId = 0,
5923
        $getAllSessions = false
5924
    ) {
5925
        $forum = Database::get_course_table(TABLE_FORUM);
5926
        if ($getAllSessions) {
5927
            $sql = "SELECT count(*) as count
5928
                    FROM $forum f
5929
                    WHERE f.c_id = %s";
5930
        } else {
5931
            $sql = "SELECT count(*) as count
5932
                    FROM $forum f
5933
                    WHERE f.c_id = %s and f.session_id = %s";
5934
        }
5935
5936
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5937
        $result = Database::query($sql);
5938
        $row = Database::fetch_array($result);
5939
5940
        return $row['count'];
5941
    }
5942
5943
    /**
5944
     * @param int $userId
5945
     * @param int $courseId
5946
     * @param int $sessionId
5947
     *
5948
     * @return mixed
5949
     */
5950
    public static function getCountPostInForumPerUser(
5951
        $userId,
5952
        $courseId,
5953
        $sessionId = 0
5954
    ) {
5955
        $forum = Database::get_course_table(TABLE_FORUM);
5956
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5957
5958
        $sql = "SELECT count(distinct post_id) as count
5959
                FROM $forum_post p
5960
                INNER JOIN $forum f
5961
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5962
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5963
5964
        $sql = sprintf(
5965
            $sql,
5966
            intval($userId),
5967
            intval($sessionId),
5968
            intval($courseId)
5969
        );
5970
5971
        $result = Database::query($sql);
5972
        $row = Database::fetch_array($result);
5973
5974
        return $row['count'];
5975
    }
5976
5977
    /**
5978
     * @param int $userId
5979
     * @param int $courseId
5980
     * @param int $sessionId
5981
     *
5982
     * @return mixed
5983
     */
5984
    public static function getCountForumPerUser(
5985
        $userId,
5986
        $courseId,
5987
        $sessionId = 0
5988
    ) {
5989
        $forum = Database::get_course_table(TABLE_FORUM);
5990
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5991
5992
        $sql = "SELECT count(distinct f.forum_id) as count
5993
                FROM $forum_post p
5994
                INNER JOIN $forum f
5995
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5996
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5997
5998
        $sql = sprintf(
5999
            $sql,
6000
            intval($userId),
6001
            intval($sessionId),
6002
            intval($courseId)
6003
        );
6004
6005
        $result = Database::query($sql);
6006
        $row = Database::fetch_array($result);
6007
6008
        return $row['count'];
6009
    }
6010
6011
    /**
6012
     * Returns the course name from a given code.
6013
     *
6014
     * @param string $code
6015
     *
6016
     * @return string
6017
     */
6018
    public static function getCourseNameFromCode($code)
6019
    {
6020
        $tbl_main_categories = Database::get_main_table(TABLE_MAIN_COURSE);
6021
        $code = Database::escape_string($code);
6022
        $sql = "SELECT title
6023
                FROM $tbl_main_categories
6024
                WHERE code = '$code'";
6025
        $result = Database::query($sql);
6026
        if ($col = Database::fetch_array($result)) {
6027
            return $col['title'];
6028
        }
6029
    }
6030
6031
    /**
6032
     * Generates a course code from a course title.
6033
     *
6034
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
6035
     * @todo the function might be upgraded for avoiding code duplications (currently,
6036
     * it might suggest a code that is already in use)
6037
     *
6038
     * @param string $title A course title
6039
     *
6040
     * @return string A proposed course code
6041
     *                +
6042
     * @assert (null,null) === false
6043
     * @assert ('ABC_DEF', null) === 'ABCDEF'
6044
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
6045
     */
6046
    public static function generate_course_code($title)
6047
    {
6048
        return substr(
6049
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
6050
            0,
6051
            self::MAX_COURSE_LENGTH_CODE
6052
        );
6053
    }
6054
6055
    /**
6056
     * this function gets all the users of the course,
6057
     * including users from linked courses.
6058
     *
6059
     * @param $filterByActive
6060
     *
6061
     * @return array
6062
     */
6063
    public static function getCourseUsers($filterByActive = null)
6064
    {
6065
        // This would return only the users from real courses:
6066
        return self::get_user_list_from_course_code(
6067
            api_get_course_id(),
6068
            api_get_session_id(),
6069
            null,
6070
            null,
6071
            null,
6072
            null,
6073
            false,
6074
            false,
6075
            [],
6076
            [],
6077
            [],
6078
            $filterByActive
6079
        );
6080
    }
6081
6082
    /**
6083
     * this function gets all the groups of the course,
6084
     * not including linked courses.
6085
     */
6086
    public static function getCourseGroups()
6087
    {
6088
        $sessionId = api_get_session_id();
6089
        if (0 != $sessionId) {
6090
            $groupList = self::get_group_list_of_course(
6091
                api_get_course_id(),
6092
                $sessionId,
6093
                1
6094
            );
6095
        } else {
6096
            $groupList = self::get_group_list_of_course(
6097
                api_get_course_id(),
6098
                0,
6099
                1
6100
            );
6101
        }
6102
6103
        return $groupList;
6104
    }
6105
6106
    /**
6107
     * @param FormValidator $form
6108
     * @param array         $alreadySelected
6109
     *
6110
     * @return HTML_QuickForm_element
6111
     */
6112
    public static function addUserGroupMultiSelect(&$form, $alreadySelected, $addShortCut = false)
6113
    {
6114
        $userList = self::getCourseUsers(true);
6115
        $groupList = self::getCourseGroups();
6116
6117
        $array = self::buildSelectOptions(
6118
            $groupList,
6119
            $userList,
6120
            $alreadySelected
6121
        );
6122
6123
        $result = [];
6124
        foreach ($array as $content) {
6125
            $result[$content['value']] = $content['content'];
6126
        }
6127
6128
        $multiple = $form->addElement(
6129
            'advmultiselect',
6130
            'users',
6131
            get_lang('Users'),
6132
            $result,
6133
            ['select_all_checkbox' => true, 'id' => 'users']
6134
        );
6135
6136
        $sessionId = api_get_session_id();
6137
        if ($addShortCut && empty($sessionId)) {
6138
            $addStudents = [];
6139
            foreach ($userList as $user) {
6140
                if ($user['status_rel'] == STUDENT) {
6141
                    $addStudents[] = $user['user_id'];
6142
                }
6143
            }
6144
            if (!empty($addStudents)) {
6145
                $form->addHtml(
6146
                    '<script>
6147
                    $(function() {
6148
                        $("#add_students").on("click", function() {
6149
                            var addStudents = '.json_encode($addStudents).';
6150
                            $.each(addStudents, function( index, value ) {
6151
                                var option = $("#users option[value=\'USER:"+value+"\']");
6152
                                if (option.val()) {
6153
                                    $("#users_to").append(new Option(option.text(), option.val()))
6154
                                    option.remove();
6155
                                }
6156
                            });
6157
6158
                            return false;
6159
                        });
6160
                    });
6161
                    </script>'
6162
                );
6163
6164
                $form->addLabel(
6165
                    '',
6166
                    Display::url(get_lang('AddStudent'), '#', ['id' => 'add_students', 'class' => 'btn btn-primary'])
6167
                );
6168
            }
6169
        }
6170
6171
        return $multiple;
6172
    }
6173
6174
    /**
6175
     * This function separates the users from the groups
6176
     * users have a value USER:XXX (with XXX the groups id have a value
6177
     *  GROUP:YYY (with YYY the group id).
6178
     *
6179
     * @param array $to Array of strings that define the type and id of each destination
6180
     *
6181
     * @return array Array of groups and users (each an array of IDs)
6182
     */
6183
    public static function separateUsersGroups($to)
6184
    {
6185
        $groupList = [];
6186
        $userList = [];
6187
6188
        foreach ($to as $to_item) {
6189
            if (!empty($to_item)) {
6190
                $parts = explode(':', $to_item);
6191
                $type = isset($parts[0]) ? $parts[0] : '';
6192
                $id = isset($parts[1]) ? $parts[1] : '';
6193
6194
                switch ($type) {
6195
                    case 'GROUP':
6196
                        $groupList[] = (int) $id;
6197
                        break;
6198
                    case 'USER':
6199
                        $userList[] = (int) $id;
6200
                        break;
6201
                }
6202
            }
6203
        }
6204
6205
        $send_to['groups'] = $groupList;
6206
        $send_to['users'] = $userList;
6207
6208
        return $send_to;
6209
    }
6210
6211
    /**
6212
     * Shows the form for sending a message to a specific group or user.
6213
     *
6214
     * @param FormValidator $form
6215
     * @param array         $groupInfo
6216
     * @param array         $to
6217
     *
6218
     * @return HTML_QuickForm_element
6219
     */
6220
    public static function addGroupMultiSelect($form, $groupInfo, $to = [])
6221
    {
6222
        $groupUsers = GroupManager::get_subscribed_users($groupInfo);
6223
        $array = self::buildSelectOptions([$groupInfo], $groupUsers, $to);
6224
6225
        $result = [];
6226
        foreach ($array as $content) {
6227
            $result[$content['value']] = $content['content'];
6228
        }
6229
6230
        return $form->addElement('advmultiselect', 'users', get_lang('Users'), $result);
6231
    }
6232
6233
    /**
6234
     * this function shows the form for sending a message to a specific group or user.
6235
     *
6236
     * @param array $groupList
6237
     * @param array $userList
6238
     * @param array $alreadySelected
6239
     *
6240
     * @return array
6241
     */
6242
    public static function buildSelectOptions(
6243
        $groupList = [],
6244
        $userList = [],
6245
        $alreadySelected = []
6246
    ) {
6247
        if (empty($alreadySelected)) {
6248
            $alreadySelected = [];
6249
        }
6250
6251
        $result = [];
6252
        // adding the groups to the select form
6253
        if ($groupList) {
6254
            foreach ($groupList as $thisGroup) {
6255
                $groupId = $thisGroup['iid'];
6256
                if (is_array($alreadySelected)) {
6257
                    if (!in_array(
6258
                        "GROUP:".$groupId,
6259
                        $alreadySelected
6260
                    )
6261
                    ) {
6262
                        $userCount = isset($thisGroup['userNb']) ? $thisGroup['userNb'] : 0;
6263
                        if (empty($userCount)) {
6264
                            $userCount = isset($thisGroup['count_users']) ? $thisGroup['count_users'] : 0;
6265
                        }
6266
                        // $alreadySelected is the array containing the groups (and users) that are already selected
6267
                        $user_label = ($userCount > 0) ? get_lang('Users') : get_lang('user');
6268
                        $user_disabled = ($userCount > 0) ? "" : "disabled=disabled";
6269
                        $result[] = [
6270
                            'disabled' => $user_disabled,
6271
                            'value' => "GROUP:".$groupId,
6272
                            // The space before "G" is needed in order to advmultiselect.php js puts groups first
6273
                            'content' => " G: ".$thisGroup['name']." - ".$userCount." ".$user_label,
6274
                        ];
6275
                    }
6276
                }
6277
            }
6278
        }
6279
6280
        // adding the individual users to the select form
6281
        if ($userList) {
6282
            foreach ($userList as $user) {
6283
                if (is_array($alreadySelected)) {
6284
                    if (!in_array(
6285
                        "USER:".$user['user_id'],
6286
                        $alreadySelected
6287
                    )
6288
                    ) {
6289
                        // $alreadySelected is the array containing the users (and groups) that are already selected
6290
                        $result[] = [
6291
                            'value' => "USER:".$user['user_id'],
6292
                            'content' => api_get_person_name($user['firstname'], $user['lastname']),
6293
                        ];
6294
                    }
6295
                }
6296
            }
6297
        }
6298
6299
        return $result;
6300
    }
6301
6302
    /**
6303
     * @return array a list (array) of all courses
6304
     */
6305
    public static function get_course_list()
6306
    {
6307
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6308
6309
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
6310
    }
6311
6312
    /**
6313
     * Returns course code from a given gradebook category's id.
6314
     *
6315
     * @param int  Category ID
6316
     *
6317
     * @return string Course code
6318
     */
6319
    public static function get_course_by_category($category_id)
6320
    {
6321
        $category_id = (int) $category_id;
6322
        $sql = 'SELECT c_id FROM '.Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY).'
6323
                WHERE id='.$category_id;
6324
        $info = Database::fetch_array(Database::query($sql), 'ASSOC');
6325
6326
        return $info ? $info['c_id'] : false;
6327
    }
6328
6329
    /**
6330
     * This function gets all the courses that are not in a session.
6331
     *
6332
     * @param date Start date
6333
     * @param date End date
6334
     * @param bool $includeClosed Whether to include closed and hidden courses
6335
     *
6336
     * @return array Not-in-session courses
6337
     */
6338
    public static function getCoursesWithoutSession(
6339
        $startDate = null,
6340
        $endDate = null,
6341
        $includeClosed = false
6342
    ) {
6343
        $dateConditional = ($startDate && $endDate) ?
6344
            " WHERE session_id IN (SELECT id FROM ".Database::get_main_table(TABLE_MAIN_SESSION).
6345
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" : null;
6346
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
6347
6348
        $sql = "SELECT id, code, title
6349
                FROM ".Database::get_main_table(TABLE_MAIN_COURSE)."
6350
                WHERE $visibility code NOT IN (
6351
                    SELECT DISTINCT course_code
6352
                    FROM ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE).$dateConditional."
6353
                )
6354
                ORDER BY id";
6355
6356
        $result = Database::query($sql);
6357
        $courses = [];
6358
        while ($row = Database::fetch_array($result)) {
6359
            $courses[] = $row;
6360
        }
6361
6362
        return $courses;
6363
    }
6364
6365
    /**
6366
     * Get list of courses based on users of a group for a group admin.
6367
     *
6368
     * @param int $userId The user id
6369
     *
6370
     * @return array
6371
     */
6372
    public static function getCoursesFollowedByGroupAdmin($userId)
6373
    {
6374
        $coursesList = [];
6375
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
6376
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6377
        $userGroup = new UserGroup();
6378
        $userIdList = $userGroup->getGroupUsersByUser($userId);
6379
6380
        if (empty($userIdList)) {
6381
            return [];
6382
        }
6383
6384
        $sql = "SELECT DISTINCT(c.id), c.title
6385
                FROM $courseTable c
6386
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6387
                WHERE (
6388
                    cru.user_id IN (".implode(', ', $userIdList).")
6389
                    AND cru.relation_type = 0
6390
                )";
6391
6392
        if (api_is_multiple_url_enabled()) {
6393
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6394
            $accessUrlId = api_get_current_access_url_id();
6395
6396
            if (-1 != $accessUrlId) {
6397
                $sql = "SELECT DISTINCT(c.id), c.title
6398
                        FROM $courseTable c
6399
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
6400
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
6401
                        WHERE crau.access_url_id = $accessUrlId
6402
                            AND (
6403
                            cru.id_user IN (".implode(', ', $userIdList).") AND
6404
                            cru.relation_type = 0
6405
                        )";
6406
            }
6407
        }
6408
6409
        $result = Database::query($sql);
6410
        while ($row = Database::fetch_assoc($result)) {
6411
            $coursesList[] = $row;
6412
        }
6413
6414
        return $coursesList;
6415
    }
6416
6417
    /**
6418
     * Direct course link see #5299.
6419
     *
6420
     * You can send to your students an URL like this
6421
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
6422
     * Where "c" is the course code and "e" is the exercise Id, after a successful
6423
     * registration the user will be sent to the course or exercise
6424
     *
6425
     * @param array $form_data
6426
     *
6427
     * @return array
6428
     */
6429
    public static function redirectToCourse($form_data)
6430
    {
6431
        $course_code_redirect = Session::read('course_redirect');
6432
        $_user = api_get_user_info();
6433
        $userId = api_get_user_id();
6434
6435
        if (!empty($course_code_redirect)) {
6436
            $course_info = api_get_course_info($course_code_redirect);
6437
            if (!empty($course_info)) {
6438
                if (in_array(
6439
                    $course_info['visibility'],
6440
                    [COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD]
6441
                )
6442
                ) {
6443
                    if (self::is_user_subscribed_in_course($userId, $course_info['code'])) {
6444
                        $form_data['action'] = $course_info['course_public_url'];
6445
                        $form_data['message'] = sprintf(get_lang('You have been registered to course %s'), $course_info['title']);
6446
                        $form_data['button'] = Display::button(
6447
                            'next',
6448
                            get_lang('Go to the course', null, $_user['language']),
6449
                            ['class' => 'btn btn-primary btn-large']
6450
                        );
6451
6452
                        $exercise_redirect = (int) Session::read('exercise_redirect');
6453
                        // Specify the course id as the current context does not
6454
                        // hold a global $_course array
6455
                        $objExercise = new Exercise($course_info['real_id']);
6456
                        $result = $objExercise->read($exercise_redirect);
6457
6458
                        if (!empty($exercise_redirect) && !empty($result)) {
6459
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).
6460
                                'exercise/overview.php?exerciseId='.$exercise_redirect.'&cid='.$course_info['real_id'];
6461
                            $form_data['message'] .= '<br />'.get_lang('Go to the test');
6462
                            $form_data['button'] = Display::button(
6463
                                'next',
6464
                                get_lang('Go', null, $_user['language']),
6465
                                ['class' => 'btn btn-primary btn-large']
6466
                            );
6467
                        }
6468
6469
                        if (!empty($form_data['action'])) {
6470
                            header('Location: '.$form_data['action']);
6471
                            exit;
6472
                        }
6473
                    }
6474
                }
6475
            }
6476
        }
6477
6478
        return $form_data;
6479
    }
6480
6481
    /**
6482
     * Return tab of params to display a course title in the My Courses tab
6483
     * Check visibility, right, and notification icons, and load_dirs option
6484
     * get html course params.
6485
     *
6486
     * @param $courseId
6487
     * @param bool $loadDirs
6488
     *
6489
     * @return array with keys ['right_actions'] ['teachers'] ['notifications']
6490
     */
6491
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
6492
    {
6493
        $userId = api_get_user_id();
6494
        $courseId = intval($courseId);
6495
        // Table definitions
6496
        $TABLECOURS = Database::get_main_table(TABLE_MAIN_COURSE);
6497
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6498
        $TABLE_ACCESS_URL_REL_COURSE = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
6499
        $current_url_id = api_get_current_access_url_id();
6500
6501
        // Get course list auto-register
6502
        $special_course_list = self::get_special_course_list();
6503
6504
        $without_special_courses = '';
6505
        if (!empty($special_course_list)) {
6506
            $without_special_courses = ' AND course.id NOT IN ("'.implode('","', $special_course_list).'")';
6507
        }
6508
6509
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
6510
        $sql = "SELECT
6511
                    course.id,
6512
                    course.title,
6513
                    course.code,
6514
                    course.subscribe subscr,
6515
                    course.unsubscribe unsubscr,
6516
                    course_rel_user.status status,
6517
                    course_rel_user.sort sort,
6518
                    course_rel_user.user_course_cat user_course_cat
6519
                FROM
6520
                $TABLECOURS course
6521
                INNER JOIN $TABLECOURSUSER course_rel_user
6522
                ON (course.id = course_rel_user.c_id)
6523
                INNER JOIN $TABLE_ACCESS_URL_REL_COURSE url
6524
                ON (url.c_id = course.id)
6525
                WHERE
6526
                    course.id = $courseId AND
6527
                    course_rel_user.user_id = $userId
6528
                    $without_special_courses
6529
                ";
6530
6531
        // If multiple URL access mode is enabled, only fetch courses
6532
        // corresponding to the current URL.
6533
        if (api_get_multiple_access_url() && -1 != $current_url_id) {
6534
            $sql .= " AND url.c_id = course.id AND access_url_id = $current_url_id";
6535
        }
6536
        // Use user's classification for courses (if any).
6537
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
6538
6539
        $result = Database::query($sql);
6540
6541
        // Browse through all courses. We can only have one course because
6542
        // of the  course.id=".intval($courseId) in sql query
6543
        $course = Database::fetch_array($result);
6544
        $course_info = api_get_course_info_by_id($courseId);
6545
        if (empty($course_info)) {
6546
            return '';
6547
        }
6548
6549
        //$course['id_session'] = null;
6550
        $course_info['id_session'] = null;
6551
        $course_info['status'] = $course['status'];
6552
6553
        // For each course, get if there is any notification icon to show
6554
        // (something that would have changed since the user's last visit).
6555
        $show_notification = !api_get_configuration_value('hide_course_notification')
6556
            ? Display::show_notification($course_info)
6557
            : '';
6558
6559
        // New code displaying the user's status in respect to this course.
6560
        $status_icon = Display::return_icon(
6561
            'blackboard.png',
6562
            $course_info['title'],
6563
            [],
6564
            ICON_SIZE_LARGE
6565
        );
6566
6567
        $params = [];
6568
        $params['right_actions'] = '';
6569
6570
        if (api_is_platform_admin()) {
6571
            if ($loadDirs) {
6572
                $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>';
6573
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6574
                    Display::return_icon('edit.png', get_lang('Edit'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).
6575
                    '</a>';
6576
                $params['right_actions'] .= Display::div(
6577
                    '',
6578
                    [
6579
                        'id' => 'document_result_'.$course_info['real_id'].'_0',
6580
                        'class' => 'document_preview_container',
6581
                    ]
6582
                );
6583
            } else {
6584
                $params['right_actions'] .=
6585
                    '<a class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6586
                    Display::returnFontAwesomeIcon('pencil').'</a>';
6587
            }
6588
        } else {
6589
            if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
6590
                if ($loadDirs) {
6591
                    $params['right_actions'] .= '<a id="document_preview_'.$course_info['real_id'].'_0" class="document_preview" href="javascript:void(0);">'.
6592
                        Display::return_icon('folder.png', get_lang('Documents'), ['align' => 'absmiddle'], ICON_SIZE_SMALL).'</a>';
6593
                    $params['right_actions'] .= Display::div(
6594
                        '',
6595
                        [
6596
                            'id' => 'document_result_'.$course_info['real_id'].'_0',
6597
                            'class' => 'document_preview_container',
6598
                        ]
6599
                    );
6600
                } else {
6601
                    if (COURSEMANAGER == $course_info['status']) {
6602
                        $params['right_actions'] .= '<a
6603
                            class="btn btn-default btn-sm" title="'.get_lang('Edit').'" href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cid='.$course['real_id'].'">'.
6604
                            Display::returnFontAwesomeIcon('pencil').'</a>';
6605
                    }
6606
                }
6607
            }
6608
        }
6609
6610
        $course_title_url = '';
6611
        if (COURSE_VISIBILITY_CLOSED != $course_info['visibility'] || COURSEMANAGER == $course['status']) {
6612
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
6613
            $course_title = Display::url($course_info['title'], $course_title_url);
6614
        } else {
6615
            $course_title = $course_info['title'].' '.Display::tag(
6616
                'span',
6617
                get_lang('(the course is currently closed)'),
6618
                ['class' => 'item_closed']
6619
            );
6620
        }
6621
6622
        // Start displaying the course block itself
6623
        if ('true' === api_get_setting('display_coursecode_in_courselist')) {
6624
            $course_title .= ' ('.$course_info['visual_code'].') ';
6625
        }
6626
        $teachers = '';
6627
        if ('true' === api_get_setting('display_teacher_in_courselist')) {
6628
            $teachers = self::getTeacherListFromCourseCodeToString(
6629
                $course['code'],
6630
                self::USER_SEPARATOR,
6631
                true
6632
            );
6633
        }
6634
        $params['link'] = $course_title_url;
6635
        $params['icon'] = $status_icon;
6636
        $params['title'] = $course_title;
6637
        $params['teachers'] = $teachers;
6638
        if (COURSE_VISIBILITY_CLOSED != $course_info['visibility']) {
6639
            $params['notifications'] = $show_notification;
6640
        }
6641
6642
        return $params;
6643
    }
6644
6645
    /**
6646
     * Get the course id based on the original id and field name in the extra fields.
6647
     * Returns 0 if course was not found.
6648
     *
6649
     * @param string $original_course_id_value Original course id
6650
     * @param string $original_course_id_name  Original field name
6651
     *
6652
     * @return int Course id
6653
     */
6654
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
6655
    {
6656
        $extraFieldValue = new ExtraFieldValue('course');
6657
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
6658
            $original_course_id_name,
6659
            $original_course_id_value
6660
        );
6661
6662
        if ($value) {
6663
            return $value['item_id'];
6664
        }
6665
6666
        return 0;
6667
    }
6668
6669
    /**
6670
     * Helper function to create a default gradebook (if necessary) upon course creation.
6671
     *
6672
     * @param int    $modelId    The gradebook model ID
6673
     * @param string $courseCode Course code
6674
     */
6675
    public static function createDefaultGradebook($modelId, $courseCode)
6676
    {
6677
        if ('true' === api_get_setting('gradebook_enable_grade_model')) {
6678
            //Create gradebook_category for the new course and add
6679
            // a gradebook model for the course
6680
            if (isset($modelId) &&
6681
                !empty($modelId) &&
6682
                '-1' != $modelId
6683
            ) {
6684
                GradebookUtils::create_default_course_gradebook(
6685
                    $courseCode,
6686
                    $modelId
6687
                );
6688
            }
6689
        }
6690
    }
6691
6692
    /**
6693
     * Helper function to check if there is a course template and, if so, to
6694
     * copy the template as basis for the new course.
6695
     *
6696
     * @param string $courseCode     Course code
6697
     * @param int    $courseTemplate 0 if no course template is defined
6698
     */
6699
    public static function useTemplateAsBasisIfRequired($courseCode, $courseTemplate)
6700
    {
6701
        $template = api_get_setting('course_creation_use_template');
6702
        $teacherCanSelectCourseTemplate = 'true' === api_get_setting('teacher_can_select_course_template');
6703
        $courseTemplate = isset($courseTemplate) ? intval($courseTemplate) : 0;
6704
6705
        $useTemplate = false;
6706
6707
        if ($teacherCanSelectCourseTemplate && $courseTemplate) {
6708
            $useTemplate = true;
6709
            $originCourse = api_get_course_info_by_id($courseTemplate);
6710
        } elseif (!empty($template)) {
6711
            $useTemplate = true;
6712
            $originCourse = api_get_course_info_by_id($template);
6713
        }
6714
6715
        if ($useTemplate) {
6716
            // Include the necessary libraries to generate a course copy
6717
            // Call the course copy object
6718
            $originCourse['official_code'] = $originCourse['code'];
6719
            $cb = new CourseBuilder(null, $originCourse);
6720
            $course = $cb->build(null, $originCourse['code']);
6721
            $cr = new CourseRestorer($course);
6722
            $cr->set_file_option();
6723
            $cr->restore($courseCode);
6724
        }
6725
    }
6726
6727
    /**
6728
     * Helper method to get the number of users defined with a specific course extra field.
6729
     *
6730
     * @param string $name                 Field title
6731
     * @param string $tableExtraFields     The extra fields table name
6732
     * @param string $tableUserFieldValues The user extra field value table name
6733
     *
6734
     * @return int The number of users with this extra field with a specific value
6735
     */
6736
    public static function getCountRegisteredUsersWithCourseExtraField(
6737
        $name,
6738
        $tableExtraFields = '',
6739
        $tableUserFieldValues = ''
6740
    ) {
6741
        if (empty($tableExtraFields)) {
6742
            $tableExtraFields = Database::get_main_table(TABLE_EXTRA_FIELD);
6743
        }
6744
        if (empty($tableUserFieldValues)) {
6745
            $tableUserFieldValues = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
6746
        }
6747
6748
        $registered_users_with_extra_field = 0;
6749
        if (!empty($name) && '-' != $name) {
6750
            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
6751
            $name = Database::escape_string($name);
6752
            $sql = "SELECT count(v.item_id) as count
6753
                    FROM $tableUserFieldValues v
6754
                    INNER JOIN $tableExtraFields f
6755
                    ON (f.id = v.field_id)
6756
                    WHERE value = '$name' AND extra_field_type = $extraFieldType";
6757
            $result_count = Database::query($sql);
6758
            if (Database::num_rows($result_count)) {
6759
                $row_count = Database::fetch_array($result_count);
6760
                $registered_users_with_extra_field = $row_count['count'];
6761
            }
6762
        }
6763
6764
        return $registered_users_with_extra_field;
6765
    }
6766
6767
    /**
6768
     * Get the course categories form a course list.
6769
     *
6770
     * @return array
6771
     */
6772
    public static function getCourseCategoriesFromCourseList(array $courseList)
6773
    {
6774
        $allCategories = array_column($courseList, 'category');
6775
        $categories = array_unique($allCategories);
6776
6777
        sort($categories);
6778
6779
        return $categories;
6780
    }
6781
6782
    /**
6783
     * Display the description button of a course in the course catalog.
6784
     *
6785
     * @param array $course
6786
     * @param string $url
6787
     *
6788
     * @return string HTML string
6789
     */
6790
    public static function returnDescriptionButton($course)
6791
    {
6792
        if (empty($course)) {
6793
            return '';
6794
        }
6795
6796
        $class = '';
6797
        if (api_get_setting('show_courses_descriptions_in_catalog') === 'true') {
6798
            $title = $course['title'];
6799
            if (empty($url)) {
6800
                $class = 'ajax';
6801
                $url = api_get_path(WEB_CODE_PATH).
6802
                    'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'];
6803
            } else {
6804
                if (strpos($url, 'ajax') !== false) {
6805
                    $class = 'ajax';
6806
                }
6807
            }
6808
6809
            return Display::url(
6810
                Display::returnFontAwesomeIcon('info-circle', 'lg'),
6811
                $url,
6812
                [
6813
                    'class' => "$class btn btn-default btn-sm",
6814
                    'data-title' => $title,
6815
                    'title' => get_lang('Description'),
6816
                    'aria-label' => get_lang('Description'),
6817
                    'data-size' => 'lg',
6818
                ]
6819
            );
6820
        }
6821
6822
        return '';
6823
    }
6824
6825
    /**
6826
     * @return int
6827
     */
6828
    public static function getCountOpenCourses()
6829
    {
6830
        $visibility = [
6831
            COURSE_VISIBILITY_REGISTERED,
6832
            COURSE_VISIBILITY_OPEN_PLATFORM,
6833
            COURSE_VISIBILITY_OPEN_WORLD,
6834
        ];
6835
6836
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6837
        $sql = "SELECT count(id) count
6838
                FROM $table
6839
                WHERE visibility IN (".implode(',', $visibility).")";
6840
        $result = Database::query($sql);
6841
        $row = Database::fetch_array($result);
6842
6843
        return (int) $row['count'];
6844
    }
6845
6846
    /**
6847
     * @return int
6848
     */
6849
    public static function getCountExercisesFromOpenCourse()
6850
    {
6851
        $visibility = [
6852
            COURSE_VISIBILITY_REGISTERED,
6853
            COURSE_VISIBILITY_OPEN_PLATFORM,
6854
            COURSE_VISIBILITY_OPEN_WORLD,
6855
        ];
6856
6857
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
6858
        $tableExercise = Database::get_course_table(TABLE_QUIZ_TEST);
6859
        $sql = "SELECT count(e.iid) count
6860
                FROM $table c
6861
                INNER JOIN $tableExercise e
6862
                ON (c.id = e.c_id)
6863
                WHERE e.active <> -1 AND visibility IN (".implode(',', $visibility).")";
6864
        $result = Database::query($sql);
6865
        $row = Database::fetch_array($result);
6866
6867
        return (int) $row['count'];
6868
    }
6869
6870
    /**
6871
     * retrieves all the courses that the user has already subscribed to.
6872
     *
6873
     * @param int $user_id
6874
     *
6875
     * @return array an array containing all the information of the courses of the given user
6876
     */
6877
    public static function getCoursesByUserCourseCategory($user_id)
6878
    {
6879
        $course = Database::get_main_table(TABLE_MAIN_COURSE);
6880
        $courseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
6881
        $avoidCoursesCondition = CoursesAndSessionsCatalog::getAvoidCourseCondition();
6882
        $visibilityCondition = self::getCourseVisibilitySQLCondition('course', true);
6883
6884
        // Secondly we select the courses that are in a category (user_course_cat<>0) and
6885
        // sort these according to the sort of the category
6886
        $user_id = (int) $user_id;
6887
        $sql = "SELECT
6888
                    course.code k,
6889
                    course.visual_code vc,
6890
                    course.subscribe subscr,
6891
                    course.unsubscribe unsubscr,
6892
                    course.title i,
6893
                    course.tutor_name t,
6894
                    course.category_code cat,
6895
                    course.directory dir,
6896
                    course_rel_user.status status,
6897
                    course_rel_user.sort sort,
6898
                    course_rel_user.user_course_cat user_course_cat
6899
                FROM $course course, $courseRelUser course_rel_user
6900
                WHERE
6901
                    course.id = course_rel_user.c_id AND
6902
                    course_rel_user.relation_type <> ".COURSE_RELATION_TYPE_RRHH." AND
6903
                    course_rel_user.user_id = '".$user_id."'
6904
                    $avoidCoursesCondition
6905
                    $visibilityCondition
6906
                ORDER BY course_rel_user.sort ASC";
6907
6908
        $result = Database::query($sql);
6909
        $courses = [];
6910
        while ($row = Database::fetch_array($result, 'ASOC')) {
6911
            $courses[] = [
6912
                'code' => $row['k'],
6913
                'visual_code' => $row['vc'],
6914
                'title' => $row['i'],
6915
                'directory' => $row['dir'],
6916
                'status' => $row['status'],
6917
                'tutor' => $row['t'],
6918
                'subscribe' => $row['subscr'],
6919
                'category' => $row['cat'],
6920
                'unsubscribe' => $row['unsubscr'],
6921
                'sort' => $row['sort'],
6922
                'user_course_category' => $row['user_course_cat'],
6923
            ];
6924
        }
6925
6926
        return $courses;
6927
    }
6928
6929
    /**
6930
     * @param string $listType
6931
     *
6932
     * @return string
6933
     */
6934
    public static function getCourseListTabs($listType)
6935
    {
6936
        $tabs = [
6937
            [
6938
                'content' => get_lang('SimpleCourseList'),
6939
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list.php',
6940
            ],
6941
            [
6942
                'content' => get_lang('AdminCourseList'),
6943
                'url' => api_get_path(WEB_CODE_PATH).'admin/course_list_admin.php',
6944
            ],
6945
        ];
6946
6947
        $default = 1;
6948
        switch ($listType) {
6949
            case 'simple':
6950
                $default = 1;
6951
                break;
6952
            case 'admin':
6953
                $default = 2;
6954
                break;
6955
        }
6956
6957
        return Display::tabsOnlyLink($tabs, $default);
6958
    }
6959
6960
    /**
6961
     * @param ToolChain $toolList
6962
     */
6963
    public static function setToolList($toolList)
6964
    {
6965
        self::$toolList = $toolList;
6966
    }
6967
6968
    /**
6969
     * @return ToolChain
6970
     */
6971
    public static function getToolList()
6972
    {
6973
        return self::$toolList;
6974
    }
6975
6976
    /**
6977
     * Check if a specific access-url-related setting is a problem or not.
6978
     *
6979
     * @param array  $_configuration The $_configuration array
6980
     * @param int    $accessUrlId    The access URL ID
6981
     * @param string $param
6982
     * @param string $msgLabel
6983
     *
6984
     * @return bool|string
6985
     */
6986
    private static function checkCreateCourseAccessUrlParam($_configuration, $accessUrlId, $param, $msgLabel)
6987
    {
6988
        if (isset($_configuration[$accessUrlId][$param]) && $_configuration[$accessUrlId][$param] > 0) {
6989
            $num = null;
6990
            switch ($param) {
6991
                case 'hosting_limit_courses':
6992
            $num = self::count_courses($accessUrlId);
6993
                    break;
6994
                case 'hosting_limit_active_courses':
6995
                    $num = self::countActiveCourses($accessUrlId);
6996
                    break;
6997
            }
6998
6999
            if ($num && $num >= $_configuration[$accessUrlId][$param]) {
7000
                api_warn_hosting_contact($param);
7001
7002
                Display::addFlash(
7003
                    Display::return_message($msgLabel)
7004
                );
7005
7006
                return true;
7007
            }
7008
        }
7009
7010
        return false;
7011
    }
7012
7013
    /**
7014
     * Fill course with all necessary items.
7015
     *
7016
     * @param array $courseInfo Course info array
7017
     * @param array $params     Parameters from the course creation form
7018
     * @param int   $authorId
7019
     */
7020
    private static function fillCourse($courseInfo, $params, $authorId = 0)
7021
    {
7022
        $authorId = empty($authorId) ? api_get_user_id() : (int) $authorId;
7023
7024
        AddCourse::fillCourse(
7025
            $courseInfo,
7026
            $params['exemplary_content'],
7027
            $authorId
7028
        );
7029
7030
        if (isset($params['gradebook_model_id'])) {
7031
            self::createDefaultGradebook(
7032
                $params['gradebook_model_id'],
7033
                $courseInfo['code']
7034
            );
7035
        }
7036
7037
        // If parameter defined, copy the contents from a specific
7038
        // template course into this new course
7039
        if (isset($params['course_template'])) {
7040
            self::useTemplateAsBasisIfRequired(
7041
                $courseInfo['id'],
7042
                $params['course_template']
7043
            );
7044
        }
7045
        $params['course_code'] = $courseInfo['code'];
7046
        $params['item_id'] = $courseInfo['real_id'];
7047
7048
        $courseFieldValue = new ExtraFieldValue('course');
7049
        $courseFieldValue->saveFieldValues($params);
7050
    }
7051
}
7052