Passed
Pull Request — 1.10.x (#986)
by
unknown
182:31 queued 134:48
created

CourseManager::update_attributes()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 18
rs 9.2
cc 4
eloc 13
nc 4
nop 2
1
<?php
2
/* For licensing terms, see /license.txt*/
3
4
use Chamilo\CoreBundle\Entity\ExtraField as EntityExtraField;
5
use ChamiloSession as Session;
6
7
/**
8
 * Class CourseManager
9
 *
10
 * This is the course library for Chamilo.
11
 *
12
 * All main course functions should be placed here.
13
 *
14
 * Many functions of this library deal with providing support for
15
 * virtual/linked/combined courses (this was already used in several universities
16
 * but not available in standard Chamilo).
17
 *
18
 * There are probably some places left with the wrong code.
19
 *
20
 * @package chamilo.library
21
 */
22
class CourseManager
23
{
24
    const MAX_COURSE_LENGTH_CODE = 40;
25
    /** This constant is used to show separate user names in the course
26
     * list (userportal), footer, etc */
27
    const USER_SEPARATOR = ' |';
28
    const COURSE_FIELD_TYPE_CHECKBOX = 10;
29
    public $columns = array();
30
31
    /**
32
     * Creates a course
33
     * @param   array $params columns in the main.course table
34
     *
35
     * @return  mixed  false if the course was not created, array with the course info
36
     */
37
    public static function create_course($params, $extraFields = array())
38
    {
39
        global $_configuration;
40
        // Check portal limits
41
        $access_url_id = 1;
42
        if (api_get_multiple_access_url()) {
43
            $access_url_id = api_get_current_access_url_id();
44
        }
45
46
        if (isset($_configuration[$access_url_id]) &&
47
            is_array($_configuration[$access_url_id])
48
        ) {
49 View Code Duplication
            if (isset($_configuration[$access_url_id]['hosting_limit_courses']) &&
50
                $_configuration[$access_url_id]['hosting_limit_courses'] > 0
51
            ) {
52
                $num = self::count_courses($access_url_id);
53
                if ($num >= $_configuration[$access_url_id]['hosting_limit_courses']) {
54
                    api_warn_hosting_contact('hosting_limit_courses');
55
56
                    return api_set_failure(get_lang('PortalCoursesLimitReached'));
57
                }
58
            }
59
60 View Code Duplication
            if (isset($_configuration[$access_url_id]['hosting_limit_active_courses']) &&
61
                $_configuration[$access_url_id]['hosting_limit_active_courses'] > 0
62
            ) {
63
                $num = self::countActiveCourses($access_url_id);
64
                if ($num >= $_configuration[$access_url_id]['hosting_limit_active_courses']) {
65
                    api_warn_hosting_contact('hosting_limit_active_courses');
66
67
                    return api_set_failure(
68
                        get_lang('PortalActiveCoursesLimitReached')
69
                    );
70
                }
71
            }
72
        }
73
74
75
        if (empty($params['title'])) {
76
            return false;
77
        }
78
79
        if (empty($params['wanted_code'])) {
80
            $params['wanted_code'] = $params['title'];
81
            // Check whether the requested course code has already been occupied.
82
            $params['wanted_code'] = CourseManager::generate_course_code(
83
                api_substr($params['title'], 0, self::MAX_COURSE_LENGTH_CODE)
0 ignored issues
show
Security Bug introduced by
It seems like api_substr($params['titl...MAX_COURSE_LENGTH_CODE) targeting api_substr() can also be of type false; however, CourseManager::generate_course_code() does only seem to accept string, did you maybe forget to handle an error condition?
Loading history...
84
            );
85
        }
86
87
        // Create the course keys
88
        $keys = AddCourse::define_course_keys($params['wanted_code']);
89
90
        $params['exemplary_content'] = isset($params['exemplary_content']) ? $params['exemplary_content'] : false;
91
92
        if (count($keys)) {
93
94
            $params['code'] = $keys['currentCourseCode'];
95
            $params['visual_code'] = $keys['currentCourseId'];
96
            $params['directory'] = $keys['currentCourseRepository'];
97
98
            $course_info = api_get_course_info($params['code']);
99
100
            if (empty($course_info)) {
101
                $course_id = AddCourse::register_course($params);
102
                $course_info = api_get_course_info_by_id($course_id);
103
104
                if (!empty($course_info)) {
105
                    AddCourse::prepare_course_repository($course_info['directory'], $course_info['code']);
106
                    AddCourse::fill_db_course(
107
                        $course_id,
108
                        $course_info['directory'],
109
                        $course_info['course_language'],
110
                        $params['exemplary_content']
111
                    );
112
113
                    if (api_get_setting('gradebook_enable_grade_model') == 'true') {
114
                        //Create gradebook_category for the new course and add
115
                        // a gradebook model for the course
116
                        if (isset($params['gradebook_model_id']) &&
117
                            !empty($params['gradebook_model_id']) &&
118
                            $params['gradebook_model_id'] != '-1'
119
                        ) {
120
                            GradebookUtils::create_default_course_gradebook(
121
                                $course_info['code'],
122
                                $params['gradebook_model_id']
123
                            );
124
                        }
125
                    }
126
                    // If parameter defined, copy the contents from a specific
127
                    // template course into this new course
128
                    $template = api_get_setting('course_creation_use_template');
129
                    if (!empty($template)) {
130
                        // Include the necessary libraries to generate a course copy
131
                        require_once api_get_path(SYS_CODE_PATH) . 'coursecopy/classes/CourseBuilder.class.php';
132
                        require_once api_get_path(SYS_CODE_PATH) . 'coursecopy/classes/CourseRestorer.class.php';
133
                        require_once api_get_path(SYS_CODE_PATH) . 'coursecopy/classes/CourseSelectForm.class.php';
134
                        // Call the course copy object
135
                        $originCourse = api_get_course_info_by_id($template);
136
                        $originCourse['official_code'] = $originCourse['code'];
137
                        $cb = new CourseBuilder(null, $originCourse);
138
                        $course = $cb->build(null, $originCourse['code']);
139
                        $cr = new CourseRestorer($course);
140
                        $cr->set_file_option();
141
                        $cr->restore($course_info['id']); //course_info[id] is the course.code value (I know...)
142
                    }
143
144
                    $params['course_code'] = $course_info['code'];
145
                    $params['item_id'] = $course_info['real_id'];
146
147
                    $courseFieldValue = new ExtraFieldValue('course');
148
                    $courseFieldValue->saveFieldValues($params);
149
150
                    return $course_info;
151
                }
152
            }
153
        }
154
155
        return false;
156
    }
157
158
    /**
159
     * Returns all the information of a given course code
160
     * @param string $course_code , the course code
161
     * @return an array with all the fields of the course table
162
     * @author Patrick Cool <[email protected]>, Ghent University
163
     * @assert ('') === false
164
     */
165 View Code Duplication
    public static function get_course_information($course_code)
166
    {
167
        return Database::fetch_array(
168
            Database::query(
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...g($course_code) . '\'') can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
169
                "SELECT *, id as real_id FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . "
170
                WHERE code='" . Database::escape_string($course_code) . "'"), 'ASSOC'
171
        );
172
    }
173
174
    /**
175
     * Returns a list of courses. Should work with quickform syntax
176
     * @param    integer $from Offset (from the 7th = '6'). Optional.
177
     * @param    integer $howmany Number of results we want. Optional.
178
     * @param    int $orderby The column we want to order it by. Optional, defaults to first column.
179
     * @param    string $orderdirection The direction of the order (ASC or DESC). Optional, defaults to ASC.
180
     * @param    int $visibility The visibility of the course, or all by default.
181
     * @param    string $startwith If defined, only return results for which the course *title* begins with this string
182
     * @param    string $urlId The Access URL ID, if using multiple URLs
183
     * @param    bool $alsoSearchCode An extension option to indicate that we also want to search for course codes (not *only* titles)
184
     * @param    array $conditionsLike
185
     * @return array
186
     */
187
    public static function get_courses_list(
188
        $from = 0,
189
        $howmany = 0,
190
        $orderby = 1,
191
        $orderdirection = 'ASC',
192
        $visibility = -1,
193
        $startwith = '',
194
        $urlId = null,
195
        $alsoSearchCode = false,
196
        $conditionsLike = array()
197
    ) {
198
        $sql = "SELECT course.* FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . " course ";
199
200
        if (!empty($urlId)) {
201
            $table = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
202
            $sql .= " INNER JOIN $table url ON (url.c_id = course.id) ";
203
        }
204
205
        if (!empty($startwith)) {
206
            $sql .= "WHERE (title LIKE '" . Database::escape_string($startwith) . "%' ";
207
            if ($alsoSearchCode) {
208
                $sql .= "OR code LIKE '" . Database::escape_string($startwith) . "%' ";
209
            }
210
            $sql .= ') ';
211 View Code Duplication
            if ($visibility !== -1 && $visibility == strval(intval($visibility))) {
212
                $sql .= " AND visibility = $visibility ";
213
            }
214 View Code Duplication
        } else {
215
            $sql .= "WHERE 1 ";
216
            if ($visibility !== -1 && $visibility == strval(intval($visibility))) {
217
                $sql .= " AND visibility = $visibility ";
218
            }
219
        }
220
221
        if (!empty($urlId)) {
222
            $urlId = intval($urlId);
223
            $sql .= " AND access_url_id= $urlId";
224
        }
225
226
        $allowedFields = array(
227
            'title',
228
            'code'
229
        );
230
231
        if (count($conditionsLike) > 0) {
232
            $sql .= ' AND ';
233
            $temp_conditions = array();
234
            foreach ($conditionsLike as $field => $value) {
235
                if (!in_array($field, $allowedFields)) {
236
                    continue;
237
                }
238
                $field = Database::escape_string($field);
239
                $value = Database::escape_string($value);
240
                $simple_like = false;
241 View Code Duplication
                if ($simple_like) {
242
                    $temp_conditions[] = $field . " LIKE '$value%'";
243
                } else {
244
                    $temp_conditions[] = $field . ' LIKE \'%' . $value . '%\'';
245
                }
246
            }
247
            $condition = ' AND ';
248
            if (!empty($temp_conditions)) {
249
                $sql .= implode(' ' . $condition . ' ', $temp_conditions);
250
            }
251
        }
252
253
        if (!empty($orderby)) {
254
            $sql .= " ORDER BY " . Database::escape_string($orderby) . " ";
255
        } else {
256
            $sql .= " ORDER BY 1 ";
257
        }
258
259
        if (!in_array($orderdirection, array('ASC', 'DESC'))) {
260
            $sql .= 'ASC';
261
        } else {
262
            $sql .= ($orderdirection == 'ASC' ? 'ASC' : 'DESC');
263
        }
264
265
        if (!empty($howmany) && is_int($howmany) and $howmany > 0) {
266
            $sql .= ' LIMIT ' . Database::escape_string($howmany);
267
        } else {
268
            $sql .= ' LIMIT 1000000'; //virtually no limit
269
        }
270
        if (!empty($from)) {
271
            $from = intval($from);
272
            $sql .= ' OFFSET ' . intval($from);
273
        } else {
274
            $sql .= ' OFFSET 0';
275
        }
276
277
        return Database::store_result(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, store_result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
278
    }
279
280
    /**
281
     * Returns the access settings of the course:
282
     * which visibility;
283
     * whether subscribing is allowed;
284
     * whether unsubscribing is allowed.
285
     *
286
     * @param string $course_code , the course code
287
     * @todo for more consistency: use course_info call from database API
288
     * @return an array with int fields "visibility", "subscribe", "unsubscribe"
289
     * @assert ('') === false
290
     */
291 View Code Duplication
    public static function get_access_settings($course_code)
292
    {
293
        return Database::fetch_array(
294
            Database::query(
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...g($course_code) . '\'') can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
295
                "SELECT visibility, subscribe, unsubscribe
296
                FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . "
297
                WHERE code = '" . Database::escape_string($course_code) . "'"
298
            )
299
        );
300
    }
301
302
    /**
303
     * Returns the status of a user in a course, which is COURSEMANAGER or STUDENT.
304
     * @param   int $user_id
305
     * @param   string $course_code
306
     *
307
     * @return int the status of the user in that course
308
     */
309
    public static function get_user_in_course_status($user_id, $course_code)
310
    {
311
        $courseInfo = api_get_course_info($course_code);
312
        $courseId = $courseInfo['real_id'];
313
        $result = Database::fetch_array(
314
            Database::query(
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...= " . intval($user_id)) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
315
                "SELECT status FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
316
                WHERE
317
                    c_id  = $courseId AND
318
                    user_id = " . intval($user_id)
319
            )
320
        );
321
322
        return $result['status'];
323
    }
324
325
    /**
326
     * @param int $userId
327
     * @param int $courseId
328
     *
329
     * @return mixed
330
     */
331 View Code Duplication
    public static function getUserCourseInfo($userId, $courseId)
332
    {
333
334
        $result = Database::fetch_array(
335
            Database::query("
0 ignored issues
show
Bug introduced by
It seems like \Database::query(' ... = ' . intval($userId)) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
336
                SELECT * FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
337
                WHERE
338
                    c_id  = '" . intval($courseId). "' AND
339
                    user_id = " . intval($userId)
340
            )
341
        );
342
343
        return $result;
344
    }
345
346
    /**
347
     * @param int  $userId
348
     * @param int  $courseId
349
     * @param bool $isTutor
350
     *
351
     * @return bool
352
     */
353
    public static function updateUserCourseTutor($userId, $courseId, $isTutor)
354
    {
355
        $table = Database::escape_string(TABLE_MAIN_COURSE_USER);
356
357
        $courseId = intval($courseId);
358
        $isTutor = intval($isTutor);
359
360
        $sql = "UPDATE $table SET is_tutor = '".$isTutor."'
361
			    WHERE
362
				    user_id = '".$userId."' AND
363
				    c_id = '".$courseId."'";
364
365
        $result = Database::query($sql);
366
367
        if (Database::affected_rows($result) > 0) {
368
            return true;
369
        } else {
370
            return false;
371
        }
372
    }
373
374
    /**
375
     * @param int $user_id
376
     * @param string $course_code
377
     *
378
     * @return mixed
379
     */
380 View Code Duplication
    public static function get_tutor_in_course_status($user_id, $course_code)
381
    {
382
        $result = Database::fetch_array(
383
            Database::query("
0 ignored issues
show
Bug introduced by
It seems like \Database::query(' ...= ' . intval($user_id)) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
384
                SELECT is_tutor
385
                FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
386
                WHERE
387
                    course_code = '" . Database::escape_string($course_code) . "' AND
388
                    user_id = " . intval($user_id)
389
            )
390
        );
391
392
        return $result['is_tutor'];
393
    }
394
395
    /**
396
     * Unsubscribe one or more users from a course
397
     *
398
     * @param   mixed   user_id or an array with user ids
399
     * @param   string  course code
400
     * @param   int     session id
401
     * @assert ('', '') === false
402
     *
403
     */
404
    public static function unsubscribe_user($user_id, $course_code, $session_id = 0)
405
    {
406
        if (!is_array($user_id)) {
407
            $user_id = array($user_id);
408
        }
409
410
        if (count($user_id) == 0) {
411
            return;
412
        }
413
414
        if (!empty($session_id)) {
415
            $session_id = intval($session_id);
416
        } else {
417
            $session_id = api_get_session_id();
418
        }
419
420
        $user_list = array();
421
422
        // Cleaning the $user_id variable
423
        if (is_array($user_id)) {
424
            $new_user_id_list = array();
425
            foreach ($user_id as $my_user_id) {
426
                $new_user_id_list[] = intval($my_user_id);
427
            }
428
            $new_user_id_list = array_filter($new_user_id_list);
429
            $user_list = $new_user_id_list;
430
            $user_ids = implode(',', $new_user_id_list);
431
        } else {
432
            $user_ids = intval($user_id);
433
            $user_list[] = $user_id;
434
        }
435
436
        $course_info = api_get_course_info($course_code);
437
        $course_id = $course_info['real_id'];
438
439
        // Unsubscribe user from all groups in the course.
440
        $sql = "DELETE FROM " . Database::get_course_table(TABLE_GROUP_USER) . "
441
                WHERE c_id = $course_id AND user_id IN (" . $user_ids . ")";
442
        Database::query($sql);
443
        $sql = "DELETE FROM " . Database::get_course_table(TABLE_GROUP_TUTOR) . "
444
                WHERE c_id = $course_id AND user_id IN (" . $user_ids . ")";
445
        Database::query($sql);
446
447
        // Erase user student publications (works) in the course - by André Boivin
448
449
        if (!empty($user_list)) {
450
            require_once api_get_path(SYS_CODE_PATH) . 'work/work.lib.php';
451
            foreach ($user_list as $userId) {
452
                // Getting all work from user
453
                $workList = getWorkPerUser($userId);
454
                if (!empty($workList)) {
455
                    foreach ($workList as $work) {
456
                        $work = $work['work'];
457
                        // Getting user results
458
                        if (!empty($work->user_results)) {
459
                            foreach ($work->user_results as $workSent) {
460
                                deleteWorkItem($workSent['id'], $course_info);
461
                            }
462
                        }
463
                    }
464
                }
465
            }
466
        }
467
468
        // Unsubscribe user from all blogs in the course.
469
        Database::query("DELETE FROM " . Database::get_course_table(TABLE_BLOGS_REL_USER) . " WHERE c_id = $course_id AND  user_id IN (" . $user_ids . ")");
470
        Database::query("DELETE FROM " . Database::get_course_table(TABLE_BLOGS_TASKS_REL_USER) . " WHERE c_id = $course_id AND  user_id IN (" . $user_ids . ")");
471
472
        // Deleting users in forum_notification and mailqueue course tables
473
        $sql = "DELETE FROM  " . Database::get_course_table(TABLE_FORUM_NOTIFICATION) . "
474
                WHERE c_id = $course_id AND user_id IN (" . $user_ids . ")";
475
        Database::query($sql);
476
477
        $sql = "DELETE FROM " . Database::get_course_table(TABLE_FORUM_MAIL_QUEUE) . "
478
                WHERE c_id = $course_id AND user_id IN (" . $user_ids . ")";
479
        Database::query($sql);
480
481
        // Unsubscribe user from the course.
482
        if (!empty($session_id)) {
483
484
            // Delete in table session_rel_course_rel_user
485
            $sql = "DELETE FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . "
486
                    WHERE
487
                        session_id ='" . $session_id . "' AND
488
                        c_id = '" . $course_id . "' AND
489
                        user_id IN ($user_ids)";
490
            Database::query($sql);
491
492
            foreach ($user_list as $uid) {
493
                // check if a user is register in the session with other course
494
                $sql = "SELECT user_id FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . "
495
                        WHERE session_id='$session_id' AND user_id='$uid'";
496
                $rs = Database::query($sql);
497
498
                if (Database::num_rows($rs) == 0) {
499
                    // Delete in table session_rel_user
500
                    $sql = "DELETE FROM " . Database::get_main_table(TABLE_MAIN_SESSION_USER) . "
501
                            WHERE
502
                                session_id ='" . $session_id . "' AND
503
                                user_id = '$uid' AND
504
                                relation_type<>" . SESSION_RELATION_TYPE_RRHH . "";
505
                    Database::query($sql);
506
                }
507
            }
508
509
            // Update the table session
510
            $sql = "SELECT COUNT(*) FROM " . Database::get_main_table(TABLE_MAIN_SESSION_USER) . "
511
                    WHERE session_id = '" . $session_id . "' AND relation_type <> " . SESSION_RELATION_TYPE_RRHH;
512
            $row = Database::fetch_array(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
513
            $count = $row[0];
514
            // number of users by session
515
            $sql = "UPDATE " . Database::get_main_table(TABLE_MAIN_SESSION) . " SET nbr_users = '$count'
516
                    WHERE id = '" . $session_id . "'";
517
            Database::query($sql);
518
519
            // Update the table session_rel_course
520
            $sql = "SELECT COUNT(*) FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . "
521
                    WHERE session_id = '$session_id' AND c_id = '$course_id' AND status<>2";
522
            $row = Database::fetch_array(@Database::query($sql));
523
            $count = $row[0];
524
525
            // number of users by session and course
526
            $sql = "UPDATE " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE) . "
527
                    SET nbr_users = '$count'
528
                    WHERE session_id = '$session_id' AND c_id = '$course_id'";
529
            Database::query($sql);
530
531
        } else {
532
            $sql = "DELETE FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
533
                    WHERE
534
                        user_id IN (" . $user_ids . ") AND
535
                        relation_type<>" . COURSE_RELATION_TYPE_RRHH . " AND
536
                        c_id = '" . $course_id . "'";
537
            Database::query($sql);
538
539
            // add event to system log
540
            $user_id = api_get_user_id();
541
542
            Event::addEvent(
543
                LOG_UNSUBSCRIBE_USER_FROM_COURSE,
544
                LOG_COURSE_CODE,
545
                $course_code,
546
                api_get_utc_datetime(),
547
                $user_id
548
            );
549
550
            foreach ($user_list as $userId) {
551
                $userInfo = api_get_user_info($userId);
552
                Event::addEvent(
553
                    LOG_UNSUBSCRIBE_USER_FROM_COURSE,
554
                    LOG_USER_OBJECT,
555
                    $userInfo,
556
                    api_get_utc_datetime(),
557
                    $user_id
558
                );
559
            }
560
        }
561
    }
562
563
    /**
564
     * Subscribe a user to a course. No checks are performed here to see if
565
     * course subscription is allowed.
566
     * @param   int     User ID
567
     * @param   string  Course code
568
     * @param   int     Status (STUDENT, COURSEMANAGER, COURSE_ADMIN, NORMAL_COURSE_MEMBER)
569
     * @return  bool    True on success, false on failure
570
     * @see add_user_to_course
571
     * @assert ('', '') === false
572
     */
573
    public static function subscribe_user(
574
        $user_id,
575
        $course_code,
576
        $status = STUDENT,
577
        $session_id = 0,
578
        $userCourseCategoryId = 0
579
    ) {
580
        if ($user_id != strval(intval($user_id))) {
581
            return false; //detected possible SQL injection
582
        }
583
584
        $course_code = Database::escape_string($course_code);
585
        $courseInfo = api_get_course_info($course_code);
586
        $courseId = $courseInfo['real_id'];
587
        $courseCode = $courseInfo['code'];
588
589
        $userCourseCategoryId = intval($userCourseCategoryId);
590
591
        if (empty($user_id) || empty ($course_code)) {
592
            return false;
593
        }
594
595
        if (!empty($session_id)) {
596
            $session_id = intval($session_id);
597
        } else {
598
            $session_id = api_get_session_id();
599
        }
600
601
        $status = ($status == STUDENT || $status == COURSEMANAGER) ? $status : STUDENT;
602
        //$role_id = ($status == COURSEMANAGER) ? COURSE_ADMIN : NORMAL_COURSE_MEMBER;
603
604
        // A preliminary check whether the user has bben already registered on the platform.
605
        if (Database::num_rows(Database::query(
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...er_id = '{$user_id}' ") can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
606
                "SELECT status FROM " . Database::get_main_table(TABLE_MAIN_USER) . "
607
                WHERE user_id = '$user_id' ")) == 0
608
        ) {
609
            return false; // The user has not been registered to the platform.
610
        }
611
612
        // Check whether the user has not been already subscribed to the course.
613
614 View Code Duplication
        if (empty($session_id)) {
615
            if (Database::num_rows(Database::query("
0 ignored issues
show
Bug introduced by
It seems like \Database::query(' ... c_id = '{$courseId}'") can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
616
                    SELECT * FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
617
                    WHERE user_id = '$user_id' AND relation_type<>" . COURSE_RELATION_TYPE_RRHH . " AND c_id = '$courseId'")) > 0
618
            ) {
619
                // The user has been already subscribed to the course.
620
                return false;
621
            }
622
        }
623
624
        if (!empty($session_id)) {
625
            SessionManager::subscribe_users_to_session_course(array($user_id), $session_id, $courseCode);
626
        } else {
627
            CourseManager::add_user_to_course($user_id, $courseCode, $status);
628
629
            // Add event to the system log
630
            Event::addEvent(
631
                LOG_SUBSCRIBE_USER_TO_COURSE,
632
                LOG_COURSE_CODE,
633
                $course_code,
634
                api_get_utc_datetime(),
635
                api_get_user_id()
636
            );
637
638
            $user_info = api_get_user_info($user_id);
639
            Event::addEvent(
640
                LOG_SUBSCRIBE_USER_TO_COURSE,
641
                LOG_USER_OBJECT,
642
                $user_info,
643
                api_get_utc_datetime(),
644
                api_get_user_id()
645
            );
646
        }
647
648
        return true;
649
    }
650
651
    /**
652
     * Get the course id based on the original id and field name in the
653
     * extra fields. Returns 0 if course was not found
654
     *
655
     * @param string $original_course_id_value
656
     * @param string $original_course_id_name
657
     * @return int Course id
658
     *
659
     * @assert ('', '') === false
660
     */
661
    public static function get_course_code_from_original_id($original_course_id_value, $original_course_id_name)
662
    {
663
        $t_cfv = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
664
        $table_field = Database::get_main_table(TABLE_EXTRA_FIELD);
665
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
666
667
        $original_course_id_value = Database::escape_string($original_course_id_value);
668
        $original_course_id_name = Database::escape_string($original_course_id_name);
669
670
        $sql = "SELECT item_id
671
                FROM $table_field cf
672
                INNER JOIN $t_cfv cfv
673
                ON cfv.field_id=cf.id
674
                WHERE
675
                    variable = '$original_course_id_name' AND
676
                    value = '$original_course_id_value' AND
677
                    cf.extra_field_type = $extraFieldType
678
                ";
679
        $res = Database::query($sql);
680
        $row = Database::fetch_object($res);
681
        if ($row) {
682
            return $row->item_id;
683
        } else {
684
            return 0;
685
        }
686
    }
687
688
    /**
689
     * Gets the course code from the course id. Returns null if course id was not found
690
     *
691
     * @param int Course id
692
     * @return string Course code
693
     * @assert ('') === false
694
     */
695
    public static function get_course_code_from_course_id($id)
696
    {
697
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
698
        $id = intval($id);
699
        $sql = "SELECT code FROM $table WHERE id = '$id' ";
700
        $res = Database::query($sql);
701
        $row = Database::fetch_object($res);
702
        if ($row) {
703
            return $row->code;
704
        } else {
705
            return null;
706
        }
707
    }
708
709
    /**
710
     * Subscribe a user $user_id to a course defined by $courseCode.
711
     * @author Hugues Peeters
712
     * @author Roan Embrechts
713
     *
714
     * @param  int $user_id the id of the user
715
     * @param  string $courseCode the course code
716
     * @param  int $status (optional) The user's status in the course
717
     * @param  int The user category in which this subscription will be classified
718
     *
719
     * @return boolean true if subscription succeeds, boolean false otherwise.
720
     * @assert ('', '') === false
721
     */
722
    public static function add_user_to_course($user_id, $courseCode, $status = STUDENT, $userCourseCategoryId = 0)
723
    {
724
        $debug = false;
725
        $user_table = Database::get_main_table(TABLE_MAIN_USER);
726
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
727
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
728
729
        $status = ($status == STUDENT || $status == COURSEMANAGER) ? $status : STUDENT;
730
        if (empty($user_id) || empty($courseCode) || ($user_id != strval(intval($user_id)))) {
731
            return false;
732
        }
733
734
        $courseCode = Database::escape_string($courseCode);
735
        $courseInfo = api_get_course_info($courseCode);
736
        $courseId = $courseInfo['real_id'];
737
738
        // Check in advance whether the user has already been registered on the platform.
739
        $sql = "SELECT status FROM " . $user_table . " WHERE user_id = $user_id ";
740 View Code Duplication
        if (Database::num_rows(Database::query($sql)) == 0) {
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
741
            if ($debug) {
742
                error_log('The user has not been registered to the platform');
743
            }
744
            return false; // The user has not been registered to the platform.
745
        }
746
747
        // Check whether the user has already been subscribed to this course.
748
        $sql = "SELECT * FROM $course_user_table
749
                WHERE
750
                    user_id = $user_id AND
751
                    relation_type <> " . COURSE_RELATION_TYPE_RRHH . " AND
752
                    c_id = $courseId";
753 View Code Duplication
        if (Database::num_rows(Database::query($sql)) > 0) {
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
754
            if ($debug) {
755
                error_log('The user has been already subscribed to the course');
756
            }
757
            return false; // The user has been subscribed to the course.
758
        }
759
760
        if (!api_is_course_admin()) {
761
            // Check in advance whether subscription is allowed or not for this course.
762
            $sql = "SELECT code, visibility FROM $course_table
763
                    WHERE id = $courseId AND subscribe = '" . SUBSCRIBE_NOT_ALLOWED . "'";
764 View Code Duplication
            if (Database::num_rows(Database::query($sql)) > 0) {
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
765
                if ($debug) {
766
                    error_log('Subscription is not allowed for this course');
767
                }
768
                return false; // Subscription is not allowed for this course.
769
            }
770
        }
771
772
        // Ok, subscribe the user.
773
        $max_sort = api_max_sort_value('0', $user_id);
774
        $params = [
775
            'c_id' => $courseId,
776
            'user_id' => $user_id,
777
            'status' => $status,
778
            'sort' => $max_sort + 1,
779
            'relation_type' => 0,
780
            'user_course_cat' => $userCourseCategoryId
781
        ];
782
        $insertId = Database::insert($course_user_table, $params);
783
784
        return $insertId;
785
    }
786
787
    /**
788
     *    Checks wether a parameter exists.
789
     *    If it doesn't, the function displays an error message.
790
     *
791
     * @return true if parameter is set and not empty, false otherwise
792
     * @todo move function to better place, main_api ?
793
     */
794
    public static function check_parameter($parameter, $error_message)
795
    {
796
        if (empty($parameter)) {
797
            Display::display_normal_message($error_message);
798
            return false;
799
        }
800
        return true;
801
    }
802
803
    /**
804
     *    Lets the script die when a parameter check fails.
805
     * @todo move function to better place, main_api ?
806
     */
807
    public static function check_parameter_or_fail($parameter, $error_message)
808
    {
809
        if (!self::check_parameter($parameter, $error_message)) {
810
            die();
811
        }
812
    }
813
814
    /**
815
     * @return true if there already are one or more courses
816
     *  with the same code OR visual_code (visualcode), false otherwise
817
     */
818
    public static function course_code_exists($wanted_course_code)
819
    {
820
        $wanted_course_code = Database::escape_string($wanted_course_code);
821
        $sql = "SELECT COUNT(*) as number
822
                FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . "
823
                WHERE code = '$wanted_course_code' OR visual_code = '$wanted_course_code'";
824
        $result = Database::fetch_array(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
825
826
        return $result['number'] > 0;
827
    }
828
829
    /**
830
     * Get course list as coach
831
     *
832
     * @param int $user_id
833
     * @param bool $include_courses_in_sessions
834
     * @return array Course list
835
     *
836
     **/
837
    public static function get_course_list_as_coach($user_id, $include_courses_in_sessions = false)
838
    {
839
        // 1. Getting courses as teacher (No session)
840
        $courses_temp = CourseManager::get_course_list_of_user_as_course_admin($user_id);
841
        $courseList = array();
842
843
        if (!empty($courses_temp)) {
844
            foreach ($courses_temp as $course_item) {
845
                $courseList[0][$course_item['code']] = $course_item['code'];
846
            }
847
        }
848
849
        //2. Include courses in sessions
850
        if ($include_courses_in_sessions) {
851
            $sessions = Tracking::get_sessions_coached_by_user($user_id);
852
853
            if (!empty($sessions)) {
854
                foreach ($sessions as $session_item) {
855
                    $courses = Tracking:: get_courses_followed_by_coach($user_id, $session_item['id']);
856
                    if (is_array($courses)) {
857
                        foreach ($courses as $course_item) {
858
                            $courseList[$session_item['id']][$course_item] = $course_item;
859
                        }
860
                    }
861
                }
862
            }
863
        }
864
865
        return $courseList;
866
    }
867
868
    /**
869
     * @param int $user_id
870
     * @param bool $include_sessions
871
     * @return array
872
     */
873
    public static function get_user_list_from_courses_as_coach($user_id, $include_sessions = true)
874
    {
875
        $students_in_courses = array();
876
        $sessions = CourseManager::get_course_list_as_coach($user_id, true);
877
878
        if (!empty($sessions)) {
879
            foreach ($sessions as $session_id => $courses) {
880
                if (!$include_sessions) {
881
                    if (!empty($session_id)) {
882
                        continue;
883
                    }
884
                }
885
                if (empty($session_id)) {
886
                    foreach ($courses as $course_code) {
887
                        $students_in_course = CourseManager::get_user_list_from_course_code($course_code);
888
889
                        foreach ($students_in_course as $user_item) {
0 ignored issues
show
Bug introduced by
The expression $students_in_course of type array|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
890
                            //Only students
891
                            if ($user_item['status_rel'] == STUDENT) {
892
                                $students_in_courses[$user_item['user_id']] = $user_item['user_id'];
893
                            }
894
                        }
895
                    }
896
                } else {
897
                    $students_in_course = SessionManager::get_users_by_session($session_id, '0');
898
                    if (is_array($students_in_course)) {
899
                        foreach ($students_in_course as $user_item) {
900
                            $students_in_courses[$user_item['user_id']] = $user_item['user_id'];
901
                        }
902
                    }
903
                }
904
            }
905
        }
906
907
        $students = Tracking:: get_student_followed_by_coach($user_id);
908
        if (!empty($students_in_courses)) {
909
            if (!empty($students)) {
910
                $students = array_merge($students, $students_in_courses);
911
            } else {
912
                $students = $students_in_courses;
913
            }
914
        }
915
916
        if (!empty($students)) {
917
            $students = array_unique($students);
918
        }
919
        return $students;
920
    }
921
922
    /**
923
     * @param int $user_id
924
     * @return array An array with the course info of all the courses (real and virtual)
925
     * of which the current user is course admin.
926
     */
927
    public static function get_course_list_of_user_as_course_admin($user_id)
928
    {
929
        if ($user_id != strval(intval($user_id))) {
930
            return array();
931
        }
932
933
        // Definitions database tables and variables
934
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
935
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
936
        $user_id = intval($user_id);
937
        $data = array();
938
939
        $sql = "SELECT
940
                    course.code,
941
                    course.title,
942
                    course.id,
943
                    course.id as real_id
944
                FROM $tbl_course_user as course_rel_user
945
                INNER JOIN $tbl_course as course
946
                ON course.id = course_rel_user.c_id
947
                WHERE
948
                    course_rel_user.user_id='$user_id' AND
949
                    course_rel_user.status='1'
950
                ORDER BY course.title";
951
952
        if (api_get_multiple_access_url()) {
953
            $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
954
            $access_url_id = api_get_current_access_url_id();
955
            if ($access_url_id != -1) {
956
                $sql = "
957
                    SELECT
958
                        course.code,
959
                        course.title,
960
                        course.id,
961
                        course.id as real_id
962
                    FROM $tbl_course_user as course_rel_user
963
                    INNER JOIN $tbl_course as course
964
                    ON course.id = course_rel_user.c_id
965
                    INNER JOIN $tbl_course_rel_access_url course_rel_url
966
                    ON (course_rel_url.c_id = course.id)
967
                    WHERE
968
                        access_url_id = $access_url_id  AND
969
                        course_rel_user.user_id = '$user_id' AND
970
                        course_rel_user.status = '1'
971
                    ORDER BY course.title";
972
            }
973
        }
974
975
        $result_nb_cours = Database::query($sql);
976
        if (Database::num_rows($result_nb_cours) > 0) {
977
            while ($row = Database::fetch_array($result_nb_cours, 'ASSOC')) {
978
                $data[$row['id']] = $row;
979
            }
980
        }
981
982
        return $data;
983
    }
984
985
    /**
986
     * @param int $userId
987
     * @param array $courseInfo
988
     * @return bool
989
     */
990
    public static function isUserSubscribedInCourseAsDrh($userId, $courseInfo)
991
    {
992
        $userId = intval($userId);
993
994
        if (!api_is_drh()) {
995
            return false;
996
        }
997
998
        if (empty($courseInfo) || empty($userId)) {
999
            return false;
1000
        }
1001
1002
        $courseId = intval($courseInfo['real_id']);
1003
        $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
1004
1005
        $sql = "SELECT * FROM $table
1006
                WHERE
1007
                    user_id = $userId AND
1008
                    relation_type = " . COURSE_RELATION_TYPE_RRHH . " AND
1009
                    c_id = $courseId";
1010
1011
        $result = Database::fetch_array(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1012
1013
        if (!empty($result)) {
1014
            // The user has been registered in this course.
1015
            return true;
1016
        }
1017
    }
1018
1019
    /**
1020
     * Check if user is subscribed inside a course
1021
     * @param  int $user_id
1022
     * @param  string $course_code , if this parameter is null, it'll check for all courses
1023
     * @param  bool $in_a_session True for checking inside sessions too, by default is not checked
1024
     * @return bool   $session_id true if the user is registered in the course, false otherwise
1025
     */
1026
    public static function is_user_subscribed_in_course(
1027
        $user_id,
1028
        $course_code = null,
1029
        $in_a_session = false,
1030
        $session_id = null
1031
    ) {
1032
        $user_id = intval($user_id);
1033
1034
        if (empty($session_id)) {
1035
            $session_id = api_get_session_id();
1036
        } else {
1037
            $session_id = intval($session_id);
1038
        }
1039
1040
        $condition_course = '';
1041
        if (isset($course_code)) {
1042
            $courseInfo = api_get_course_info($course_code);
1043
            if (empty($courseInfo)) {
1044
                return false;
1045
            }
1046
            $courseId = $courseInfo['real_id'];
1047
            $condition_course = ' AND c_id = ' . $courseId;
1048
        }
1049
1050
        $sql = "SELECT * FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
1051
                WHERE
1052
                    user_id = $user_id AND
1053
                    relation_type<>" . COURSE_RELATION_TYPE_RRHH . "
1054
                    $condition_course ";
1055
1056
        $result = Database::fetch_array(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1057
1058
        if (!empty($result)) {
1059
            // The user has been registered in this course.
1060
            return true;
1061
        }
1062
1063
        if (!$in_a_session) {
1064
            // The user has not been registered in this course.
1065
            return false;
1066
        }
1067
1068
        $tableSessionCourseUser = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1069
        $sql = 'SELECT 1 FROM ' . $tableSessionCourseUser .
1070
            ' WHERE user_id = ' . $user_id . ' ' . $condition_course;
1071
        if (Database::num_rows(Database::query($sql)) > 0) {
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1072
            return true;
1073
        }
1074
1075
        $sql = 'SELECT 1 FROM ' . $tableSessionCourseUser .
1076
            ' WHERE user_id = ' . $user_id . ' AND status=2 ' . $condition_course;
1077
        if (Database::num_rows(Database::query($sql)) > 0) {
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1078
            return true;
1079
        }
1080
1081
        $sql = 'SELECT 1 FROM ' . Database::get_main_table(TABLE_MAIN_SESSION) .
1082
            ' WHERE id = ' . $session_id . ' AND id_coach=' . $user_id;
1083
1084
        if (Database::num_rows(Database::query($sql)) > 0) {
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1085
            return true;
1086
        }
1087
1088
        return false;
1089
    }
1090
1091
    /**
1092
     *    Is the user a teacher in the given course?
1093
     *
1094
     * @param $user_id , the id (int) of the user
1095
     * @param $course_code , the course code
1096
     *
1097
     * @return true if the user is a teacher in the course, false otherwise
1098
     */
1099
    public static function is_course_teacher($user_id, $course_code)
1100
    {
1101
        if ($user_id != strval(intval($user_id))) {
1102
            return false;
1103
        }
1104
1105
        $courseInfo = api_get_course_info($course_code);
1106
        $courseId = $courseInfo['real_id'];
1107
1108
        $result = Database::query(
1109
            'SELECT status FROM ' . Database::get_main_table(TABLE_MAIN_COURSE_USER) .
1110
            ' WHERE c_id = ' . $courseId . ' AND user_id = ' . $user_id . ''
1111
        );
1112
1113
        if (Database::num_rows($result) > 0) {
1114
            return Database::result($result, 0, 'status') == 1;
1115
        }
1116
1117
        return false;
1118
    }
1119
1120
    /**
1121
     *    Is the user subscribed in the real course or linked courses?
1122
     *
1123
     * @param int the id of the user
1124
     * @param int $courseId
1125
     * @deprecated linked_courses definition doesn't exists
1126
     * @return true if the user is registered in the real course or linked courses, false otherwise
1127
     */
1128
    public static function is_user_subscribed_in_real_or_linked_course($user_id, $courseId, $session_id = '')
1129
    {
1130
        if ($user_id != strval(intval($user_id))) {
1131
            return false;
1132
        }
1133
1134
        $courseId = intval($courseId);
1135
1136
        if ($session_id == '') {
1137
            $result = Database::fetch_array(
1138
                Database::query(
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...e.id = '{$courseId}')") can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1139
                    "SELECT *
1140
                    FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . " course
1141
                    LEFT JOIN " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . " course_user
1142
                    ON course.id = course_user.c_id
1143
                    WHERE
1144
                        course_user.user_id = '$user_id' AND
1145
                        course_user.relation_type<>" . COURSE_RELATION_TYPE_RRHH . " AND
1146
                        ( course.id = '$courseId')"
1147
                )
1148
            );
1149
            return !empty($result);
1150
        }
1151
1152
        $session_id = intval($session_id);
1153
1154
        // From here we trust session id.
1155
        // Is he/she subscribed to the session's course?
1156
1157
        // A user?
1158 View Code Duplication
        if (Database::num_rows(Database::query("SELECT user_id
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...user_id ='{$user_id}'") can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1159
                FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . "
1160
                WHERE session_id='" . $session_id . "'
1161
                AND user_id ='$user_id'"))
1162
        ) {
1163
            return true;
1164
        }
1165
1166
        // A course coach?
1167 View Code Duplication
        if (Database::num_rows(Database::query("SELECT user_id
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...D c_id ='{$courseId}'") can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1168
                FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . "
1169
                WHERE session_id='" . $session_id . "'
1170
                AND user_id = '$user_id' AND status = 2
1171
                AND c_id ='$courseId'"))
1172
        ) {
1173
            return true;
1174
        }
1175
1176
        // A session coach?
1177 View Code Duplication
        if (Database::num_rows(Database::query("SELECT id_coach
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...id_coach='{$user_id}'") can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
1178
                FROM " . Database::get_main_table(TABLE_MAIN_SESSION) . " AS session
1179
                WHERE session.id='" . $session_id . "'
1180
                AND id_coach='$user_id'"))
1181
        ) {
1182
            return true;
1183
        }
1184
1185
        return false;
1186
    }
1187
1188
    /**
1189
     * Return user info array of all users registered in a course
1190
     * This only returns the users that are registered in this actual course, not linked courses.
1191
     * @param string $course_code
1192
     * @param int $session_id
1193
     * @param string $limit
1194
     * @param string $order_by the field to order the users by.
1195
     * Valid values are 'lastname', 'firstname', 'username', 'email', 'official_code' OR a part of a SQL statement
1196
     * that starts with ORDER BY ...
1197
     * @param null $filter_by_status if using the session_id: 0 or 2 (student, coach),
1198
     * if using session_id = 0 STUDENT or COURSEMANAGER
1199
     * @param null $return_count
1200
     * @param bool $add_reports
1201
     * @param bool $resumed_report
1202
     * @param array $extra_field
1203
     * @param array $courseCodeList
1204
     * @param array $userIdList
1205
     * @param string $filterByActive
1206
     * @param array $sessionIdList
1207
     * @return array|int
1208
     */
1209
    public static function get_user_list_from_course_code(
1210
        $course_code = null,
1211
        $session_id = 0,
1212
        $limit = null,
1213
        $order_by = null,
1214
        $filter_by_status = null,
1215
        $return_count = null,
1216
        $add_reports = false,
1217
        $resumed_report = false,
1218
        $extra_field = array(),
1219
        $courseCodeList = array(),
1220
        $userIdList = array(),
1221
        $filterByActive = null,
1222
        $sessionIdList = array()
1223
    ) {
1224
        $course_table = Database::get_main_table(TABLE_MAIN_COURSE);
1225
        $sessionTable = Database::get_main_table(TABLE_MAIN_SESSION);
1226
1227
        $session_id = intval($session_id);
1228
        $course_code = Database::escape_string($course_code);
1229
        $courseInfo = api_get_course_info($course_code);
1230
        $courseId = 0;
1231
        if (!empty($courseInfo)) {
1232
            $courseId = $courseInfo['real_id'];
1233
        }
1234
1235
        $where = array();
1236
        if (empty($order_by)) {
1237
            $order_by = 'user.lastname, user.firstname';
1238
            if (api_is_western_name_order()) {
1239
                $order_by = 'user.firstname, user.lastname';
1240
            }
1241
        }
1242
1243
        // if the $order_by does not contain 'ORDER BY'
1244
        // we have to check if it is a valid field that can be sorted on
1245
        if (!strstr($order_by, 'ORDER BY')) {
1246
            if (!empty($order_by)) {
1247
                $order_by = 'ORDER BY ' . $order_by;
1248
            } else {
1249
                $order_by = '';
1250
            }
1251
        }
1252
1253
        $filter_by_status_condition = null;
1254
1255
        if (!empty($session_id) || !empty($sessionIdList)) {
1256
            $sql = 'SELECT DISTINCT
1257
                        user.user_id,
1258
                        user.email,
1259
                        session_course_user.status as status_session,
1260
                        session_id,
1261
                        user.*,
1262
                        course.*,
1263
                        session.name as session_name
1264
                    ';
1265
            if ($return_count) {
1266
                $sql = " SELECT COUNT(user.user_id) as count";
1267
            }
1268
1269
            $sessionCondition = " session_course_user.session_id = $session_id";
1270
            if (!empty($sessionIdList)) {
1271
                $sessionIdListTostring = implode("','", array_map('intval', $sessionIdList));
1272
                $sessionCondition = " session_course_user.session_id IN ('$sessionIdListTostring') ";
1273
            }
1274
1275
            $courseCondition = " course.id = $courseId";
1276
            if (!empty($courseCodeList)) {
1277
                $courseCodeListForSession = array_map(array('Database', 'escape_string'), $courseCodeList);
1278
                $courseCodeListForSession = implode('","', $courseCodeListForSession);
1279
                $courseCondition = ' course.code IN ("' . $courseCodeListForSession . '")  ';
1280
            }
1281
1282
            $sql .= ' FROM ' . Database::get_main_table(TABLE_MAIN_USER) . ' as user ';
1283
            $sql .= " LEFT JOIN ".Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . " as session_course_user
1284
                      ON
1285
                        user.user_id = session_course_user.user_id AND
1286
                        $sessionCondition
1287
                        INNER JOIN $course_table course ON session_course_user.c_id = course.id AND
1288
                        $courseCondition
1289
                        INNER JOIN $sessionTable session ON session_course_user.session_id = session.id
1290
                   ";
1291
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1292
1293
            // 2 = coach
1294
            // 0 = student
1295
            if (isset($filter_by_status)) {
1296
                $filter_by_status = intval($filter_by_status);
1297
                $filter_by_status_condition = " session_course_user.status = $filter_by_status AND ";
1298
            }
1299
        } else {
1300
            if ($return_count) {
1301
                $sql = " SELECT COUNT(*) as count";
1302
                if ($resumed_report) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
1303
                    //$sql = " SELECT count(field_id) ";
1304
                }
1305
            } else {
1306
                if (empty($course_code)) {
1307
                    $sql = 'SELECT DISTINCT
1308
                                course.title,
1309
                                course.code,
1310
                                course_rel_user.status as status_rel,
1311
                                user.user_id,
1312
                                user.email,
1313
                                course_rel_user.is_tutor,
1314
                                user.*  ';
1315
                } else {
1316
                    $sql = 'SELECT DISTINCT
1317
                                course_rel_user.status as status_rel,
1318
                                user.user_id,
1319
                                user.email,
1320
                                course_rel_user.is_tutor,
1321
                                user.*  ';
1322
                }
1323
            }
1324
1325
            $sql .= ' FROM ' . Database::get_main_table(TABLE_MAIN_USER) . ' as user ';
1326
            $sql .= ' LEFT JOIN ' . Database::get_main_table(TABLE_MAIN_COURSE_USER) . ' as course_rel_user
1327
                        ON user.user_id = course_rel_user.user_id AND
1328
                        course_rel_user.relation_type <> ' . COURSE_RELATION_TYPE_RRHH . '  ';
1329
            $sql .= " INNER JOIN $course_table course ON course_rel_user.c_id = course.id ";
1330
1331
            if (!empty($course_code)) {
1332
                $sql .= ' AND course_rel_user.c_id="' . $courseId . '"';
1333
            }
1334
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1335
1336
            if (isset($filter_by_status) && is_numeric($filter_by_status)) {
1337
                $filter_by_status = intval($filter_by_status);
1338
                $filter_by_status_condition = " course_rel_user.status = $filter_by_status AND ";
1339
            }
1340
        }
1341
1342
        $multiple_access_url = api_get_multiple_access_url();
1343
        if ($multiple_access_url) {
1344
            $sql .= ' LEFT JOIN ' . Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER) . ' au
1345
                      ON (au.user_id = user.user_id) ';
1346
        }
1347
1348
        $extraFieldWasAdded = false;
1349
        if ($return_count && $resumed_report) {
1350
            foreach ($extra_field as $extraField) {
1351
                $extraFieldInfo = UserManager::get_extra_field_information_by_name($extraField);
1352
                if (!empty($extraFieldInfo)) {
1353
                    $fieldValuesTable = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1354
                    $sql .= ' LEFT JOIN '.$fieldValuesTable.' as ufv
1355
                            ON (
1356
                                user.user_id = ufv.item_id AND
1357
                                (field_id = '.$extraFieldInfo['id'].' OR field_id IS NULL)
1358
                            )';
1359
                    $extraFieldWasAdded = true;
1360
                }
1361
            }
1362
        }
1363
1364
        $sql .= ' WHERE ' . $filter_by_status_condition . ' ' . implode(' OR ', $where);
1365
1366
        if ($multiple_access_url) {
1367
            $current_access_url_id = api_get_current_access_url_id();
1368
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1369
        }
1370
1371
        if ($return_count && $resumed_report && $extraFieldWasAdded) {
1372
            $sql .= ' AND field_id IS NOT NULL GROUP BY value ';
1373
        }
1374
1375
        if (!empty($courseCodeList)) {
1376
            $courseCodeList = array_map(array('Database', 'escape_string'), $courseCodeList);
1377
            $courseCodeList = implode('","', $courseCodeList);
1378
            if (empty($sessionIdList)) {
1379
                $sql .= ' AND course.code IN ("'.$courseCodeList.'")';
1380
            }
1381
        }
1382
1383 View Code Duplication
        if (!empty($userIdList)) {
1384
            $userIdList = array_map('intval', $userIdList);
1385
            $userIdList = implode('","', $userIdList);
1386
            $sql .= ' AND user.user_id IN ("' . $userIdList . '")';
1387
        }
1388
1389
        if (isset($filterByActive)) {
1390
            $filterByActive = intval($filterByActive);
1391
            $sql .= ' AND user.active = ' . $filterByActive;
1392
        }
1393
1394
        $sql .= ' ' . $order_by . ' ' . $limit;
1395
1396
        $rs = Database::query($sql);
1397
        $users = array();
1398
1399
        $extra_fields = UserManager::get_extra_fields(0, 100, null, null, true, true);
1400
1401
        $counter = 1;
1402
        $count_rows = Database::num_rows($rs);
1403
1404
        if ($return_count && $resumed_report) {
1405
            return $count_rows;
1406
        }
1407
1408
        $table_user_field_value = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
1409
        $tableExtraField = Database::get_main_table(TABLE_EXTRA_FIELD);
1410
        if ($count_rows) {
1411
            while ($user = Database::fetch_array($rs)) {
1412
                if ($return_count) {
1413
                    return $user['count'];
1414
                }
1415
                $report_info = array();
1416
1417
                $user_info = $user;
1418
                $user_info['status'] = $user['status'];
1419
1420
                if (isset($user['is_tutor'])) {
1421
                    $user_info['is_tutor'] = $user['is_tutor'];
1422
                }
1423
1424
                if (!empty($session_id)) {
1425
                    $user_info['status_session'] = $user['status_session'];
1426
                }
1427
1428
                $sessionId = isset($user['session_id']) ? $user['session_id'] : 0;
1429
                $course_code = isset($user['code']) ? $user['code'] : null;
1430
1431
                if ($add_reports) {
1432
                    if ($resumed_report) {
1433
                        $extra = array();
1434
1435
                        if (!empty($extra_fields)) {
1436
                            foreach ($extra_fields as $extra) {
1437
                                if (in_array($extra['1'], $extra_field)) {
1438
                                    $user_data = UserManager::get_extra_user_data_by_field(
1439
                                        $user['user_id'],
1440
                                        $extra['1']
1441
                                    );
1442
                                    break;
1443
                                }
1444
                            }
1445
                        }
1446
1447
                        $row_key = '-1';
1448
                        $name = '-';
1449
1450
                        if (!empty($extra)) {
1451
                            if (!empty($user_data[$extra['1']])) {
1452
                                $row_key = $user_data[$extra['1']];
1453
                                $name = $user_data[$extra['1']];
1454
                                $users[$row_key]['extra_'.$extra['1']] = $name;
1455
                            }
1456
                        }
1457
1458
                        $users[$row_key]['training_hours'] += Tracking::get_time_spent_on_the_course(
1459
                            $user['user_id'],
1460
                            $courseId,
1461
                            $sessionId
1462
                        );
1463
1464
                        $users[$row_key]['count_users'] += $counter;
1465
1466
                        $registered_users_with_extra_field = 0;
1467
1468
                        if (!empty($name) && $name != '-') {
1469
                            $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
1470
                            $name = Database::escape_string($name);
1471
                            $sql = "SELECT count(v.item_id) as count
1472
                                    FROM $table_user_field_value v INNER JOIN
1473
                                    $tableExtraField f
1474
                                    ON (f.id = v.field_id)
1475
                                    WHERE value = '$name' AND extra_field_type = $extraFieldType";
1476
                            $result_count = Database::query($sql);
1477
                            if (Database::num_rows($result_count)) {
1478
                                $row_count = Database::fetch_array($result_count);
1479
                                $registered_users_with_extra_field = $row_count['count'];
1480
                            }
1481
                        }
1482
1483
                        $users[$row_key]['count_users_registered'] = $registered_users_with_extra_field;
1484
                        $users[$row_key]['average_hours_per_user'] = $users[$row_key]['training_hours'] / $users[$row_key]['count_users'];
1485
1486
                        $category = Category:: load(
1487
                            null,
1488
                            null,
1489
                            $course_code,
1490
                            null,
1491
                            null,
1492
                            $sessionId
1493
                        );
1494
1495
                        if (!isset($users[$row_key]['count_certificates'])) {
1496
                            $users[$row_key]['count_certificates'] = 0;
1497
                        }
1498
1499
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1500
                            $users[$row_key]['count_certificates']++;
1501
                        }
1502
1503
                        foreach ($extra_fields as $extra) {
1504
                            if ($extra['1'] == 'ruc') {
1505
                                continue;
1506
                            }
1507
1508
                            if (!isset($users[$row_key][$extra['1']])) {
1509
                                $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1510
                                if (!empty($user_data[$extra['1']])) {
1511
                                    $users[$row_key][$extra['1']] = $user_data[$extra['1']];
1512
                                }
1513
                            }
1514
                        }
1515
                    } else {
1516
                        $sessionName = !empty($sessionId) ? ' - '.$user['session_name'] : '';
1517
                        $report_info['course'] = $user['title'].$sessionName;
1518
                        $report_info['user'] = api_get_person_name($user['firstname'], $user['lastname']);
1519
                        $report_info['email'] = $user['email'];
1520
                        $report_info['time'] = api_time_to_hms(
1521
                            Tracking::get_time_spent_on_the_course(
1522
                                $user['user_id'],
1523
                                $courseId,
1524
                                $sessionId
1525
                            )
1526
                        );
1527
1528
                        $category = Category:: load(
1529
                            null,
1530
                            null,
1531
                            $course_code,
1532
                            null,
1533
                            null,
1534
                            $sessionId
1535
                        );
1536
1537
                        $report_info['certificate'] = Display::label(get_lang('No'));
1538
                        if (isset($category[0]) && $category[0]->is_certificate_available($user['user_id'])) {
1539
                            $report_info['certificate'] = Display::label(get_lang('Yes'), 'success');
1540
                        }
1541
1542
                        $progress = intval(
1543
                            Tracking::get_avg_student_progress(
1544
                                $user['user_id'],
1545
                                $course_code,
1546
                                array(),
1547
                                $sessionId
1548
                            )
1549
                        );
1550
                        $report_info['progress_100'] = $progress == 100 ? Display::label(get_lang('Yes'), 'success') : Display::label(get_lang('No'));
1551
                        $report_info['progress'] = $progress . "%";
1552
1553
                        foreach ($extra_fields as $extra) {
1554
                            $user_data = UserManager::get_extra_user_data_by_field($user['user_id'], $extra['1']);
1555
                            $report_info[$extra['1']] = $user_data[$extra['1']];
1556
                        }
1557
                        $report_info['user_id'] = $user['user_id'];
1558
                        $users[] = $report_info;
1559
                    }
1560
                } else {
1561
                    $users[$user['user_id']] = $user_info;
1562
                }
1563
            }
1564
        }
1565
1566
        return $users;
1567
    }
1568
1569
    /**
1570
     * @param bool $resumed_report
1571
     * @param array $extra_field
1572
     * @param array $courseCodeList
1573
     * @param array $userIdList
1574
     * @param array $sessionIdList
1575
     * @return array|int
1576
     */
1577
    static function get_count_user_list_from_course_code(
1578
        $resumed_report = false,
1579
        $extra_field = array(),
1580
        $courseCodeList = array(),
1581
        $userIdList = array(),
1582
        $sessionIdList = array()
1583
    ) {
1584
        return self::get_user_list_from_course_code(
1585
            null,
1586
            0,
1587
            null,
1588
            null,
1589
            null,
1590
            true,
1591
            false,
1592
            $resumed_report,
1593
            $extra_field,
1594
            $courseCodeList,
1595
            $userIdList,
1596
            null,
1597
            $sessionIdList
1598
        );
1599
    }
1600
1601
    /**
1602
     * Gets subscribed users in a course or in a course/session
1603
     *
1604
     * @param   string $course_code
1605
     * @param   int $session_id
1606
     * @return  int
1607
     */
1608
    public static function get_users_count_in_course(
1609
        $course_code,
1610
        $session_id = 0,
1611
        $status = null
1612
    ) {
1613
        // variable initialisation
1614
        $session_id = intval($session_id);
1615
        $course_code = Database::escape_string($course_code);
1616
1617
        $courseInfo = api_get_course_info($course_code);
1618
        $courseId = $courseInfo['real_id'];
1619
1620
        $sql = 'SELECT DISTINCT count(*) as count  FROM ' . Database::get_main_table(TABLE_MAIN_USER) . ' as user ';
1621
        $where = array();
1622
        if (!empty($session_id)) {
1623
            $sql .= ' LEFT JOIN ' . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . ' as session_course_user
1624
                      ON
1625
                        user.user_id = session_course_user.user_id AND
1626
                        session_course_user.c_id = "' . $courseId . '" AND
1627
                        session_course_user.session_id  = ' . $session_id;
1628
1629
            $where[] = ' session_course_user.c_id IS NOT NULL ';
1630
        } else {
1631
            $sql .= ' LEFT JOIN ' . Database::get_main_table(TABLE_MAIN_COURSE_USER) . ' as course_rel_user
1632
                        ON
1633
                            user.user_id = course_rel_user.user_id AND
1634
                            course_rel_user.relation_type<>' . COURSE_RELATION_TYPE_RRHH . ' AND
1635
                            course_rel_user.c_id = ' . $courseId ;
1636
            $where[] = ' course_rel_user.c_id IS NOT NULL ';
1637
        }
1638
1639
        $multiple_access_url = api_get_multiple_access_url();
1640
        if ($multiple_access_url) {
1641
            $sql .= ' LEFT JOIN ' . Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_USER) . '  au
1642
                      ON (au.user_id = user.user_id) ';
1643
        }
1644
1645
        $sql .= ' WHERE ' . implode(' OR ', $where);
1646
1647
        if ($multiple_access_url) {
1648
            $current_access_url_id = api_get_current_access_url_id();
1649
            $sql .= " AND (access_url_id =  $current_access_url_id ) ";
1650
        }
1651
        $rs = Database::query($sql);
1652
        $count = 0;
1653
        if (Database::num_rows($rs)) {
1654
            $user = Database::fetch_array($rs);
1655
            $count = $user['count'];
1656
        }
1657
1658
        return $count;
1659
    }
1660
1661
    /**
1662
     * Get a list of coaches of a course and a session
1663
     * @param   string  Course code
1664
     * @param   int     Session ID
1665
     * @return  array   List of users
1666
     */
1667
    public static function get_coach_list_from_course_code($course_code, $session_id)
1668
    {
1669
        if (empty($course_code) OR empty($session_id)) {
1670
            return array();
1671
        }
1672
1673
        $course_code = Database::escape_string($course_code);
1674
        $courseInfo = api_get_course_info($course_code);
1675
        $courseId = $courseInfo['real_id'];
1676
1677
        $session_id = intval($session_id);
1678
        $users = array();
1679
1680
        // We get the coach for the given course in a given session.
1681
        $sql = 'SELECT user_id FROM ' . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) .
1682
               ' WHERE session_id ="' . $session_id . '" AND c_id="' . $courseId . '" AND status = 2';
1683
        $rs = Database::query($sql);
1684
        while ($user = Database::fetch_array($rs)) {
1685
            $user_info = api_get_user_info($user['user_id']);
1686
            $user_info['status'] = $user['status'];
1687
            //$user_info['tutor_id'] = $user['tutor_id'];
1688
            $user_info['email'] = $user['email'];
1689
            $users[$user['user_id']] = $user_info;
1690
        }
1691
1692
        $table = Database::get_main_table(TABLE_MAIN_SESSION);
1693
        // We get the session coach.
1694
        $sql = 'SELECT id_coach FROM ' . $table . ' WHERE id=' . $session_id;
1695
        $rs = Database::query($sql);
1696
        $session_id_coach = Database::result($rs, 0, 'id_coach');
1697
        $user_info = api_get_user_info($session_id_coach);
1698
        $user_info['status'] = $user['status'];
1699
        //$user_info['tutor_id'] = $user['tutor_id'];
1700
        $user_info['email'] = $user['email'];
1701
        $users[$session_id_coach] = $user_info;
1702
1703
        return $users;
1704
    }
1705
1706
    /**
1707
     *  Return user info array of all users registered in a course
1708
     *  This only returns the users that are registered in this actual course, not linked courses.
1709
     *
1710
     * @param string $course_code
1711
     * @param boolean $with_session
1712
     * @param integer $session_id
1713
     * @param string $date_from
1714
     * @param string $date_to
1715
     * @param boolean $includeInvitedUsers Whether include the invited users
1716
     * @param int $groupId
1717
     * @return array with user id
1718
     */
1719
    public static function get_student_list_from_course_code(
1720
        $course_code,
1721
        $with_session = false,
1722
        $session_id = 0,
1723
        $date_from = null,
1724
        $date_to = null,
1725
        $includeInvitedUsers = true,
1726
        $groupId = 0
1727
    ) {
1728
        $userTable = Database::get_main_table(TABLE_MAIN_USER);
1729
        $session_id = intval($session_id);
1730
        $course_code = Database::escape_string($course_code);
1731
        $courseInfo = api_get_course_info($course_code);
1732
        $courseId = $courseInfo['real_id'];
1733
        $students = array();
1734
1735
        if ($session_id == 0) {
1736
            if (empty($groupId)) {
1737
                // students directly subscribed to the course
1738
                $sql = "SELECT *
1739
                        FROM ".Database::get_main_table(TABLE_MAIN_COURSE_USER)." cu
1740
                        INNER JOIN $userTable u
1741
                        ON cu.user_id = u.user_id
1742
                        WHERE c_id = '$courseId' AND cu.status = ".STUDENT;
1743
1744
                if (!$includeInvitedUsers) {
1745
                    $sql .= " AND u.status != ".INVITEE;
1746
                }
1747
                $rs = Database::query($sql);
1748
                while ($student = Database::fetch_array($rs)) {
1749
                    $students[$student['user_id']] = $student;
1750
                }
1751
            } else {
1752
                $students = GroupManager::get_users(
1753
                    $groupId,
1754
                    false,
1755
                    null,
1756
                    null,
1757
                    false,
1758
                    $courseInfo['real_id']
1759
                );
1760
                $students = array_flip($students);
1761
            }
1762
        }
1763
1764
        // students subscribed to the course through a session
1765
        if ($with_session) {
1766
1767
            $joinSession = "";
1768
            //Session creation date
1769
            if (!empty($date_from) && !empty($date_to)) {
1770
                $joinSession = "INNER JOIN " . Database::get_main_table(TABLE_MAIN_SESSION) . " s";
1771
            }
1772
1773
            $sql_query = "SELECT *
1774
                          FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . " scu
1775
                          $joinSession
1776
                          INNER JOIN $userTable u ON scu.user_id = u.user_id
1777
                          WHERE scu.c_id = '$courseId' AND scu.status <> 2";
1778
1779
            if (!empty($date_from) && !empty($date_to)) {
1780
                $date_from = Database::escape_string($date_from);
1781
                $date_to = Database::escape_string($date_to);
1782
                $sql_query .= " AND s.access_start_date >= '$date_from' AND s.access_end_date <= '$date_to'";
1783
            }
1784
1785
            if ($session_id != 0) {
1786
                $sql_query .= ' AND scu.session_id = ' . $session_id;
1787
            }
1788
1789
            if (!$includeInvitedUsers) {
1790
                $sql_query .= " AND u.status != " . INVITEE;
1791
            }
1792
1793
            $rs = Database::query($sql_query);
1794
            while ($student = Database::fetch_array($rs)) {
1795
                $students[$student['user_id']] = $student;
1796
            }
1797
        }
1798
1799
        return $students;
1800
    }
1801
1802
    /**
1803
     * Return user info array of all teacher-users registered in a course
1804
     * This only returns the users that are registered in this actual course, not linked courses.
1805
     *
1806
     * @param string $course_code
1807
     * @return array with user id
1808
     */
1809
    public static function get_teacher_list_from_course_code($course_code)
1810
    {
1811
        $courseInfo = api_get_course_info($course_code);
1812
        $courseId = $courseInfo['real_id'];
1813
        if (empty($courseId)) {
1814
            return false;
1815
        }
1816
1817
        $sql = "SELECT DISTINCT
1818
                    u.id as user_id,
1819
                    u.lastname,
1820
                    u.firstname,
1821
                    u.email,
1822
                    u.username,
1823
                    u.status
1824
                FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . " cu
1825
                INNER JOIN " . Database::get_main_table(TABLE_MAIN_USER) . " u
1826
                ON (cu.user_id = u.id)
1827
                WHERE
1828
                    cu.c_id = $courseId AND
1829
                    cu.status = 1 ";
1830
        $rs = Database::query($sql);
1831
        $teachers = array();
1832
        while ($teacher = Database::fetch_array($rs)) {
1833
            $teachers[$teacher['user_id']] = $teacher;
1834
        }
1835
1836
        return $teachers;
1837
    }
1838
1839
    /**
1840
     * Returns a string list of teachers assigned to the given course
1841
     * @param string $course_code
1842
     * @param string $separator between teachers names
1843
     * @param bool $add_link_to_profile Whether to add a link to the teacher's profile
1844
     * @return string List of teachers teaching the course
1845
     */
1846
    public static function get_teacher_list_from_course_code_to_string(
1847
        $course_code,
1848
        $separator = self::USER_SEPARATOR,
1849
        $add_link_to_profile = false,
1850
        $orderList = false
1851
    ) {
1852
        $teacher_list = self::get_teacher_list_from_course_code($course_code);
1853
        $teacher_string = '';
1854
        $html = '';
1855
        $list = array();
1856
        if (!empty($teacher_list)) {
1857 View Code Duplication
            foreach ($teacher_list as $teacher) {
1858
                $teacher_name = api_get_person_name(
1859
                    $teacher['firstname'],
1860
                    $teacher['lastname']
1861
                );
1862
                if ($add_link_to_profile) {
1863
                    $url = api_get_path(WEB_AJAX_PATH) . 'user_manager.ajax.php?a=get_user_popup&user_id=' . $teacher['user_id'];
1864
                    $teacher_name = Display::url(
1865
                        $teacher_name,
1866
                        $url,
1867
                        [
1868
                            'class' => 'ajax',
1869
                            'data-title' => $teacher_name
1870
                        ]
1871
                    );
1872
                }
1873
                $list[] = $teacher_name;
1874
            }
1875
1876 View Code Duplication
            if (!empty($list)) {
1877
                if ($orderList === true){
1878
                    $html .= '<ul class="user-teacher">';
1879
                    foreach ($list as $teacher){
1880
                        $html .= Display::tag('li', Display::return_icon('teacher.png', $teacher, null, ICON_SIZE_TINY) . ' ' . $teacher);
1881
                    }
1882
                    $html .= '</ul>';
1883
                }else{
1884
                    $html .= array_to_string($list, $separator);
1885
                }
1886
            }
1887
        }
1888
1889
        return $html;
1890
    }
1891
1892
    /**
1893
     * This function returns information about coachs from a course in session
1894
     * @param int $session_id
1895
     * @param int $courseId
1896
     *
1897
     * @return array    - array containing user_id, lastname, firstname, username
1898
     *
1899
     */
1900
    public static function get_coachs_from_course($session_id = 0, $courseId = '')
1901
    {
1902
        if (!empty($session_id)) {
1903
            $session_id = intval($session_id);
1904
        } else {
1905
            $session_id = api_get_session_id();
1906
        }
1907
1908
        if (!empty($courseId)) {
1909
            $courseId = intval($courseId);
1910
        } else {
1911
            $courseId = api_get_course_int_id();
1912
        }
1913
1914
        $tbl_user = Database:: get_main_table(TABLE_MAIN_USER);
1915
        $tbl_session_course_user = Database:: get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
1916
        $coaches = array();
1917
1918
        $sql = "SELECT DISTINCT u.user_id,u.lastname,u.firstname,u.username
1919
                FROM $tbl_user u, $tbl_session_course_user scu
1920
                WHERE
1921
                    u.user_id = scu.user_id AND
1922
                    scu.session_id = '$session_id' AND
1923
                    scu.c_id = '$courseId' AND
1924
                    scu.status = 2";
1925
        $rs = Database::query($sql);
1926
1927
        if (Database::num_rows($rs) > 0) {
1928
            while ($row = Database::fetch_array($rs)) {
1929
                $completeName = api_get_person_name($row['firstname'], $row['lastname']);
1930
1931
                $coaches[] = $row + ['full_name' => $completeName];
1932
            }
1933
1934
            return $coaches;
1935
        } else {
1936
1937
            return false;
1938
        }
1939
    }
1940
1941
    /**
1942
     * @param int $session_id
1943
     * @param int $courseId
1944
     * @param string $separator
1945
     * @param bool $add_link_to_profile
1946
     * @return null|string
1947
     */
1948
    public static function get_coachs_from_course_to_string(
1949
        $session_id = 0,
1950
        $courseId = null,
1951
        $separator = self::USER_SEPARATOR,
1952
        $add_link_to_profile = false,
1953
        $orderList = false
1954
    ) {
1955
        $coachs_course = self::get_coachs_from_course($session_id, $courseId);
1956
        $course_coachs = array();
1957
        $html = '';
1958
        if (is_array($coachs_course)) {
1959 View Code Duplication
            foreach ($coachs_course as $coach_course) {
1960
                $coach_name = api_get_person_name($coach_course['firstname'], $coach_course['lastname']);
1961
                if ($add_link_to_profile) {
1962
                    $url = api_get_path(WEB_AJAX_PATH) . 'user_manager.ajax.php?a=get_user_popup&user_id=' . $coach_course['user_id'];
1963
                    $coach_name = Display::url(
1964
                        $coach_name,
1965
                        $url,
1966
                        [
1967
                            'class' => 'ajax',
1968
                            'data-title' => $coach_name
1969
                        ]
1970
                    );
1971
                }
1972
                $course_coachs[] = $coach_name;
1973
            }
1974
        }
1975
        $coaches_to_string = null;
1976
1977 View Code Duplication
        if (!empty($course_coachs)) {
1978
            if ($orderList === true){
1979
                $html .= '<ul class="user-coachs">';
1980
                    foreach ($course_coachs as $coachs){
1981
                        $html .= Display::tag('li', Display::return_icon('teacher.png', $coachs, null, ICON_SIZE_TINY) . ' ' . $coachs);
1982
                    }
1983
                $html .= '</ul>';
1984
            } else {
1985
                $coaches_to_string = array_to_string($course_coachs, $separator);
1986
            }
1987
1988
        }
1989
1990
        return $html;
1991
    }
1992
1993
    /**
1994
     * Return user info array of all users registered in the specified course
1995
     * this includes the users of the course itself and the users of all linked courses.
1996
     *
1997
     * @param string $course_code
1998
     * @param bool $with_sessions
1999
     * @param int $session_id
2000
     * @return array with user info
2001
     */
2002
    public static function get_real_and_linked_user_list($course_code, $with_sessions = true, $session_id = 0)
2003
    {
2004
        $complete_user_list = array();
2005
2006
        //get users from real course
2007
        $user_list = self::get_user_list_from_course_code($course_code, $session_id);
2008
        foreach ($user_list as $this_user) {
0 ignored issues
show
Bug introduced by
The expression $user_list of type array|integer is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
2009
            $complete_user_list[] = $this_user;
2010
        }
2011
2012
        return $complete_user_list;
2013
    }
2014
2015
    /**
2016
     * Get the list of groups from the course
2017
     * @param   string $course_code
2018
     * @param   int $session_id Session ID (optional)
2019
     * @param   boolean $in_get_empty_group get empty groups (optional)
2020
     * @return  array   List of groups info
2021
     */
2022
    public static function get_group_list_of_course($course_code, $session_id = 0, $in_get_empty_group = 0)
2023
    {
2024
        $course_info = api_get_course_info($course_code);
2025
2026
        if (empty($course_info)) {
2027
            return array();
2028
        }
2029
        $course_id = $course_info['real_id'];
2030
2031
        if (empty($course_id)) {
2032
            return array();
2033
        }
2034
2035
        $group_list = array();
2036
        $session_id != 0 ? $session_condition = ' WHERE g.session_id IN(1,' . intval($session_id) . ')' : $session_condition = ' WHERE g.session_id = 0';
2037
2038
        if ($in_get_empty_group == 0) {
2039
            // get only groups that are not empty
2040
            $sql = "SELECT DISTINCT g.id, g.name
2041
                    FROM " . Database::get_course_table(TABLE_GROUP) . " AS g
2042
                    INNER JOIN " . Database::get_course_table(TABLE_GROUP_USER) . " gu
2043
                    ON (g.id = gu.group_id AND g.c_id = $course_id AND gu.c_id = $course_id)
2044
                    $session_condition
2045
                    ORDER BY g.name";
2046
        } else {
2047
            // get all groups even if they are empty
2048
            $sql = "SELECT g.id, g.name
2049
                    FROM " . Database::get_course_table(TABLE_GROUP) . " AS g
2050
                    $session_condition
2051
                    AND c_id = $course_id";
2052
        }
2053
        $result = Database::query($sql);
2054
2055
        while ($group_data = Database::fetch_array($result)) {
2056
            $group_data['userNb'] = GroupManager::number_of_students($group_data['id'], $course_id);
2057
            $group_list[$group_data['id']] = $group_data;
2058
        }
2059
        return $group_list;
2060
    }
2061
2062
    /**
2063
     * Delete a course
2064
     * This function deletes a whole course-area from the platform. When the
2065
     * given course is a virtual course, the database and directory will not be
2066
     * deleted.
2067
     * When the given course is a real course, also all virtual courses refering
2068
     * to the given course will be deleted.
2069
     * Considering the fact that we remove all traces of the course in the main
2070
     * database, it makes sense to remove all tracking as well (if stats databases exist)
2071
     * so that a new course created with this code would not use the remains of an older
2072
     * course.
2073
     *
2074
     * @param string The code of the course to delete
2075
     * @todo When deleting a virtual course: unsubscribe users from that virtual
2076
     * course from the groups in the real course if they are not subscribed in
2077
     * that real course.
2078
     * @todo Remove globals
2079
     */
2080
    public static function delete_course($code)
2081
    {
2082
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
2083
        $table_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2084
        $table_session_course = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
2085
        $table_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2086
        $table_course_survey = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY);
2087
        $table_course_survey_question = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION);
2088
        $table_course_survey_question_option = Database::get_main_table(TABLE_MAIN_SHARED_SURVEY_QUESTION_OPTION);
2089
        $table_course_rel_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2090
2091
        $table_stats_hotpots = Database::get_main_table(TABLE_STATISTIC_TRACK_E_HOTPOTATOES);
2092
        $table_stats_attempt = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ATTEMPT);
2093
        $table_stats_exercises = Database::get_main_table(TABLE_STATISTIC_TRACK_E_EXERCISES);
2094
        $table_stats_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ACCESS);
2095
        $table_stats_lastaccess = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
2096
        $table_stats_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
2097
        $table_stats_online = Database::get_main_table(TABLE_STATISTIC_TRACK_E_ONLINE);
2098
        $table_stats_default = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DEFAULT);
2099
        $table_stats_downloads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_DOWNLOADS);
2100
        $table_stats_links = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LINKS);
2101
        $table_stats_uploads = Database::get_main_table(TABLE_STATISTIC_TRACK_E_UPLOADS);
2102
2103
        $codeFiltered = Database::escape_string($code);
2104
        $sql = "SELECT * FROM $table_course WHERE code='" . $codeFiltered . "'";
2105
        $res = Database::query($sql);
2106
2107
        if (Database::num_rows($res) == 0) {
2108
            return;
2109
        }
2110
2111
        $sql = "SELECT * FROM $table_course
2112
                WHERE code = '" . $codeFiltered . "'";
2113
        $res = Database::query($sql);
2114
        $course = Database::fetch_array($res);
2115
        $courseId = $course['id'];
2116
2117
        $count = 0;
2118
        if (api_is_multiple_url_enabled()) {
2119
            $url_id = 1;
2120
            if (api_get_current_access_url_id() != -1) {
2121
                $url_id = api_get_current_access_url_id();
2122
            }
2123
            UrlManager::delete_url_rel_course($courseId, $url_id);
2124
            $count = UrlManager::getCountUrlRelCourse($courseId);
2125
        }
2126
2127
        if ($count == 0) {
2128
            self::create_database_dump($code);
2129
2130
            $course_tables = AddCourse::get_course_tables();
2131
2132
            // Cleaning group categories
2133
            $groupCategories = GroupManager::get_categories($course['code']);
2134
2135
            if (!empty($groupCategories)) {
2136
                foreach ($groupCategories as $category) {
2137
                    GroupManager::delete_category($category['id'], $course['code']);
2138
                }
2139
            }
2140
2141
            // Cleaning groups
2142
            $groups = GroupManager::get_groups();
2143
            if (!empty($groups)) {
2144
                $groupList = array_column($groups, 'id');
2145
                GroupManager::delete_groups($groupList);
2146
            }
2147
2148
            // Cleaning c_x tables
2149
            if (!empty($courseId)) {
2150
                foreach ($course_tables as $table) {
2151
                    $table = Database::get_course_table($table);
2152
                    $sql = "DELETE FROM $table WHERE c_id = $courseId ";
2153
                    Database::query($sql);
2154
                }
2155
            }
2156
2157
            $course_dir = api_get_path(SYS_COURSE_PATH) . $course['directory'];
2158
            $archive_dir = api_get_path(SYS_ARCHIVE_PATH) . $course['directory'] . '_' . time();
2159
            if (is_dir($course_dir)) {
2160
                rename($course_dir, $archive_dir);
2161
            }
2162
2163
            // Unsubscribe all users from the course
2164
            $sql = "DELETE FROM $table_course_user WHERE c_id='" . $courseId . "'";
2165
            Database::query($sql);
2166
            // Delete the course from the sessions tables
2167
            $sql = "DELETE FROM $table_session_course WHERE c_id='" . $courseId . "'";
2168
            Database::query($sql);
2169
            $sql = "DELETE FROM $table_session_course_user WHERE c_id='" . $courseId . "'";
2170
            Database::query($sql);
2171
2172
            // Delete from Course - URL
2173
            $sql = "DELETE FROM $table_course_rel_url WHERE c_id = '" . $courseId. "'";
2174
            Database::query($sql);
2175
2176
            $sql = 'SELECT survey_id FROM ' . $table_course_survey . ' WHERE course_code="' . $codeFiltered . '"';
2177
            $result_surveys = Database::query($sql);
2178 View Code Duplication
            while ($surveys = Database::fetch_array($result_surveys)) {
2179
                $survey_id = $surveys[0];
2180
                $sql = 'DELETE FROM ' . $table_course_survey_question . ' WHERE survey_id="' . $survey_id . '"';
2181
                Database::query($sql);
2182
                $sql = 'DELETE FROM ' . $table_course_survey_question_option . ' WHERE survey_id="' . $survey_id . '"';
2183
                Database::query($sql);
2184
                $sql = 'DELETE FROM ' . $table_course_survey . ' WHERE survey_id="' . $survey_id . '"';
2185
                Database::query($sql);
2186
            }
2187
2188
            // Delete the course from the stats tables
2189
2190
            $sql = "DELETE FROM $table_stats_hotpots WHERE c_id = $courseId";
2191
            Database::query($sql);
2192
            $sql = "DELETE FROM $table_stats_attempt WHERE c_id = $courseId";
2193
            Database::query($sql);
2194
            $sql = "DELETE FROM $table_stats_exercises WHERE c_id = $courseId";
2195
            Database::query($sql);
2196
            $sql = "DELETE FROM $table_stats_access WHERE c_id = $courseId";
2197
            Database::query($sql);
2198
            $sql = "DELETE FROM $table_stats_lastaccess WHERE c_id = $courseId";
2199
            Database::query($sql);
2200
            $sql = "DELETE FROM $table_stats_course_access WHERE c_id = $courseId";
2201
            Database::query($sql);
2202
            $sql = "DELETE FROM $table_stats_online WHERE c_id = $courseId";
2203
            Database::query($sql);
2204
            // Do not delete rows from track_e_default as these include course
2205
            // creation and other important things that do not take much space
2206
            // but give information on the course history
2207
            //$sql = "DELETE FROM $table_stats_default WHERE c_id = $courseId";
2208
            //Database::query($sql);
2209
            $sql = "DELETE FROM $table_stats_downloads WHERE c_id = $courseId";
2210
            Database::query($sql);
2211
            $sql = "DELETE FROM $table_stats_links WHERE c_id = $courseId";
2212
            Database::query($sql);
2213
            $sql = "DELETE FROM $table_stats_uploads WHERE c_id = $courseId";
2214
            Database::query($sql);
2215
2216
            // Delete the course from the database
2217
            $sql = "DELETE FROM $table_course WHERE code = '" . $codeFiltered . "'";
2218
            Database::query($sql);
2219
2220
            // delete extra course fields
2221
            $extraFieldValues = new ExtraFieldValue('course');
2222
            $extraFieldValues->deleteValuesByItem($courseId);
2223
2224
            // Add event to system log
2225
            $user_id = api_get_user_id();
2226
            Event::addEvent(
2227
                LOG_COURSE_DELETE,
2228
                LOG_COURSE_CODE,
2229
                $code,
2230
                api_get_utc_datetime(),
2231
                $user_id,
2232
                $courseId
2233
            );
2234
        }
2235
    }
2236
2237
    /**
2238
     * Creates a file called mysql_dump.sql in the course folder
2239
     * @param $course_code The code of the course
2240
     * @todo Implementation for single database
2241
     */
2242
    public static function create_database_dump($course_code)
2243
    {
2244
        $sql_dump = '';
2245
        $course_code = Database::escape_string($course_code);
2246
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
2247
        $sql = "SELECT * FROM $table_course WHERE code = '$course_code'";
2248
        $res = Database::query($sql);
2249
        $course = Database::fetch_array($res);
2250
2251
        $course_tables = AddCourse::get_course_tables();
2252
2253
        if (!empty($course['id'])) {
2254
            //Cleaning c_x tables
2255
            foreach ($course_tables as $table) {
2256
                $table = Database::get_course_table($table);
2257
                $sql = "SELECT * FROM $table WHERE c_id = {$course['id']} ";
2258
                $res_table = Database::query($sql);
2259
2260
                while ($row = Database::fetch_array($res_table, 'ASSOC')) {
2261
                    $row_to_save = array();
2262
                    foreach ($row as $key => $value) {
2263
                        $row_to_save[$key] = $key . "='" . Database::escape_string($row[$key]) . "'";
2264
                    }
2265
                    $sql_dump .= "\nINSERT INTO $table SET " . implode(', ', $row_to_save) . ';';
2266
                }
2267
            }
2268
        }
2269
2270
        if (is_dir(api_get_path(SYS_COURSE_PATH) . $course['directory'])) {
2271
            $file_name = api_get_path(SYS_COURSE_PATH) . $course['directory'] . '/mysql_dump.sql';
2272
            $handle = fopen($file_name, 'a+');
2273
            if ($handle !== false) {
2274
                fwrite($handle, $sql_dump);
2275
                fclose($handle);
2276
            } else {
0 ignored issues
show
Unused Code introduced by
This else statement is empty and can be removed.

This check looks for the else branches of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These else branches can be removed.

if (rand(1, 6) > 3) {
print "Check failed";
} else {
    //print "Check succeeded";
}

could be turned into

if (rand(1, 6) > 3) {
    print "Check failed";
}

This is much more concise to read.

Loading history...
2277
                //TODO trigger exception in a try-catch
2278
            }
2279
        }
2280
    }
2281
2282
    /**
2283
     * Sort courses for a specific user ??
2284
     * @param   int     User ID
2285
     * @param   string  Course code
2286
     * @return  int     Minimum course order
2287
     * @todo Review documentation
2288
     */
2289
    public static function userCourseSort($user_id, $course_code)
2290
    {
2291
        if ($user_id != strval(intval($user_id))) {
2292
            return false;
2293
        }
2294
2295
        $course_code = Database::escape_string($course_code);
2296
        $TABLECOURSE = Database::get_main_table(TABLE_MAIN_COURSE);
2297
        $TABLECOURSUSER = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2298
2299
        $course_title = Database::result(Database::query('SELECT title FROM ' . $TABLECOURSE . ' WHERE code="' . $course_code . '"'),
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...' . $course_code . '"') can be null; however, result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2300
            0, 0);
2301
2302
        $sql = 'SELECT course.code as code, course.title as title, cu.sort as sort
2303
                FROM ' . $TABLECOURSUSER . ' as cu, ' . $TABLECOURSE . ' as course
2304
                WHERE   course.id = cu.c_id AND user_id = "' . $user_id . '" AND
2305
                        cu.relation_type<>' . COURSE_RELATION_TYPE_RRHH . ' AND
2306
                        user_course_cat = 0
2307
                ORDER BY cu.sort';
2308
        $result = Database::query($sql);
2309
2310
        $course_title_precedent = '';
2311
        $counter = 0;
2312
        $course_found = false;
2313
        $course_sort = 1;
2314
2315
        if (Database::num_rows($result) > 0) {
2316
            while ($courses = Database::fetch_array($result)) {
2317
                if ($course_title_precedent == '') {
2318
                    $course_title_precedent = $courses['title'];
2319
                }
2320
                if (api_strcasecmp($course_title_precedent, $course_title) < 0) {
2321
                    $course_found = true;
2322
                    $course_sort = $courses['sort'];
2323
                    if ($counter == 0) {
2324
                        $sql = 'UPDATE ' . $TABLECOURSUSER . '
2325
                                SET sort = sort+1
2326
                                WHERE
2327
                                    user_id= "' . $user_id . '" AND
2328
                                    relation_type<>' . COURSE_RELATION_TYPE_RRHH . '
2329
                                    AND user_course_cat="0"
2330
                                    AND sort > "' . $course_sort . '"';
2331
                        $course_sort++;
2332
                    } else {
2333
                        $sql = 'UPDATE ' . $TABLECOURSUSER . ' SET sort = sort+1
2334
                                WHERE
2335
                                    user_id= "' . $user_id . '" AND
2336
                                    relation_type<>' . COURSE_RELATION_TYPE_RRHH . ' AND
2337
                                    user_course_cat="0" AND
2338
                                    sort >= "' . $course_sort . '"';
2339
                    }
2340
                    Database::query($sql);
2341
                    break;
2342
2343
                } else {
2344
                    $course_title_precedent = $courses['title'];
2345
                }
2346
                $counter++;
2347
            }
2348
2349
            // We must register the course in the beginning of the list
2350
            if (!$course_found) {
2351
                $course_sort = Database::result(Database::query('SELECT min(sort) as min_sort FROM ' . $TABLECOURSUSER . ' WHERE user_id="' . $user_id . '" AND user_course_cat="0"'),
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...D user_course_cat="0"') can be null; however, result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2352
                    0, 0);
2353
                Database::query('UPDATE ' . $TABLECOURSUSER . ' SET sort = sort+1 WHERE user_id= "' . $user_id . '" AND user_course_cat="0"');
2354
            }
2355
        }
2356
        return $course_sort;
2357
    }
2358
2359
    /**
2360
     * check if course exists
2361
     * @param string course_code
2362
     * @param string whether to accept virtual course codes or not
2363
     * @return true if exists, false else
2364
     */
2365
    public static function course_exists($course_code, $accept_virtual = false)
2366
    {
2367
        if ($accept_virtual === true) {
2368
            $sql = 'SELECT 1 FROM ' . Database::get_main_table(TABLE_MAIN_COURSE) . '
2369
                    WHERE code="' . Database::escape_string($course_code) . '" OR visual_code="' . Database::escape_string($course_code) . '"';
2370
        } else {
2371
            $sql = 'SELECT 1 FROM ' . Database::get_main_table(TABLE_MAIN_COURSE) . '
2372
                    WHERE code="' . Database::escape_string($course_code) . '"';
2373
        }
2374
2375
        return Database::num_rows(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, num_rows() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2376
    }
2377
2378
    /**
2379
     * Send an email to tutor after the auth-suscription of a student in your course
2380
     * @author Carlos Vargas <[email protected]>, Dokeos Latino
2381
     * @param  int $user_id the id of the user
2382
     * @param  string $course_code the course code
0 ignored issues
show
Bug introduced by
There is no parameter named $course_code. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2383
     * @param  bool $send_to_tutor_also
2384
     * @return string we return the message that is displayed when the action is successful
2385
     */
2386
    public static function email_to_tutor($user_id, $courseId, $send_to_tutor_also = false)
2387
    {
2388
        if ($user_id != strval(intval($user_id))) {
2389
            return false;
2390
        }
2391
        $courseId = intval($courseId);
2392
        $information = api_get_course_info_by_id($courseId);
2393
        $course_code = $information['code'];
2394
2395
        $student = api_get_user_info($user_id);
2396
2397
        $name_course = $information['title'];
2398
        $sql = "SELECT * FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . " WHERE c_id ='" . $courseId . "'";
2399
2400
        // TODO: Ivan: This is a mistake, please, have a look at it. Intention here is diffcult to be guessed.
2401
        //if ($send_to_tutor_also = true)
2402
        // Proposed change:
2403
        if ($send_to_tutor_also) {
2404
            $sql .= " AND is_tutor=1";
2405
        } else {
2406
            $sql .= " AND status=1";
2407
        }
2408
2409
        $result = Database::query($sql);
2410
        while ($row = Database::fetch_array($result)) {
2411
            $tutor = api_get_user_info($row['user_id']);
2412
            $emailto = $tutor['email'];
2413
            $emailsubject = get_lang('NewUserInTheCourse') . ': ' . $name_course;
2414
            $emailbody = get_lang('Dear') . ': ' . api_get_person_name($tutor['firstname'], $tutor['lastname']) . "\n";
2415
            $emailbody .= get_lang('MessageNewUserInTheCourse') . ': ' . $name_course . "\n";
2416
            $emailbody .= get_lang('UserName') . ': ' . $student['username'] . "\n";
2417
            if (api_is_western_name_order()) {
2418
                $emailbody .= get_lang('FirstName') . ': ' . $student['firstname'] . "\n";
2419
                $emailbody .= get_lang('LastName') . ': ' . $student['lastname'] . "\n";
2420
            } else {
2421
                $emailbody .= get_lang('LastName') . ': ' . $student['lastname'] . "\n";
2422
                $emailbody .= get_lang('FirstName') . ': ' . $student['firstname'] . "\n";
2423
            }
2424
            $emailbody .= get_lang('Email') . ': <a href="mailto:' . $student['email'] . '">' . $student['email'] ."</a>\n\n";
2425
            $recipient_name = api_get_person_name($tutor['firstname'], $tutor['lastname'], null,
2426
                PERSON_NAME_EMAIL_ADDRESS);
2427
            $sender_name = api_get_person_name(api_get_setting('administratorName'),
2428
                api_get_setting('administratorSurname'), null, PERSON_NAME_EMAIL_ADDRESS);
2429
            $email_admin = api_get_setting('emailAdministrator');
2430
2431
            $additionalParameters = array(
2432
                'smsType' => SmsPlugin::NEW_USER_SUBSCRIBED_COURSE,
2433
                'userId' => $tutor['user_id'],
2434
                'userUsername' => $student['username'],
2435
                'courseCode' => $course_code
2436
            );
2437
            api_mail_html(
2438
                $recipient_name,
2439
                $emailto,
2440
                $emailsubject,
2441
                $emailbody,
2442
                $sender_name,
2443
                $email_admin,
2444
                null,
2445
                null,
2446
                null,
2447
                $additionalParameters
2448
            );
2449
        }
2450
    }
2451
2452
    /**
2453
     * @return array
2454
     */
2455
    public static function get_special_course_list()
2456
    {
2457
        $courseTable = Database:: get_main_table(TABLE_MAIN_COURSE);
2458
        $tbl_course_field = Database:: get_main_table(TABLE_EXTRA_FIELD);
2459
        $tbl_course_field_value = Database:: get_main_table(TABLE_EXTRA_FIELD_VALUES);
2460
2461
        //we filter the courses from the URL
2462
        $join_access_url = $where_access_url = '';
2463
        if (api_get_multiple_access_url()) {
2464
            $access_url_id = api_get_current_access_url_id();
2465
            if ($access_url_id != -1) {
2466
                $tbl_url_course = Database:: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2467
                $join_access_url = "LEFT JOIN $tbl_url_course url_rel_course
2468
                                    ON url_rel_course.c_id = tcfv.item_id ";
2469
                $where_access_url = " AND access_url_id = $access_url_id ";
2470
            }
2471
        }
2472
2473
        $extraFieldType = EntityExtraField::COURSE_FIELD_TYPE;
2474
2475
        // get course list auto-register
2476
        $sql = "SELECT DISTINCT(c.code)
2477
                FROM $tbl_course_field_value tcfv
2478
                INNER JOIN $tbl_course_field tcf
2479
                ON tcfv.field_id =  tcf.id $join_access_url
2480
                INNER JOIN $courseTable c
2481
                ON (c.id = tcfv.item_id)
2482
                WHERE
2483
                    tcf.extra_field_type = $extraFieldType AND
2484
                    tcf.variable = 'special_course' AND
2485
                    tcfv.value = 1  $where_access_url";
2486
2487
        $result = Database::query($sql);
2488
        $courseList = array();
2489
2490
        if (Database::num_rows($result) > 0) {
2491
            while ($result_row = Database::fetch_array($result)) {
2492
                $courseList[] = $result_row['code'];
2493
            }
2494
        }
2495
2496
        return $courseList;
2497
    }
2498
2499
    /**
2500
     * Get list of courses for a given user
2501
     * @param int $user_id
2502
     * @param boolean $include_sessions Whether to include courses from session or not
2503
     * @param boolean $adminGetsAllCourses If the user is platform admin,
2504
     * whether he gets all the courses or just his. Note: This does *not* include all sessions
2505
     * @return array    List of codes and db name
2506
     * @author isaac flores paz
2507
     */
2508
    public static function get_courses_list_by_user_id($user_id, $include_sessions = false, $adminGetsAllCourses = false)
2509
    {
2510
        $user_id = intval($user_id);
2511
        $course_list = array();
2512
        $codes = array();
2513
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
2514
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2515
        $tbl_user_course_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
2516
        $special_course_list = self::get_special_course_list();
2517
2518
        if ($adminGetsAllCourses && UserManager::is_admin($user_id)) {
2519
            // get the whole courses list
2520
            $sql = "SELECT DISTINCT(course.code), course.id as real_id
2521
                    FROM $tbl_course course";
2522
        } else {
2523
2524
            $with_special_courses = $without_special_courses = '';
2525
            if (!empty($special_course_list)) {
2526
                $sc_string = '"' . implode('","', $special_course_list) . '"';
2527
                $with_special_courses = ' course.code IN (' . $sc_string . ')';
2528
                $without_special_courses = ' AND course.code NOT IN (' . $sc_string . ')';
2529
            }
2530
2531 View Code Duplication
            if (!empty($with_special_courses)) {
2532
                $sql = "SELECT DISTINCT(course.code), course.id as real_id
2533
                        FROM $tbl_course_user  course_rel_user
2534
                        LEFT JOIN $tbl_course  course
2535
                        ON course.id = course_rel_user.c_id
2536
                        LEFT JOIN $tbl_user_course_category user_course_category
2537
                        ON course_rel_user.user_course_cat = user_course_category.id
2538
                        WHERE  $with_special_courses
2539
                        GROUP BY course.code
2540
                        ORDER BY user_course_category.sort, course.title, course_rel_user.sort ASC
2541
2542
                    ";
2543
                //
2544
                $rs_special_course = Database::query($sql);
2545
                if (Database::num_rows($rs_special_course) > 0) {
2546
                    while ($result_row = Database::fetch_array($rs_special_course)) {
2547
                        $result_row['special_course'] = 1;
2548
                        $course_list[] = $result_row;
2549
                        $codes[] = $result_row['real_id'];
2550
                    }
2551
                }
2552
            }
2553
2554
            // get course list not auto-register. Use Distinct to avoid multiple
2555
            // entries when a course is assigned to a HRD (DRH) as watcher
2556
            $sql = "SELECT DISTINCT(course.code), course.id as real_id
2557
                FROM $tbl_course course
2558
                INNER JOIN $tbl_course_user cru ON course.id = cru.c_id
2559
                WHERE cru.user_id='$user_id' $without_special_courses";
2560
        }
2561
        $result = Database::query($sql);
2562
2563
        if (Database::num_rows($result)) {
2564
            while ($row = Database::fetch_array($result, 'ASSOC')) {
2565
                $course_list[] = $row;
2566
                $codes[] = $row['real_id'];
2567
            }
2568
        }
2569
2570
        if ($include_sessions === true) {
2571
            $sql = "SELECT DISTINCT(c.code), c.id as real_id
2572
                    FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER) . " s,
2573
                    " . Database::get_main_table(TABLE_MAIN_COURSE) . " c
2574
                    WHERE user_id = $user_id AND s.c_id = c.id";
2575
            $r = Database::query($sql);
2576
            while ($row = Database::fetch_array($r, 'ASSOC')) {
2577
                if (!in_array($row['real_id'], $codes)) {
2578
                    $course_list[] = $row;
2579
                }
2580
            }
2581
        }
2582
2583
        return $course_list;
2584
    }
2585
2586
    /**
2587
     * Get course ID from a given course directory name
2588
     * @param   string  Course directory (without any slash)
2589
     * @return  string  Course code, or false if not found
2590
     */
2591
    public static function get_course_id_from_path($path)
2592
    {
2593
        $path = Database::escape_string(str_replace('.', '', str_replace('/', '', $path)));
2594
        $res = Database::query("SELECT code FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . "
2595
                WHERE directory LIKE BINARY '$path'");
2596
        if ($res === false) {
2597
            return false;
2598
        }
2599
        if (Database::num_rows($res) != 1) {
2600
            return false;
2601
        }
2602
        $row = Database::fetch_array($res);
2603
2604
        return $row['code'];
2605
    }
2606
2607
    /**
2608
     * Get course code(s) from visual code
2609
     * @deprecated
2610
     * @param   string  Visual code
2611
     * @return  array   List of codes for the given visual code
2612
     */
2613
    public static function get_courses_info_from_visual_code($code)
2614
    {
2615
        $result = array();
2616
        $sql_result = Database::query("SELECT * FROM " . Database::get_main_table(TABLE_MAIN_COURSE) . "
2617
                WHERE visual_code = '" . Database::escape_string($code) . "'");
2618
        while ($virtual_course = Database::fetch_array($sql_result)) {
2619
            $result[] = $virtual_course;
2620
        }
2621
        return $result;
2622
    }
2623
2624
    /**
2625
     * Get emails of tutors to course
2626
     * @param string Visual code
2627
     * @return array List of emails of tutors to course
2628
     * @author @author Carlos Vargas <[email protected]>, Dokeos Latino
2629
     * */
2630
    public static function get_emails_of_tutors_to_course($courseId)
2631
    {
2632
        $list = array();
2633
        $res = Database::query("SELECT user_id FROM " . Database::get_main_table(TABLE_MAIN_COURSE_USER) . "
2634
                WHERE c_id ='" . intval($courseId) . "' AND status=1");
2635
        while ($list_users = Database::fetch_array($res)) {
2636
            $result = Database::query("SELECT * FROM " . Database::get_main_table(TABLE_MAIN_USER) . "
2637
                    WHERE user_id=" . $list_users['user_id']);
2638
            while ($row_user = Database::fetch_array($result)) {
2639
                $name_teacher = api_get_person_name($row_user['firstname'], $row_user['lastname']);
2640
                $list[] = array($row_user['email'] => $name_teacher);
2641
            }
2642
        }
2643
        return $list;
2644
    }
2645
2646
    /**
2647
     * Get coaches emails by session
2648
     * @param int session id
2649
     * @param int $courseId
2650
     * @return array  array(email => name_tutor)  by coach
2651
     * @author Carlos Vargas <[email protected]>
2652
     */
2653
    public static function get_email_of_tutor_to_session($session_id, $courseId)
2654
    {
2655
        $tbl_session_course_user = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
2656
        $tbl_user = Database::get_main_table(TABLE_MAIN_USER);
2657
        $coachs_emails = array();
2658
2659
        $courseId = intval($courseId);
2660
        $session_id = intval($session_id);
2661
2662
        $sql = "SELECT user_id
2663
                FROM $tbl_session_course_user
2664
                WHERE
2665
                    session_id = '$session_id' AND
2666
                    c_id = '$courseId' AND
2667
                    status = 2
2668
                ";
2669
        $rs = Database::query($sql);
2670
2671
        if (Database::num_rows($rs) > 0) {
2672
2673
            $user_ids = array();
2674
            while ($row = Database::fetch_array($rs)) {
2675
                $user_ids[] = $row['user_id'];
2676
            }
2677
2678
            $sql = "SELECT firstname, lastname, email FROM $tbl_user
2679
                    WHERE user_id IN (" . implode(",", $user_ids) . ")";
2680
            $rs_user = Database::query($sql);
2681
2682
            while ($row_emails = Database::fetch_array($rs_user)) {
2683
                $mail_tutor = array(
2684
                    'email' => $row_emails['email'],
2685
                    'complete_name' => api_get_person_name($row_emails['firstname'], $row_emails['lastname'])
2686
                );
2687
                $coachs_emails[] = $mail_tutor;
2688
            }
2689
        }
2690
        return $coachs_emails;
2691
    }
2692
2693
    /**
2694
     * Creates a new extra field for a given course
2695
     * @param    string    Field's internal variable name
2696
     * @param    int        Field's type
2697
     * @param    string    Field's language var name
2698
     * @return int     new extra field id
2699
     */
2700
    public static function create_course_extra_field($variable, $fieldType, $displayText, $default)
2701
    {
2702
        $extraField = new ExtraField('course');
2703
        $params = [
2704
            'variable' => $variable,
2705
            'field_type' => $fieldType,
2706
            'display_text' => $displayText,
2707
            'default_value' => $default
2708
        ];
2709
2710
        return $extraField->save($params);
2711
    }
2712
2713
    /**
2714
     * Updates course attribute. Note that you need to check that your
2715
     * attribute is valid before you use this function
2716
     *
2717
     * @param int Course id
2718
     * @param string Attribute name
2719
     * @param string Attribute value
2720
     * @return bool True if attribute was successfully updated,
2721
     * false if course was not found or attribute name is invalid
2722
     */
2723 View Code Duplication
    public static function update_attribute($id, $name, $value)
2724
    {
2725
        $id = (int)$id;
2726
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
2727
        $sql = "UPDATE $table SET $name = '" . Database::escape_string($value) . "'
2728
                WHERE id = '$id';";
2729
        return Database::query($sql);
2730
    }
2731
2732
    /**
2733
     * Update course attributes. Will only update attributes with a non-empty value.
2734
     * Note that you NEED to check that your attributes are valid before using this function
2735
     *
2736
     * @param int Course id
2737
     * @param array Associative array with field names as keys and field values as values
2738
     * @return bool True if update was successful, false otherwise
2739
     */
2740
    public static function update_attributes($id, $attributes)
2741
    {
2742
        $id = (int)$id;
2743
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
2744
        $sql = "UPDATE $table SET ";
2745
        $i = 0;
2746
        foreach ($attributes as $name => $value) {
2747
            if ($value != '') {
2748
                if ($i > 0) {
2749
                    $sql .= ", ";
2750
                }
2751
                $sql .= " $name = '" . Database::escape_string($value) . "'";
2752
                $i++;
2753
            }
2754
        }
2755
        $sql .= " WHERE id = '$id';";
2756
        return Database::query($sql);
2757
    }
2758
2759
    /**
2760
     * Update an extra field value for a given course
2761
     * @param    integer    Course ID
2762
     * @param    string    Field variable name
2763
     * @param    string    Field value
2764
     * @return    boolean    true if field updated, false otherwise
2765
     */
2766
    public static function update_course_extra_field_value($course_code, $variable, $value = '')
2767
    {
2768
        $courseInfo = api_get_course_info($course_code);
2769
        $courseId = $courseInfo['real_id'];
2770
2771
        $extraFieldValues = new ExtraFieldValue('course');
2772
        $params = [
2773
            'item_id' => $courseId,
2774
            'variable' => $variable,
2775
            'value' => $value
2776
        ];
2777
        $extraFieldValues->save($params);
2778
    }
2779
2780
    /**
2781
     * @param int $session_id
2782
     * @return mixed
2783
     */
2784
    public static function get_session_category_id_by_session_id($session_id)
2785
    {
2786
        return Database::result(
2787
            Database::query('SELECT  sc.id session_category
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...ing($session_id) . '"') can be null; however, result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2788
                FROM ' . Database::get_main_table(TABLE_MAIN_SESSION_CATEGORY) . ' sc
2789
                INNER JOIN ' . Database::get_main_table(TABLE_MAIN_SESSION) . ' s
2790
                ON sc.id=s.session_category_id WHERE s.id="' . Database::escape_string($session_id) . '"'),
2791
            0,
2792
            'session_category'
2793
        );
2794
    }
2795
2796
    /**
2797
     * Gets the value of a course extra field. Returns null if it was not found
2798
     *
2799
     * @param string Name of the extra field
2800
     * @param string Course code
2801
     *
2802
     * @return string Value
2803
     */
2804
    public static function get_course_extra_field_value($variable, $code)
2805
    {
2806
        $courseInfo = api_get_course_info($code);
2807
        $courseId = $courseInfo['real_id'];
2808
2809
        $extraFieldValues = new ExtraFieldValue('course');
2810
        $result = $extraFieldValues->get_values_by_handler_and_field_variable($variable, $courseId);
2811
        if (!empty($result['value'])) {
2812
            return $result['value'];
2813
        }
2814
2815
        return null;
2816
    }
2817
2818
    /**
2819
     * Lists details of the course description
2820
     * @param array        The course description
2821
     * @param string    The encoding
2822
     * @param bool        If true is displayed if false is hidden
2823
     * @return string     The course description in html
2824
     */
2825
    public static function get_details_course_description_html($descriptions, $charset, $action_show = true)
2826
    {
2827
        $data = null;
2828
        if (isset($descriptions) && count($descriptions) > 0) {
2829
            foreach ($descriptions as $description) {
2830
                $data .= '<div class="sectiontitle">';
2831
                if (api_is_allowed_to_edit() && $action_show) {
2832
                    //delete
2833
                    $data .= '<a href="' . api_get_self() . '?' . api_get_cidreq() . '&action=delete&description_id=' . $description->id . '" onclick="javascript:if(!confirm(\'' . addslashes(api_htmlentities(get_lang('ConfirmYourChoice'),
2834
                                ENT_QUOTES, $charset)) . '\')) return false;">';
2835
                    $data .= Display::return_icon('delete.gif', get_lang('Delete'),
2836
                        array('style' => 'vertical-align:middle;float:right;'));
2837
                    $data .= '</a> ';
2838
                    //edit
2839
                    $data .= '<a href="' . api_get_self() . '?' . api_get_cidreq() . '&description_id=' . $description->id . '">';
2840
                    $data .= Display::return_icon('edit.png', get_lang('Edit'),
2841
                        array('style' => 'vertical-align:middle;float:right; padding-right:4px;'), ICON_SIZE_SMALL);
2842
                    $data .= '</a> ';
2843
                }
2844
                $data .= $description->title;
2845
                $data .= '</div>';
2846
                $data .= '<div class="sectioncomment">';
2847
                $data .= $description->content;
2848
                $data .= '</div>';
2849
            }
2850
        } else {
2851
            $data .= '<em>' . get_lang('ThisCourseDescriptionIsEmpty') . '</em>';
2852
        }
2853
2854
        return $data;
2855
    }
2856
2857
    /**
2858
     * Returns the details of a course category
2859
     *
2860
     * @param string Category code
2861
     * @return array Course category
2862
     */
2863
    public static function get_course_category($code)
2864
    {
2865
        $table_categories = Database::get_main_table(TABLE_MAIN_CATEGORY);
2866
        $sql = "SELECT * FROM $table_categories WHERE code = '$code';";
2867
        return Database::fetch_array(Database::query($sql));
0 ignored issues
show
Bug introduced by
It seems like \Database::query($sql) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
2868
    }
2869
2870
    /**
2871
     *  Get count rows of a table inside a course database
2872
     * @param  string $table   The table of which the rows should be counted
2873
     * @param  int $session_id       optionally count rows by session id
2874
     * @return int $course_id    The number of rows in the given table.
2875
     * @deprecated
2876
     */
2877
    public static function count_rows_course_table($table, $session_id = '', $course_id = null)
2878
    {
2879
        $condition_session = '';
2880
        if ($session_id !== '') {
2881
            $session_id = intval($session_id);
2882
            $condition_session = " AND session_id = '$session_id' ";
2883
        }
2884
        if (!empty($course_id)) {
2885
            $course_id = intval($course_id);
2886
        } else {
2887
            $course_id = api_get_course_int_id();
2888
        }
2889
        $condition_session .= " AND c_id = '$course_id' ";
2890
2891
        $sql = "SELECT COUNT(*) AS n FROM $table WHERE 1=1 $condition_session ";
2892
        $rs = Database::query($sql);
2893
        $row = Database::fetch_row($rs);
2894
        return $row[0];
2895
    }
2896
2897
    /**
2898
     * Subscribes courses to human resource manager (Dashboard feature)
2899
     * @param    int   $hr_manager_id      Human Resource Manager id
2900
     * @param    array $courses_list       Courses code
2901
     * @return int
2902
     **/
2903
    public static function subscribeCoursesToDrhManager($hr_manager_id, $courses_list)
2904
    {
2905
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
2906
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
2907
2908
        $hr_manager_id = intval($hr_manager_id);
2909
        $affected_rows = 0;
2910
2911
        //Deleting assigned courses to hrm_id
2912
        if (api_is_multiple_url_enabled()) {
2913
            $sql = "SELECT s.c_id FROM $tbl_course_rel_user s
2914
                    INNER JOIN $tbl_course_rel_access_url a
2915
                    ON (a.c_id = s.c_id)
2916
                    WHERE
2917
                        user_id = $hr_manager_id AND
2918
                        relation_type=" . COURSE_RELATION_TYPE_RRHH . " AND
2919
                        access_url_id = " . api_get_current_access_url_id() . "";
2920
        } else {
2921
            $sql = "SELECT c_id FROM $tbl_course_rel_user
2922
                    WHERE user_id = $hr_manager_id AND relation_type=" . COURSE_RELATION_TYPE_RRHH . " ";
2923
        }
2924
        $result = Database::query($sql);
2925 View Code Duplication
        if (Database::num_rows($result) > 0) {
2926
            while ($row = Database::fetch_array($result)) {
2927
                $sql = "DELETE FROM $tbl_course_rel_user
2928
                        WHERE
2929
                            c_id = '{$row['c_id']}' AND
2930
                            user_id = $hr_manager_id AND
2931
                            relation_type=" . COURSE_RELATION_TYPE_RRHH . " ";
2932
                Database::query($sql);
2933
            }
2934
        }
2935
2936
        // inserting new courses list
2937
        if (is_array($courses_list)) {
2938
            foreach ($courses_list as $course_code) {
2939
                $courseInfo = api_get_course_info($course_code);
2940
                $courseId = $courseInfo['real_id'];
2941
                $sql = "INSERT IGNORE INTO $tbl_course_rel_user(c_id, user_id, status, relation_type)
2942
                        VALUES($courseId, $hr_manager_id, '" . DRH . "', '" . COURSE_RELATION_TYPE_RRHH . "')";
2943
                $result = Database::query($sql);
2944
                if (Database::affected_rows($result)) {
2945
                    $affected_rows++;
2946
                }
2947
            }
2948
        }
2949
2950
        return $affected_rows;
2951
    }
2952
2953
    /**
2954
     * get courses followed by human resources manager
2955
     * @param int $user_id
2956
     * @param int $from
2957
     * @param int $limit
2958
     * @param string $column
2959
     * @param string $direction
2960
     * @return array    courses
2961
     */
2962
    public static function get_courses_followed_by_drh(
2963
        $user_id,
2964
        $status = DRH,
2965
        $from = null,
2966
        $limit = null,
2967
        $column = null,
2968
        $direction = null,
2969
        $getCount = false
2970
    ) {
2971
        return self::getCoursesFollowedByUser(
2972
            $user_id,
2973
            $status,
2974
            $from,
2975
            $limit,
2976
            $column,
2977
            $direction,
2978
            $getCount
2979
        );
2980
    }
2981
2982
    /**
2983
     * get courses followed by user
2984
     * @param   int $user_id
2985
     * @param   int $status
2986
     * @param   int $from
2987
     * @param   int $limit
2988
     * @param   string $column
2989
     * @param   string $direction
2990
     * @param   boolean $getCount
2991
     * @param   string $keyword
2992
     * @param   int $sessionId
2993
     * @param   boolean $showAllAssignedCourses
2994
     * @return  array   courses
2995
     */
2996
    public static function getCoursesFollowedByUser(
2997
        $user_id,
2998
        $status = null,
2999
        $from = null,
3000
        $limit = null,
3001
        $column = null,
3002
        $direction = null,
3003
        $getCount = false,
3004
        $keyword = null,
3005
        $sessionId = null,
3006
        $showAllAssignedCourses = false
3007
    ) {
3008
        // Database Table Definitions
3009
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3010
        $tbl_course_rel_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3011
        $tbl_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3012
        $sessionId = intval($sessionId);
3013
        $user_id = intval($user_id);
3014
        $select = "SELECT DISTINCT *, c.id as real_id ";
3015
3016
        if ($getCount) {
3017
            $select = "SELECT COUNT(DISTINCT c.id) as count";
3018
        }
3019
3020
        $whereConditions = null;
3021
        switch ($status) {
3022
            case COURSEMANAGER:
3023
                $whereConditions .= " AND cru.user_id = '$user_id'";
3024
                if (!$showAllAssignedCourses) {
3025
                    $whereConditions .= " AND status = " . COURSEMANAGER;
3026
                } else {
3027
                    $whereConditions .= " AND relation_type = " . COURSE_RELATION_TYPE_COURSE_MANAGER;
3028
                }
3029
                break;
3030
            case DRH:
3031
                $whereConditions .= " AND
3032
                    cru.user_id = '$user_id' AND
3033
                    status = " . DRH . " AND
3034
                    relation_type = '" . COURSE_RELATION_TYPE_RRHH . "'
3035
                ";
3036
                break;
3037
        }
3038
3039
        $keywordCondition = null;
3040
        if (!empty($keyword)) {
3041
            $keyword = Database::escape_string($keyword);
3042
            $keywordCondition = " AND (c.code LIKE '%$keyword%' OR c.title LIKE '%$keyword%' ) ";
3043
        }
3044
3045
        $orderBy = null;
3046
        $extraInnerJoin = null;
3047
3048
        if (!empty($sessionId)) {
3049
            if (!empty($sessionId)) {
3050
                $courseList = SessionManager::get_course_list_by_session_id(
3051
                    $sessionId
3052
                );
3053
                if (!empty($courseList)) {
3054
                    $courseListToString = implode("','", array_keys($courseList));
3055
                    $whereConditions .= " AND c.id IN ('" . $courseListToString . "')";
3056
                }
3057
                $tableSessionRelCourse = Database::get_main_table(TABLE_MAIN_SESSION_COURSE);
3058
                $orderBy = ' ORDER BY position';
3059
                $extraInnerJoin = " INNER JOIN $tableSessionRelCourse src
3060
                                    ON (c.id = src.c_id AND session_id = $sessionId) ";
3061
            }
3062
        }
3063
3064
        $whereConditions .= $keywordCondition;
3065
        $sql = "$select
3066
                FROM $tbl_course c
3067
                    INNER JOIN $tbl_course_rel_user cru ON (cru.c_id = c.id)
3068
                    INNER JOIN $tbl_course_rel_access_url a ON (a.c_id = c.id)
3069
                    $extraInnerJoin
3070
                WHERE
3071
                    access_url_id = " . api_get_current_access_url_id() . "
3072
                    $whereConditions
3073
                $orderBy
3074
                ";
3075 View Code Duplication
        if (isset($from) && isset($limit)) {
3076
            $from = intval($from);
3077
            $limit = intval($limit);
3078
            $sql .= " LIMIT $from, $limit";
3079
        }
3080
3081
        $result = Database::query($sql);
3082
3083
        if ($getCount) {
3084
            $row = Database::fetch_array($result);
3085
            return $row['count'];
3086
        }
3087
3088
        $courses = array();
3089
        if (Database::num_rows($result) > 0) {
3090
            while ($row = Database::fetch_array($result)) {
3091
                $courses[$row['code']] = $row;
3092
            }
3093
        }
3094
        return $courses;
3095
    }
3096
3097
    /**
3098
     * check if a course is special (autoregister)
3099
     * @param int $courseId
3100
     * @return bool
3101
     */
3102
    public static function isSpecialCourse($courseId)
3103
    {
3104
        $extraFieldValue = new ExtraFieldValue('course');
3105
        $result = $extraFieldValue->get_values_by_handler_and_field_variable(
3106
            $courseId,
3107
            'special_course'
3108
        );
3109
3110
        if (!empty($result)) {
3111
            if ($result['value'] == 1) {
3112
                return true;
3113
            }
3114
        }
3115
3116
        return false;
3117
    }
3118
3119
    /**
3120
     * Update course picture
3121
     * @param   string  Course code
3122
     * @param   string  File name
3123
     * @param   string  The full system name of the image from which course picture will be created.
3124
     * @param   string $cropParameters Optional string that contents "x,y,width,height" of a cropped image format
3125
     * @return  bool    Returns the resulting. In case of internal error or negative validation returns FALSE.
3126
     */
3127
    public static function update_course_picture($course_code, $filename, $source_file = null, $cropParameters = null)
3128
    {
3129
        $course_info = api_get_course_info($course_code);
3130
        // course path
3131
        $store_path = api_get_path(SYS_COURSE_PATH) . $course_info['path'];
3132
        // image name for courses
3133
        $course_image = $store_path . '/course-pic.png';
3134
        $course_medium_image = $store_path . '/course-pic85x85.png';
3135
3136
        if (file_exists($course_image)) {
3137
            unlink($course_image);
3138
        }
3139
        if (file_exists($course_medium_image)) {
3140
            unlink($course_medium_image);
3141
        }
3142
3143
        //Crop the image to adjust 4:3 ratio
3144
        $image = new Image($source_file);
3145
        $image->crop($cropParameters);
3146
3147
        //Resize the images in two formats
3148
        $medium = new Image($source_file);
3149
        $medium->resize(85);
3150
        $medium->send_image($course_medium_image, -1, 'png');
3151
        $normal = new Image($source_file);
3152
        $normal->resize(300);
3153
        $normal->send_image($course_image, -1, 'png');
3154
3155
        $result = $medium && $normal;
3156
3157
        return $result ? $result : false;
3158
    }
3159
3160
    /**
3161
     * Deletes the course picture
3162
     * @param string $courseCode
3163
     */
3164
    public static function deleteCoursePicture($courseCode)
3165
    {
3166
        $course_info = api_get_course_info($courseCode);
3167
        // course path
3168
        $storePath = api_get_path(SYS_COURSE_PATH) . $course_info['path'];
3169
        // image name for courses
3170
        $courseImage = $storePath . '/course-pic.png';
3171
        $courseMediumImage = $storePath . '/course-pic85x85.png';
3172
        $courseSmallImage = $storePath . '/course-pic32.png';
3173
3174
        if (file_exists($courseImage)) {
3175
            unlink($courseImage);
3176
        }
3177
        if (file_exists($courseMediumImage)) {
3178
            unlink($courseMediumImage);
3179
        }
3180
        if (file_exists($courseSmallImage)) {
3181
            unlink($courseSmallImage);
3182
        }
3183
    }
3184
3185
    /**
3186
     * Builds the course block in user_portal.php
3187
     * @todo use Twig
3188
     *
3189
     * @param array $params
3190
     * @return string
3191
     */
3192
    public static function course_item_html_no_icon($params)
3193
    {
3194
        $html = '<div class="course_item">';
3195
        $html .= '<div class="row">';
3196
        $html .= '<div class="col-md-7">';
3197
3198
        $notifications = isset($params['notifications']) ? $params['notifications'] : null;
3199
3200
        $html .= '<h3>' . $params['title'] . $notifications . '</h3> ';
3201
3202
        if (isset($params['description'])) {
3203
            $html .= '<p>' . $params['description'] . '</p>';
3204
        }
3205
        if (!empty($params['subtitle'])) {
3206
            $html .= '<small>' . $params['subtitle'] . '</small>';
3207
        }
3208
        if (!empty($params['teachers'])) {
3209
            $html .= '<h5 class="teacher">' . Display::return_icon('teacher.png', get_lang('Teacher'), array(),
3210
                    ICON_SIZE_TINY) . $params['teachers'] . '</h5>';
3211
        }
3212
        if (!empty($params['coaches'])) {
3213
            $html .= '<h5 class="teacher">' . Display::return_icon('teacher.png', get_lang('Coach'), array(),
3214
                    ICON_SIZE_TINY) . $params['coaches'] . '</h5>';
3215
        }
3216
3217
        $html .= '</div>';
3218
        $params['right_actions'] = isset($params['right_actions']) ? $params['right_actions'] : null;
3219
        $html .= '<div class="pull-right course-box-actions">' . $params['right_actions'] . '</div>';
3220
        $html .= '</div>';
3221
        $html .= '</div>';
3222
        return $html;
3223
    }
3224
3225
    /**
3226
     * @param $params
3227
     * @param bool|false $is_sub_content
3228
     * @return string
3229
     */
3230
    public static function session_items_html($params, $is_sub_content = false)
3231
    {
3232
        $html = '';
3233
        $html .= '<div class="row">';
3234
        $html .= '<div class="col-md-2">';
3235
        if (!empty($params['link'])){
3236
            $html .= '<a class="thumbnail" href="'.$params['link'].'">';
3237
            $html .= $params['icon'];
3238
            $html .= '</a>';
3239
        }else{
3240
            $html .= $params['icon'];
3241
        }
3242
        $html .= '</div>';
3243
        $html .= '<div class="col-md-10">';
3244
        $html .= $params['title'];
3245
        $html .= $params['coaches'];
3246
        $html .= '</div>';
3247
        $html .= '</div>';
3248
3249
        return $html;
3250
    }
3251
3252
    /**
3253
     * Builds the course block in user_portal.php
3254
     * @todo use Twig
3255
     * @param array $params
3256
     * @param bool|false $is_sub_content
3257
     * @return string
3258
     */
3259
    public static function course_item_html($params, $is_sub_content = false)
3260
    {
3261
        $html = '';
3262
        $class = "panel panel-default";
3263
        if ($is_sub_content) {
3264
            $class = "course_item";
3265
        }
3266
        $html .= '<div class="' . $class . '">';
3267
        $html .= '<div class="panel-body">';
3268
        $html .= '<div class="course-items">';
3269
        $html .= ' <div class="row">';
3270
        $html .= '<div class="col-md-2">';
3271
        if (!empty($params['link'])) {
3272
            $html .= '<a class="thumbnail" href="' . $params['link'] . '">';
3273
            $html .= $params['icon'];
3274
            $html .= '</a>';
3275
        } else {
3276
            $html .= '<div class="thumbnail">';
3277
            $html .= $params['icon'];
3278
            $html .= '</div>';
3279
        }
3280
        $html .= '</div>';
3281
        $notifications = isset($params['notifications']) ? $params['notifications'] : '';
3282
        $param_class = isset($params['class']) ? $params['class'] : '';
3283
        $params['right_actions'] = isset($params['right_actions']) ? $params['right_actions'] : '';
3284
3285
        $html .= '<div class="col-md-10 ' . $param_class . '">';
3286
        $html .= '<div class="pull-right">' . $params['right_actions'] . '</div>';
3287
        $html .= '<h4 class="course-items-title">' . $params['title'] . $notifications . '</h4> ';
3288
3289
        if (isset($params['show_description'], $params['description']) && $params['show_description'] == 1) {
3290
            $html .= '<p class="description-session">' . $params['description'] . '</p>';
3291
        }
3292
        if (!empty($params['subtitle'])) {
3293
            $html .= '<div class="subtitle-session">' . $params['subtitle'] . '</div>';
3294
        }
3295
        if (!empty($params['teachers'])) {
3296
            $html .= '<h5 class="course-items-session">' .
3297
                    Display::return_icon('teacher.png', get_lang('Teacher'), array(), ICON_SIZE_TINY) .
3298
                $params['teachers'] . '</h5>';
3299
        }
3300
        if (!empty($params['coaches'])) {
3301
            $html .= '<h5 class="course-items-session">' .
3302
                Display::return_icon('teacher.png', get_lang('Coach'), array(), ICON_SIZE_TINY) .
3303
                $params['coaches'] . '</h5>';
3304
        }
3305
3306
        $html .= '</div>';
3307
        $html .= '</div>';
3308
3309
        $html .= '</div>';
3310
3311
        $html .= '</div>';
3312
        $html .= '</div>';
3313
        return $html;
3314
    }
3315
3316
    /**
3317
     * @param string $main_content
3318
     * @param string $sub_content
3319
     * @param string $sub_sub_content
3320
     * @return string
3321
     */
3322
    public static function course_item_parent($main_content, $sub_content, $sub_sub_content = null)
3323
    {
3324
        return '<div class="panel panel-default">' . $main_content . $sub_content . $sub_sub_content . '</div>';
3325
    }
3326
3327
    /**
3328
     * Display special courses (and only these) as several HTML divs of class userportal-course-item
3329
     *
3330
     * Special courses are courses that stick on top of the list and are "auto-registerable"
3331
     * in the sense that any user clicking them is registered as a student
3332
     * @param int       User id
3333
     * @param bool      Whether to show the document quick-loader or not
3334
     * @return string
3335
     */
3336
    public static function display_special_courses($user_id, $load_dirs = false)
3337
    {
3338
        $user_id = intval($user_id);
3339
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
3340
        $tbl_course_user = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3341
3342
        $special_course_list = self::get_special_course_list();
3343
3344
        $with_special_courses = $without_special_courses = '';
3345
        if (!empty($special_course_list)) {
3346
            $with_special_courses = ' course.code IN ("' . implode('","', $special_course_list) . '")';
3347
        }
3348
        $html = null;
3349
        $courseCount = 0;
3350
        if (!empty($with_special_courses)) {
3351
            $sql = "SELECT
3352
                        course.id,
3353
                        course.code,
3354
                        course.subscribe subscr,
3355
                        course.unsubscribe unsubscr,
3356
                        course_rel_user.status status,
3357
                        course_rel_user.sort sort,
3358
                        course_rel_user.user_course_cat user_course_cat,
3359
                        course_rel_user.user_id
3360
                    FROM $tbl_course course
3361
                    LEFT JOIN $tbl_course_user course_rel_user
3362
                    ON course.id = course_rel_user.c_id AND course_rel_user.user_id = '$user_id'
3363
                    WHERE $with_special_courses group by course.code";
3364
3365
            $rs_special_course = Database::query($sql);
3366
            $number_of_courses = Database::num_rows($rs_special_course);
3367
3368
            $key = 0;
3369
3370
            if ($number_of_courses > 0) {
3371
                while ($course = Database::fetch_array($rs_special_course)) {
3372
                    $course_info = api_get_course_info($course['code']);
3373
                    if ($course_info['visibility'] == COURSE_VISIBILITY_HIDDEN) {
3374
                        continue;
3375
                    }
3376
                    $courseCount++;
3377
                    $params = array();
3378
                    // Get notifications.
3379
                    $course_info['id_session'] = null;
3380
                    $course_info['status'] = $course['status'];
3381
                    $show_notification = Display::show_notification($course_info);
3382
3383
                    if (empty($course['user_id'])) {
3384
                        $course['status'] = STUDENT;
3385
                    }
3386
3387
                    $params['icon'] = Display::return_icon(
3388
                        'blackboard.png',
3389
                        api_htmlentities($course_info['title']),
3390
                        array(),
3391
                        ICON_SIZE_LARGE
3392
                    );
3393
3394
                    $params['right_actions'] = '';
3395
                    if (api_is_platform_admin()) {
3396
                        if ($load_dirs) {
3397
                            $params['right_actions'] .= '<a id="document_preview_' . $course['id'] . '_0" class="document_preview" href="javascript:void(0);">' .
3398
                                Display::return_icon(
3399
                                    'folder.png',
3400
                                    get_lang('Documents'),
3401
                                    array('align' => 'absmiddle'),
3402
                                    ICON_SIZE_SMALL
3403
                                ).'</a>';
3404
                            $params['right_actions'] .= '<a href="' . api_get_path(WEB_CODE_PATH) . 'course_info/infocours.php?cidReq=' . $course['code'] . '">' .
3405
                                Display::return_icon(
3406
                                    'edit.png',
3407
                                    get_lang('Edit'),
3408
                                    array('align' => 'absmiddle'),
3409
                                    ICON_SIZE_SMALL
3410
                                ).'</a>';
3411
                            $params['right_actions'] .= Display::div('', array(
3412
                                    'id' => 'document_result_' . $course['id'] . '_0',
3413
                                    'class' => 'document_preview_container'
3414
                                ));
3415
                        } else {
3416
                            $params['right_actions'] .= '<a href="' . api_get_path(WEB_CODE_PATH) . 'course_info/infocours.php?cidReq=' . $course['code'] . '">' .
3417
                                Display::return_icon('edit.png',
3418
                                    get_lang('Edit'), array('align' => 'absmiddle'), ICON_SIZE_SMALL) . '</a>';
3419
                        }
3420
                        if ($course['status'] == COURSEMANAGER) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3421
                            //echo Display::return_icon('teachers.gif', get_lang('Status').': '.get_lang('Teacher'), array('style'=>'width: 11px; height: 11px;'));
3422
                        }
3423
                    } else {
3424
                        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3425
                            if ($load_dirs) {
3426
                                $params['right_actions'] .= '<a id="document_preview_' . $course['id'] . '_0" class="document_preview" href="javascript:void(0);">' .
3427
                                    Display::return_icon(
3428
                                        'folder.png',
3429
                                        get_lang('Documents'),
3430
                                        array('align' => 'absmiddle'),
3431
                                        ICON_SIZE_SMALL
3432
                                    ).'</a>';
3433
                                $params['right_actions'] .= Display::div('', array(
3434
                                        'id' => 'document_result_' . $course['id'] . '_0',
3435
                                        'class' => 'document_preview_container'
3436
                                    ));
3437
                            }
3438
                        }
3439
                    }
3440
3441
                    if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED || $course['status'] == COURSEMANAGER) {
3442
                        $course_title = '<a href="' . $course_info['course_public_url'] . '?id_session=0&autoreg=1">' . $course_info['title'] . '</a>';
3443
                    } else {
3444
                        $course_title = $course_info['title'] . " " . Display::tag('span', get_lang('CourseClosed'),
3445
                                array('class' => 'item_closed'));
3446
                    }
3447
3448
                    if (api_get_setting('display_coursecode_in_courselist') == 'true') {
3449
                        $course_title .= ' (' . $course_info['visual_code'] . ') ';
3450
                    }
3451 View Code Duplication
                    if (api_get_setting('display_teacher_in_courselist') == 'true') {
3452
                        $params['teachers'] = CourseManager::get_teacher_list_from_course_code_to_string(
3453
                            $course['code'],
3454
                            self::USER_SEPARATOR,
3455
                            true
3456
                        );
3457
                    }
3458
                    $course_title .= '&nbsp;';
3459
                    $course_title .= Display::return_icon('klipper.png', get_lang('CourseAutoRegister'));
3460
3461
                    $params['title'] = $course_title;
3462
                    $params['link'] = $course_info['course_public_url'].'?id_session=0&autoreg=1';
3463
3464
                    if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3465
                        $params['notifications'] = $show_notification;
3466
                    }
3467
3468
                    $html .= self::course_item_html($params, false);
3469
                    $key++;
3470
                }
3471
            }
3472
        }
3473
3474
        return [
3475
            'html' => $html,
3476
            'course_count' => $courseCount
3477
        ];
3478
    }
3479
3480
    /**
3481
     * Display courses (without special courses) as several HTML divs
3482
     * of course categories, as class userportal-catalog-item.
3483
     * @uses displayCoursesInCategory() to display the courses themselves
3484
     * @param int        user id
3485
     * @param bool      Whether to show the document quick-loader or not
3486
     * @return string
3487
     */
3488
    public static function display_courses($user_id, $load_dirs = false)
3489
    {
3490
        $user_id = intval($user_id);
3491
        if (empty($user_id)) {
3492
            $user_id = api_get_user_id();
3493
        }
3494
3495
        // Step 1: We get all the categories of the user
3496
        $table = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3497
        $sql = "SELECT id, title FROM $table
3498
                WHERE user_id = '" . $user_id . "'
3499
                ORDER BY sort ASC";
3500
        $result = Database::query($sql);
3501
        $html = null;
3502
        $courseCount = 0;
3503
        while ($row = Database::fetch_array($result)) {
3504
            // We simply display the title of the category.
3505
            $params = array(
3506
                'icon' => Display::return_icon(
3507
                    'folder_yellow.png',
3508
                    api_htmlentities($row['title']), array(), ICON_SIZE_LARGE
3509
                ),
3510
                'title' => $row['title'],
3511
                'class' => 'table_user_course_category'
3512
            );
3513
3514
            $courseInCategory = self:: displayCoursesInCategory(
3515
                $row['id'],
3516
                $load_dirs
3517
            );
3518
3519
            $html .= self::course_item_parent(
3520
                self::course_item_html($params, true),
3521
                $courseInCategory['html']
3522
            );
3523
            $courseCount += $courseInCategory['course_count'];
3524
        }
3525
3526
        // Step 2: We display the course without a user category.
3527
        $courseInCategory = self::displayCoursesInCategory(0, $load_dirs);
3528
3529
        $html .= $courseInCategory['html'];
3530
        $courseCount += $courseInCategory['course_count'];
3531
3532
        return [
3533
            'html' => $html,
3534
            'course_count' => $courseCount
3535
        ];
3536
    }
3537
3538
    /**
3539
     *  Display courses inside a category (without special courses) as HTML dics of
3540
     *  class userportal-course-item.
3541
     * @param int      User category id
3542
     * @param bool      Whether to show the document quick-loader or not
3543
     * @return string
3544
     */
3545
    public static function displayCoursesInCategory($user_category_id, $load_dirs = false)
3546
    {
3547
        $user_id = api_get_user_id();
3548
        // Table definitions
3549
        $TABLECOURS = Database:: get_main_table(TABLE_MAIN_COURSE);
3550
        $TABLECOURSUSER = Database:: get_main_table(TABLE_MAIN_COURSE_USER);
3551
        $TABLE_ACCESS_URL_REL_COURSE = Database:: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
3552
        $current_url_id = api_get_current_access_url_id();
3553
3554
        // Get course list auto-register
3555
        $special_course_list = self::get_special_course_list();
3556
3557
        $without_special_courses = '';
3558
        if (!empty($special_course_list)) {
3559
            $without_special_courses = ' AND course.code NOT IN ("' . implode('","', $special_course_list) . '")';
3560
        }
3561
3562
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
3563
        $sql = "SELECT
3564
                course.id,
3565
                course.title,
3566
                course.code,
3567
                course.subscribe subscr,
3568
                course.unsubscribe unsubscr,
3569
                course_rel_user.status status,
3570
                course_rel_user.sort sort,
3571
                course_rel_user.user_course_cat user_course_cat
3572
                FROM $TABLECOURS course,
3573
                     $TABLECOURSUSER course_rel_user,
3574
                     $TABLE_ACCESS_URL_REL_COURSE url
3575
                WHERE
3576
                    course.id = course_rel_user.c_id AND
3577
                    url.c_id = course.id AND
3578
                    course_rel_user.user_id = '" . $user_id . "' AND
3579
                    course_rel_user.user_course_cat = '" . $user_category_id . "'
3580
                    $without_special_courses ";
3581
3582
        // If multiple URL access mode is enabled, only fetch courses
3583
        // corresponding to the current URL.
3584
        if (api_get_multiple_access_url() && $current_url_id != -1) {
3585
            $sql .= " AND url.c_id = course.id AND access_url_id='" . $current_url_id . "'";
3586
        }
3587
        // Use user's classification for courses (if any).
3588
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
3589
3590
        $result = Database::query($sql);
3591
        $html = '';
3592
3593
        $course_list = array();
3594
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3595
        $courseCount = 0;
3596
        // Browse through all courses.
3597
        while ($course = Database::fetch_array($result)) {
3598
            $course_info = api_get_course_info($course['code']);
3599
            if (isset($course_info['visibility']) &&
3600
                $course_info['visibility'] == COURSE_VISIBILITY_HIDDEN
3601
            ) {
3602
                continue;
3603
            }
3604
            $course_info['id_session'] = null;
3605
            $course_info['status'] = $course['status'];
3606
3607
            //In order to avoid doubles
3608
            if (in_array($course_info['real_id'], $course_list)) {
3609
                continue;
3610
            } else {
3611
                $course_list[] = $course_info['real_id'];
3612
            }
3613
3614
            $courseCount++;
3615
3616
            // For each course, get if there is any notification icon to show
3617
            // (something that would have changed since the user's last visit).
3618
            $show_notification = Display::show_notification($course_info);
3619
3620
            $status_icon = Display::return_icon(
3621
                'blackboard.png',
3622
                api_htmlentities($course_info['title']),
3623
                array(),
3624
                ICON_SIZE_LARGE
3625
            );
3626
3627
            $iconName = basename($course_info['course_image']);
3628 View Code Duplication
            if ($showCustomIcon === 'true' && $iconName != 'course.png') {
3629
                $status_icon = Display::img(
3630
                    $course_info['course_image'],
3631
                    api_htmlentities($course_info['title']),
3632
                    array()
3633
                );
3634
            }
3635
3636
            $params = array();
3637
            $params['right_actions'] = '';
3638
3639 View Code Duplication
            if (api_is_platform_admin()) {
3640
                if ($load_dirs) {
3641
                    $params['right_actions'] .= '<a id="document_preview_' . $course_info['real_id'] . '_0" class="document_preview" href="javascript:void(0);">' . Display::return_icon('folder.png',
3642
                            get_lang('Documents'), array('align' => 'absmiddle'), ICON_SIZE_SMALL) . '</a>';
3643
                    $params['right_actions'] .= '<a href="' . api_get_path(WEB_CODE_PATH) . 'course_info/infocours.php?cidReq=' . $course['code'] . '">' . Display::return_icon('edit.png',
3644
                            get_lang('Edit'), array('align' => 'absmiddle'), ICON_SIZE_SMALL) . '</a>';
3645
                    $params['right_actions'] .= Display::div('', array(
3646
                            'id' => 'document_result_' . $course_info['real_id'] . '_0',
3647
                            'class' => 'document_preview_container'
3648
                        ));
3649
                } else {
3650
                    $params['right_actions'] .= '<a href="' . api_get_path(WEB_CODE_PATH) . 'course_info/infocours.php?cidReq=' . $course['code'] . '">' . Display::return_icon('edit.png',
3651
                            get_lang('Edit'), array('align' => 'absmiddle'), ICON_SIZE_SMALL) . '</a>';
3652
                }
3653
3654
                if ($course_info['status'] == COURSEMANAGER) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
3655
                    //echo Display::return_icon('teachers.gif', get_lang('Status').': '.get_lang('Teacher'), array('style'=>'width: 11px; height: 11px;'));
3656
                }
3657
            } else {
3658
                if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3659
                    if ($load_dirs) {
3660
                        $params['right_actions'] .= '<a id="document_preview_' . $course_info['real_id'] . '_0" class="document_preview" href="javascript:void(0);">' . Display::return_icon('folder.png',
3661
                                get_lang('Documents'), array('align' => 'absmiddle'), ICON_SIZE_SMALL) . '</a>';
3662
                        $params['right_actions'] .= Display::div('', array(
3663
                                'id' => 'document_result_' . $course_info['real_id'] . '_0',
3664
                                'class' => 'document_preview_container'
3665
                            ));
3666
                    } else {
3667
                        if ($course_info['status'] == COURSEMANAGER) {
3668
                            $params['right_actions'] .= '<a href="' . api_get_path(WEB_CODE_PATH) . 'course_info/infocours.php?cidReq=' . $course['code'] . '">' . Display::return_icon('edit.png',
3669
                                    get_lang('Edit'), array('align' => 'absmiddle'), ICON_SIZE_SMALL) . '</a>';
3670
                        }
3671
                    }
3672
                }
3673
            }
3674
3675
            $course_title_url = '';
3676 View Code Duplication
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED || $course['status'] == COURSEMANAGER) {
3677
                $course_title_url = api_get_path(WEB_COURSE_PATH) . $course_info['path'] . '/index.php?id_session=0';
3678
                $course_title = Display::url($course_info['title'], $course_title_url);
3679
            } else {
3680
                $course_title = $course_info['title'] . " " . Display::tag('span', get_lang('CourseClosed'),
3681
                        array('class' => 'item_closed'));
3682
            }
3683
3684
            // Start displaying the course block itself
3685
            if (api_get_setting('display_coursecode_in_courselist') == 'true') {
3686
                $course_title .= ' (' . $course_info['visual_code'] . ') ';
3687
            }
3688
3689 View Code Duplication
            if (api_get_setting('display_teacher_in_courselist') == 'true') {
3690
                $teachers = CourseManager::get_teacher_list_from_course_code_to_string(
3691
                    $course['code'],
3692
                    self::USER_SEPARATOR,
3693
                    true
3694
                );
3695
            }
3696
3697
            $params['link'] = $course_title_url;
3698
            $params['icon'] = $status_icon;
3699
            $params['title'] = $course_title;
3700
            $params['teachers'] = $teachers;
3701
3702
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
3703
                $params['notifications'] = $show_notification;
3704
            }
3705
3706
            $isSubContent = true;
3707
            if (empty($user_category_id)) {
3708
                $isSubContent = false;
3709
            }
3710
            $html .= self::course_item_html($params, $isSubContent);
3711
        }
3712
3713
        return [
3714
            'html' => $html,
3715
            'course_count' => $courseCount
3716
        ];
3717
    }
3718
3719
    /**
3720
     * Retrieves the user defined course categories
3721
     * @param string $userId
3722
     * @return array containing all the titles of the user defined courses with the id as key of the array
3723
     */
3724 View Code Duplication
    public static function get_user_course_categories($userId = '')
3725
    {
3726
        if ($userId == '') {
3727
            $realUserId = api_get_user_id();
3728
        } else {
3729
            $realUserId = $userId;
3730
        }
3731
3732
        $output = array();
3733
        $table_category = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3734
        $sql = "SELECT * FROM $table_category WHERE user_id = '".intval($realUserId)."'";
3735
        $result = Database::query($sql);
3736
        while ($row = Database::fetch_array($result)) {
3737
            $output[$row['id']] = $row['title'];
3738
        }
3739
        return $output;
3740
    }
3741
3742
    /**
3743
     * Return an array the user_category id and title for the course $courseId for user $userId
3744
     * @param $userId
3745
     * @param $courseId
3746
     * @return array
3747
     */
3748 View Code Duplication
    public static function getUserCourseCategoryForCourse($userId, $courseId)
3749
    {
3750
        $tblCourseRelUser = Database::get_main_table(TABLE_MAIN_COURSE_USER);
3751
        $tblUserCategory = Database::get_main_table(TABLE_USER_COURSE_CATEGORY);
3752
        $courseId = intval($courseId);
3753
        $userId = intval($userId);
3754
3755
        $sql = "SELECT user_course_cat, title
3756
                FROM $tblCourseRelUser cru
3757
                LEFT JOIN $tblUserCategory ucc
3758
                ON cru.user_course_cat = ucc.id
3759
                WHERE
3760
                    cru.user_id = $userId AND c_id= $courseId ";
3761
3762
        $res = Database::query($sql);
3763
3764
        $result = array();
3765
        if (Database::num_rows($res) > 0) {
3766
            $data = Database::fetch_assoc($res);
3767
            $result[] = $data['user_course_cat'];
3768
            $result[] = $data['title'];
3769
        }
3770
        return $result;
3771
    }
3772
3773
    /**
3774
     * Get the course id based on the original id and field name in the extra fields.
3775
     * Returns 0 if course was not found
3776
     *
3777
     * @param string $value Original course code
3778
     * @param string $variable Original field name
3779
     * @return int Course id
3780
     */
3781
    public static function getCourseInfoFromOriginalId($value, $variable)
3782
    {
3783
        $extraFieldValue = new ExtraFieldValue('course');
3784
        $result = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
3785
            $variable,
3786
            $value
3787
        );
3788
3789
        if (!empty($result)) {
3790
            $courseInfo = api_get_course_info_by_id($result['item_id']);
3791
            return $courseInfo;
3792
        }
3793
3794
        return 0;
3795
    }
3796
3797
    /**
3798
     * Display code for one specific course a logged in user is subscribed to.
3799
     * Shows a link to the course, what's new icons...
3800
     *
3801
     * $my_course['d'] - course directory
3802
     * $my_course['i'] - course title
3803
     * $my_course['c'] - visual course code
3804
     * $my_course['k']  - system course code
3805
     *
3806
     * @param   array       Course details
3807
     * @param   integer     Session ID
3808
     * @param   string      CSS class to apply to course entry
3809
     * @param   boolean     Whether the session is supposedly accessible now
3810
     * (not in the case it has passed and is in invisible/unaccessible mode)
3811
     * @param bool      Whether to show the document quick-loader or not
3812
     * @return  string      The HTML to be printed for the course entry
3813
     *
3814
     * @version 1.0.3
3815
     * @todo refactor into different functions for database calls | logic | display
3816
     * @todo replace single-character $my_course['d'] indices
3817
     * @todo move code for what's new icons to a separate function to clear things up
3818
     * @todo add a parameter user_id so that it is possible to show the
3819
     * courselist of other users (=generalisation).
3820
     * This will prevent having to write a new function for this.
3821
     */
3822
    public static function get_logged_user_course_html(
3823
        $course,
3824
        $session_id = 0,
3825
        $class = 'courses',
3826
        $session_accessible = true,
3827
        $load_dirs = false
3828
    ) {
3829
        $entityManager = Database::getManager();
3830
        $user_id = api_get_user_id();
3831
        $course_info = api_get_course_info_by_id($course['real_id']);
3832
        $status_course = CourseManager::get_user_in_course_status($user_id, $course_info['code']);
3833
        $course_info['status'] = empty($session_id) ? $status_course : STUDENT;
3834
        $course_info['id_session'] = $session_id;
3835
        $objUser = $entityManager->find('ChamiloUserBundle:User', $user_id);
3836
        $objCourse = $entityManager->find('ChamiloCoreBundle:Course', $course['real_id']);
3837
        $objSession = $entityManager->find('ChamiloCoreBundle:Session', $session_id);
3838
3839
        /*$date_start = $sess[$course_info['id_session']]['access_start_date'];
3840
        $date_end = $sess[$course_info['id_session']]['access_end_date'];*/
3841
3842
        $now = date('Y-m-d h:i:s');
3843
3844
        // Table definitions
3845
        $main_user_table = Database:: get_main_table(TABLE_MAIN_USER);
3846
        $tbl_session = Database:: get_main_table(TABLE_MAIN_SESSION);
3847
        $tbl_session_category = Database:: get_main_table(TABLE_MAIN_SESSION_CATEGORY);
3848
3849
        $course_access_settings = CourseManager::get_access_settings($course_info['code']);
3850
        $course_visibility = $course_access_settings['visibility'];
3851
3852
        if ($course_visibility == COURSE_VISIBILITY_HIDDEN) {
3853
            return '';
3854
        }
3855
3856
        $user_in_course_status = CourseManager::get_user_in_course_status(
3857
            api_get_user_id(),
3858
            $course_info['code']
3859
        );
3860
3861
        $is_coach = api_is_coach($course_info['id_session'], $course_info['real_id']);
3862
3863
        // Display course entry.
3864
        // Show a hyperlink to the course, unless the course is closed and user is not course admin.
3865
        $session_url = '';
3866
        $session_title = '';
3867
3868
        $params = array();
3869
        $params['icon'] = Display::return_icon(
3870
            'blackboard_blue.png',
3871
            api_htmlentities($course_info['name']),
3872
            array(),
3873
            ICON_SIZE_LARGE
3874
        );
3875
3876
        // Display the "what's new" icons
3877
        $notifications = '';
3878
        if ($course_visibility != COURSE_VISIBILITY_CLOSED && $course_visibility != COURSE_VISIBILITY_HIDDEN) {
3879
            $notifications .= Display:: show_notification($course_info);
3880
        }
3881
3882
        if ($session_accessible) {
3883
            if ($course_visibility != COURSE_VISIBILITY_CLOSED ||
3884
                $user_in_course_status == COURSEMANAGER
3885
            ) {
3886
                if (empty($course_info['id_session'])) {
3887
                    $course_info['id_session'] = 0;
3888
                }
3889
3890
                $sessionCourseAvailable = false;
3891
                $sessionCourseStatus = api_get_session_visibility($session_id, $course_info['real_id']);
3892
3893
                if (in_array($sessionCourseStatus,
3894
                    array(SESSION_VISIBLE_READ_ONLY, SESSION_VISIBLE, SESSION_AVAILABLE))) {
3895
                    $sessionCourseAvailable = true;
3896
                }
3897
3898
                if ($user_in_course_status == COURSEMANAGER || $sessionCourseAvailable) {
3899
                    $session_url = $course_info['course_public_url'] . '?id_session=' . $course_info['id_session'];
3900
                    $session_title = '<h4><a href="' . $session_url. '">'. $course_info['name'] . '</a>'.$notifications.'</h4>';
3901
                } else {
3902
                    $session_title = $course_info['name'];
3903
                }
3904
3905
            } else {
3906
                $session_title = $course_info['name'] . ' ' . Display::tag('span', get_lang('CourseClosed'),
3907
                        array('class' => 'item_closed'));
3908
            }
3909
        } else {
3910
            $session_title = $course_info['name'];
3911
        }
3912
3913
        $showCustomIcon = api_get_setting('course_images_in_courses_list');
3914
        $iconName = basename($course_info['course_image']);
3915 View Code Duplication
        if ($showCustomIcon === 'true' && $iconName != 'course.png') {
3916
            $params['icon'] = Display::img(
3917
                $course_info['course_image'],
3918
                api_htmlentities($course_info['name']),
3919
                array()
3920
            );
3921
        }
3922
3923
        $params['link'] = $session_url;
3924
        $params['title'] = $session_title;
3925
        $params['right_actions'] = '';
3926
3927
        if ($course_visibility != COURSE_VISIBILITY_CLOSED &&
3928
            $course_visibility != COURSE_VISIBILITY_HIDDEN
3929
        ) {
3930
            if ($load_dirs) {
3931
                $params['right_actions'] .= '<a id="document_preview_' . $course_info['real_id'] . '_' . $course_info['id_session'] . '" class="document_preview" href="javascript:void(0);">' .
3932
                    Display::return_icon('folder.png',
3933
                        get_lang('Documents'),
3934
                        array('align' => 'absmiddle'),
3935
                        ICON_SIZE_SMALL
3936
                    ) . '</a>';
3937
                $params['right_actions'] .= Display::div('', array(
3938
                    'id' => 'document_result_' . $course_info['real_id'] . '_' . $course_info['id_session'],
3939
                    'class' => 'document_preview_container'
3940
                ));
3941
            }
3942
        }
3943
3944
        if (api_get_setting('display_coursecode_in_courselist') == 'true') {
3945
            $session_title .= ' (' . $course_info['visual_code'] . ') ';
3946
        }
3947
3948
        if (api_get_setting('display_teacher_in_courselist') == 'true') {
3949
3950
            $teacher_list = CourseManager::get_teacher_list_from_course_code_to_string(
3951
                $course_info['code'],
3952
                self::USER_SEPARATOR,
3953
                true
3954
            );
3955
            $course_coachs = self::get_coachs_from_course(
3956
                $course_info['id_session'],
3957
                $course_info['real_id']
3958
            );
3959
3960 View Code Duplication
            if ($course_info['status'] == COURSEMANAGER ||
3961
                ($course_info['status'] == STUDENT && empty($course_info['id_session'])) ||
3962
                empty($course_info['status'])
3963
            ) {
3964
                $params['teachers'] = $teacher_list;
3965
            }
3966
3967 View Code Duplication
            if (($course_info['status'] == STUDENT && !empty($course_info['id_session'])) ||
3968
                ($is_coach && $course_info['status'] != COURSEMANAGER)
3969
            ) {
3970
                $params['coaches'] = $course_coachs;
3971
            }
3972
        }
3973
3974
        $session_title .= isset($course['special_course']) ? ' ' .
3975
                          Display::return_icon('klipper.png', get_lang('CourseAutoRegister')) : '';
3976
3977
        $params['title'] = $session_title;
3978
        $params['extra'] = '';
3979
3980
        $html = $params;
3981
3982
        $session_category_id = null;
3983
        if (1) {
3984
            $session = '';
3985
            $active = false;
3986
            if (!empty($course_info['session_name'])) {
3987
3988
                // Request for the name of the general coach
3989
                $sql = 'SELECT lastname, firstname,sc.name
3990
                        FROM ' . $tbl_session . ' ts
3991
                        LEFT JOIN ' . $main_user_table . ' tu
3992
                        ON ts.id_coach = tu.user_id
3993
                        INNER JOIN ' . $tbl_session_category . ' sc
3994
                        ON ts.session_category_id = sc.id
3995
                        WHERE ts.id=' . (int)$course_info['id_session'] . '
3996
                        LIMIT 1';
3997
3998
                $rs = Database::query($sql);
3999
                $sessioncoach = Database::store_result($rs);
4000
                $sessioncoach = $sessioncoach[0];
4001
4002
                $session = array();
4003
                $session['title'] = $course_info['session_name'];
4004
                $session_category_id = CourseManager::get_session_category_id_by_session_id($course_info['id_session']);
4005
                $session['category'] = $sessioncoach['name'];
4006
                if ($course_info['access_start_date'] == '0000-00-00') {
4007
                    //$session['dates'] = get_lang('WithoutTimeLimits');
4008
                    $session['dates'] = '';
4009 View Code Duplication
                    if (api_get_setting('show_session_coach') === 'true') {
4010
                        $session['coach'] = get_lang('GeneralCoach') . ': ' . api_get_person_name($sessioncoach['firstname'],
4011
                                $sessioncoach['lastname']);
4012
                    }
4013
                    $active = true;
4014
                } else {
4015
                    $session ['dates'] = ' - ' . get_lang('From') . ' ' . $course_info['access_start_date'] . ' ' . get_lang('To') . ' ' . $course_info['access_end_date'];
4016 View Code Duplication
                    if (api_get_setting('show_session_coach') === 'true') {
4017
                        $session['coach'] = get_lang('GeneralCoach') . ': ' . api_get_person_name($sessioncoach['firstname'],
4018
                                $sessioncoach['lastname']);
4019
                    }
4020
                    $active = ($date_start <= $now && $date_end >= $now);
0 ignored issues
show
Bug introduced by
The variable $date_start does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Bug introduced by
The variable $date_end does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
4021
                }
4022
            }
4023
            $user_course_category = '';
4024
            if (isset($course_info['user_course_cat'])) {
4025
                $user_course_category = $course_info['user_course_cat'];
4026
            }
4027
            $output = array(
4028
                $user_course_category,
4029
                $html,
4030
                $course_info['id_session'],
4031
                $session,
4032
                'active' => $active,
4033
                'session_category_id' => $session_category_id
4034
            );
4035
4036
            if (api_get_setting('allow_skills_tool') === 'true') {
4037
                $skill = $entityManager
4038
                    ->getRepository('ChamiloCoreBundle:Skill')
4039
                    ->getLastByUser($objUser, $objCourse, $objSession);
4040
4041
                $output['skill'] = null;
4042
4043
                if ($skill) {
4044
                    $output['skill']['name'] = $skill->getName();
4045
                    $output['skill']['icon'] = $skill->getIcon();
4046
                }
4047
            }
4048
        } else {
4049
            $output = array($course_info['user_course_cat'], $html);
4050
        }
4051
        return $output;
4052
    }
4053
4054
    /**
4055
     *
4056
     * @param    string    source course code
4057
     * @param     int        source session id
4058
     * @param    string    destination course code
4059
     * @param     int        destination session id
4060
     * @return  bool
4061
     */
4062
    public static function copy_course(
4063
        $source_course_code,
4064
        $source_session_id,
4065
        $destination_course_code,
4066
        $destination_session_id,
4067
        $params = array()
4068
    ) {
4069
        require_once api_get_path(SYS_CODE_PATH) . 'coursecopy/classes/CourseBuilder.class.php';
4070
        require_once api_get_path(SYS_CODE_PATH) . 'coursecopy/classes/CourseRestorer.class.php';
4071
        require_once api_get_path(SYS_CODE_PATH) . 'coursecopy/classes/CourseSelectForm.class.php';
4072
4073
        $course_info = api_get_course_info($source_course_code);
4074
4075
        if (!empty($course_info)) {
4076
            $cb = new CourseBuilder('', $course_info);
4077
            $course = $cb->build($source_session_id, $source_course_code, true);
4078
            $course_restorer = new CourseRestorer($course);
4079
            $course_restorer->skip_content = $params;
4080
            $course_restorer->restore($destination_course_code, $destination_session_id, true, true);
4081
            return true;
4082
        }
4083
        return false;
4084
    }
4085
4086
    /**
4087
     * A simpler version of the copy_course, the function creates an empty course with an autogenerated course code
4088
     *
4089
     * @param    string    new course title
4090
     * @param    string    source course code
4091
     * @param     int        source session id
4092
     * @param     int        destination session id
4093
     * @param    bool    new copied tools (Exercises and LPs)will be set to invisible by default?
4094
     *
4095
     * @return     array
4096
     */
4097
    public static function copy_course_simple(
4098
        $new_title,
4099
        $source_course_code,
4100
        $source_session_id = 0,
4101
        $destination_session_id = 0,
4102
        $params = array()
4103
    ) {
4104
        $source_course_info = api_get_course_info($source_course_code);
4105
        if (!empty($source_course_info)) {
4106
            $new_course_code = self::generate_nice_next_course_code($source_course_code);
4107
            if ($new_course_code) {
4108
                $new_course_info = self::create_course($new_title, $new_course_code, false);
4109
                if (!empty($new_course_info['code'])) {
4110
                    $result = self::copy_course($source_course_code, $source_session_id, $new_course_info['code'],
4111
                        $destination_session_id, $params);
4112
                    if ($result) {
4113
                        return $new_course_info;
4114
                    }
4115
                }
4116
            }
4117
        }
4118
4119
        return false;
4120
    }
4121
4122
    /**
4123
     * Creates a new course code based in a given code
4124
     *
4125
     * @param string    wanted code
4126
     * <code>    $wanted_code = 'curse' if there are in the DB codes like curse1 curse2 the function will return: course3</code>
4127
     * if the course code doest not exist in the DB the same course code will be returned
4128
     * @return string    wanted unused code
4129
     */
4130 View Code Duplication
    public static function generate_nice_next_course_code($wanted_code)
4131
    {
4132
        $course_code_ok = !self::course_code_exists($wanted_code);
4133
        if (!$course_code_ok) {
4134
            $wanted_code = CourseManager::generate_course_code($wanted_code);
4135
            $table = Database::get_main_table(TABLE_MAIN_COURSE);
4136
            $wanted_code = Database::escape_string($wanted_code);
4137
            $sql = "SELECT count(*) as count
4138
                    FROM $table
4139
                    WHERE code LIKE '$wanted_code%'";
4140
            $result = Database::query($sql);
4141
            if (Database::num_rows($result) > 0) {
4142
                $row = Database::fetch_array($result);
4143
                $count = $row['count'] + 1;
4144
                $wanted_code = $wanted_code . '_' . $count;
4145
                $result = api_get_course_info($wanted_code);
4146
                if (empty($result)) {
4147
                    return $wanted_code;
4148
                }
4149
            }
4150
4151
            return false;
4152
        }
4153
4154
        return $wanted_code;
4155
    }
4156
4157
    /**
4158
     * Gets the status of the users agreement in a course course-session
4159
     *
4160
     * @param int $user_id
4161
     * @param string $course_code
4162
     * @param int $session_id
4163
     * @return boolean
4164
     */
4165
    public static function is_user_accepted_legal($user_id, $course_code, $session_id = null)
4166
    {
4167
        $user_id = intval($user_id);
4168
        $course_code = Database::escape_string($course_code);
4169
        $session_id = intval($session_id);
4170
4171
        $courseInfo = api_get_course_info($course_code);
4172
        $courseId = $courseInfo['real_id'];
4173
4174
        // Course legal
4175
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4176
4177 View Code Duplication
        if ($enabled == 'true') {
4178
            require_once api_get_path(SYS_PLUGIN_PATH) . 'courselegal/config.php';
4179
            $plugin = CourseLegalPlugin::create();
4180
            return $plugin->isUserAcceptedLegal($user_id, $course_code, $session_id);
4181
        }
4182
4183
        if (empty($session_id)) {
4184
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4185
            $sql = "SELECT legal_agreement FROM $table
4186
                    WHERE user_id = $user_id AND c_id = $courseId ";
4187
            $result = Database::query($sql);
4188
            if (Database::num_rows($result) > 0) {
4189
                $result = Database::fetch_array($result);
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
4190
                if ($result['legal_agreement'] == 1) {
4191
                    return true;
4192
                }
4193
            }
4194
            return false;
4195
        } else {
4196
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4197
            $sql = "SELECT legal_agreement FROM $table
4198
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4199
            $result = Database::query($sql);
4200
            if (Database::num_rows($result) > 0) {
4201
                $result = Database::fetch_array($result);
0 ignored issues
show
Bug introduced by
It seems like $result can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
4202
                if ($result['legal_agreement'] == 1) {
4203
                    return true;
4204
                }
4205
            }
4206
            return false;
4207
        }
4208
    }
4209
4210
    /**
4211
     * Saves the user-course legal agreement
4212
     * @param   int user id
4213
     * @param   string course code
4214
     * @param   int session id
4215
     * @return mixed
4216
     */
4217
    public static function save_user_legal($user_id, $course_code, $session_id = null)
4218
    {
4219
        // Course plugin legal
4220
        $enabled = api_get_plugin_setting('courselegal', 'tool_enable');
4221
4222 View Code Duplication
        if ($enabled == 'true') {
4223
            require_once api_get_path(SYS_PLUGIN_PATH) . 'courselegal/config.php';
4224
            $plugin = CourseLegalPlugin::create();
4225
            return $plugin->saveUserLegal($user_id, $course_code, $session_id);
4226
        }
4227
4228
        $user_id = intval($user_id);
4229
        $course_code = Database::escape_string($course_code);
4230
        $session_id = intval($session_id);
4231
4232
        $courseInfo = api_get_course_info($course_code);
4233
        $courseId = $courseInfo['real_id'];
4234
4235 View Code Duplication
        if (empty($session_id)) {
4236
            $table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4237
            $sql = "UPDATE $table SET legal_agreement = '1'
4238
                    WHERE user_id = $user_id AND c_id  = $courseId ";
4239
            Database::query($sql);
4240
        } else {
4241
            $table = Database::get_main_table(TABLE_MAIN_SESSION_COURSE_USER);
4242
            $sql = "UPDATE  $table SET legal_agreement = '1'
4243
                    WHERE user_id = $user_id AND c_id = $courseId AND session_id = $session_id";
4244
            Database::query($sql);
4245
        }
4246
    }
4247
4248
    /**
4249
     * @param int $user_id
4250
     * @param int $course_id
4251
     * @param int $session_id
4252
     * @param int $url_id
4253
     * @return bool
4254
     */
4255
    public static function get_user_course_vote($user_id, $course_id, $session_id = null, $url_id = null)
4256
    {
4257
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4258
4259
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4260
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4261
        $user_id = intval($user_id);
4262
4263
        if (empty($user_id)) {
4264
            return false;
4265
        }
4266
4267
        $params = array(
4268
            'user_id' => $user_id,
4269
            'c_id' => $course_id,
4270
            'session_id' => $session_id,
4271
            'url_id' => $url_id
4272
        );
4273
4274
        $result = Database::select(
4275
            'vote',
4276
            $table_user_course_vote,
4277
            array(
4278
                'where' => array(
4279
                    'user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params
4280
                )
4281
            ),
4282
            'first'
4283
        );
4284
        if (!empty($result)) {
4285
            return $result['vote'];
4286
        }
4287
        return false;
4288
    }
4289
4290
    /**
4291
     * @param int $course_id
4292
     * @param int $session_id
4293
     * @param int $url_id
4294
     * @return array
4295
     */
4296
    public static function get_course_ranking($course_id, $session_id = null, $url_id = null)
4297
    {
4298
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4299
4300
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4301
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4302
        $now = api_get_utc_datetime();
4303
4304
        $params = array(
4305
            'c_id' => $course_id,
4306
            'session_id' => $session_id,
4307
            'url_id' => $url_id,
4308
            'creation_date' => $now,
4309
        );
4310
4311
        $result = Database::select(
4312
            'c_id, accesses, total_score, users',
4313
            $table_course_ranking,
4314
            array('where' => array('c_id = ? AND session_id = ? AND url_id = ?' => $params)),
4315
            'first'
4316
        );
4317
4318
        $point_average_in_percentage = 0;
4319
        $point_average_in_star = 0;
4320
        $users_who_voted = 0;
4321
4322
        if (!empty($result['users'])) {
4323
            $users_who_voted = $result['users'];
4324
            $point_average_in_percentage = round($result['total_score'] / $result['users'] * 100 / 5, 2);
4325
            $point_average_in_star = round($result['total_score'] / $result['users'], 1);
4326
        }
4327
4328
        $result['user_vote'] = false;
4329
4330
        if (!api_is_anonymous()) {
4331
            $result['user_vote'] = self::get_user_course_vote(api_get_user_id(), $course_id, $session_id, $url_id);
4332
        }
4333
4334
        $result['point_average'] = $point_average_in_percentage;
4335
        $result['point_average_star'] = $point_average_in_star;
4336
        $result['users_who_voted'] = $users_who_voted;
4337
4338
        return $result;
4339
    }
4340
4341
    /**
4342
     *
4343
     * Updates the course ranking
4344
     * @param int   course id
4345
     * @param int   session id
4346
     * @param id    url id
4347
     * @return array
4348
     **/
4349
    public static function update_course_ranking(
4350
        $course_id = null,
4351
        $session_id = null,
4352
        $url_id = null,
4353
        $points_to_add = null,
4354
        $add_access = true,
4355
        $add_user = true
4356
    ) {
4357
        // Course catalog stats modifications see #4191
4358
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4359
4360
        $now = api_get_utc_datetime();
4361
4362
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4363
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4364
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4365
4366
        $params = array(
4367
            'c_id' => $course_id,
4368
            'session_id' => $session_id,
4369
            'url_id' => $url_id,
4370
            'creation_date' => $now,
4371
            'total_score' => 0,
4372
            'users' => 0
4373
        );
4374
4375
        $result = Database::select(
4376
            'id, accesses, total_score, users',
4377
            $table_course_ranking,
4378
            array('where' => array('c_id = ? AND session_id = ? AND url_id = ?' => $params)),
4379
            'first'
4380
        );
4381
4382
        // Problem here every time we load the courses/XXXX/index.php course home page we update the access
4383
4384
        if (empty($result)) {
4385
            if ($add_access) {
4386
                $params['accesses'] = 1;
4387
            }
4388
            //The votes and users are empty
4389
            if (isset($points_to_add) && !empty($points_to_add)) {
4390
                $params['total_score'] = intval($points_to_add);
4391
            }
4392
            if ($add_user) {
4393
                $params['users'] = 1;
4394
            }
4395
            $result = Database::insert($table_course_ranking, $params);
4396
        } else {
4397
            $my_params = array();
4398
4399
            if ($add_access) {
4400
                $my_params['accesses'] = intval($result['accesses']) + 1;
4401
            }
4402
            if (isset($points_to_add) && !empty($points_to_add)) {
4403
                $my_params['total_score'] = $result['total_score'] + $points_to_add;
4404
            }
4405
            if ($add_user) {
4406
                $my_params['users'] = $result['users'] + 1;
4407
            }
4408
4409
            if (!empty($my_params)) {
4410
                $result = Database::update(
4411
                    $table_course_ranking,
4412
                    $my_params,
4413
                    array('c_id = ? AND session_id = ? AND url_id = ?' => $params)
4414
                );
4415
            }
4416
        }
4417
4418
        return $result;
4419
    }
4420
4421
    /**
4422
     * Add user vote to a course
4423
     *
4424
     * @param   int user id
4425
     * @param   int vote [1..5]
4426
     * @param   int course id
4427
     * @param   int session id
4428
     * @param   int url id (access_url_id)
4429
     * @return    mixed 'added', 'updated' or 'nothing'
4430
     */
4431
    public static function add_course_vote($user_id, $vote, $course_id, $session_id = null, $url_id = null)
4432
    {
4433
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4434
        $course_id = empty($course_id) ? api_get_course_int_id() : intval($course_id);
4435
4436
        if (empty($course_id) || empty($user_id)) {
4437
            return false;
4438
        }
4439
4440
        if (!in_array($vote, array(1, 2, 3, 4, 5))) {
4441
            return false;
4442
        }
4443
4444
        $session_id = !isset($session_id) ? api_get_session_id() : intval($session_id);
4445
        $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4446
        $vote = intval($vote);
4447
4448
        $params = array(
4449
            'user_id' => intval($user_id),
4450
            'c_id' => $course_id,
4451
            'session_id' => $session_id,
4452
            'url_id' => $url_id,
4453
            'vote' => $vote
4454
        );
4455
4456
        $action_done = 'nothing';
4457
4458
        $result = Database::select(
4459
            'id, vote',
4460
            $table_user_course_vote,
4461
            array('where' => array('user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params)),
4462
            'first'
4463
        );
4464
4465
        if (empty($result)) {
4466
            Database::insert($table_user_course_vote, $params);
4467
            $points_to_add = $vote;
4468
            $add_user = true;
4469
            $action_done = 'added';
4470
        } else {
4471
            $my_params = array('vote' => $vote);
4472
            $points_to_add = $vote - $result['vote'];
4473
            $add_user = false;
4474
4475
            Database::update(
4476
                $table_user_course_vote,
4477
                $my_params,
4478
                array('user_id = ? AND c_id = ? AND session_id = ? AND url_id = ?' => $params)
4479
            );
4480
            $action_done = 'updated';
4481
        }
4482
4483
        // Current points
4484
        if (!empty($points_to_add)) {
4485
            self::update_course_ranking(
4486
                $course_id,
4487
                $session_id,
4488
                $url_id,
4489
                $points_to_add,
4490
                false,
4491
                $add_user
4492
            );
4493
        }
4494
        return $action_done;
4495
    }
4496
4497
    /**
4498
     * Remove course ranking + user votes
4499
     *
4500
     * @param int $course_id
4501
     * @param int $session_id
4502
     * @param int $url_id
4503
     *
4504
     */
4505
    public static function remove_course_ranking($course_id, $session_id, $url_id = null)
4506
    {
4507
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4508
        $table_user_course_vote = Database::get_main_table(TABLE_MAIN_USER_REL_COURSE_VOTE);
4509
4510
        if (!empty($course_id) && isset($session_id)) {
4511
            $url_id = empty($url_id) ? api_get_current_access_url_id() : intval($url_id);
4512
            $params = array(
4513
                'c_id' => $course_id,
4514
                'session_id' => $session_id,
4515
                'url_id' => $url_id,
4516
            );
4517
            Database::delete($table_course_ranking, array('c_id = ? AND session_id = ? AND url_id = ?' => $params));
4518
            Database::delete($table_user_course_vote, array('c_id = ? AND session_id = ? AND url_id = ?' => $params));
4519
        }
4520
    }
4521
4522
    /**
4523
     * Returns an array with the hottest courses
4524
     * @param   int $days number of days
4525
     * @param   int $limit number of hottest courses
4526
     * @return array
4527
     */
4528
    public static function return_hot_courses($days = 30, $limit = 5)
4529
    {
4530
        if (api_is_invitee()) {
4531
            return array();
4532
        }
4533
4534
        $limit = intval($limit);
4535
4536
        // Getting my courses
4537
        $my_course_list = CourseManager::get_courses_list_by_user_id(api_get_user_id());
4538
4539
        $my_course_code_list = array();
4540
        foreach ($my_course_list as $course) {
4541
            $my_course_code_list[$course['real_id']] = $course['real_id'];
4542
        }
4543
4544
        if (api_is_drh()) {
4545
            $courses = CourseManager::get_courses_followed_by_drh(api_get_user_id());
4546
            foreach ($courses as $course) {
4547
                $my_course_code_list[$course['real_id']] = $course['real_id'];
4548
            }
4549
        }
4550
4551
        $table_course_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
4552
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4553
        $table_course_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4554
4555
        //$table_course_access table uses the now() and interval ...
4556
        $now = api_get_utc_datetime(time());
4557
        $sql = "SELECT COUNT(course_access_id) course_count, a.c_id, visibility
4558
                FROM $table_course c
4559
                INNER JOIN $table_course_access a
4560
                ON (c.id = a.c_id)
4561
                INNER JOIN $table_course_url u
4562
                ON u.c_id = c.id
4563
                WHERE
4564
                    u.access_url_id = " . api_get_current_access_url_id() . " AND
4565
                    login_course_date <= '$now' AND
4566
                    login_course_date > DATE_SUB('$now', INTERVAL $days DAY) AND
4567
                    visibility <> '" . COURSE_VISIBILITY_CLOSED . "' AND visibility <> '" . COURSE_VISIBILITY_HIDDEN . "'
4568
                GROUP BY a.c_id
4569
                ORDER BY course_count DESC
4570
                LIMIT $limit
4571
            ";
4572
4573
        $result = Database::query($sql);
4574
        $courses = array();
4575
4576
        if (Database::num_rows($result)) {
4577
            $courses = Database::store_result($result, 'ASSOC');
4578
            $courses = self::process_hot_course_item($courses, $my_course_code_list);
4579
        }
4580
4581
        return $courses;
4582
    }
4583
4584
    /**
4585
     * @param array $courses
4586
     * @param array $my_course_code_list
4587
     * @return mixed
4588
     */
4589
    public static function process_hot_course_item($courses, $my_course_code_list = array())
4590
    {
4591
        $hotCourses = [];
4592
4593
        $ajax_url = api_get_path(WEB_AJAX_PATH) . 'course.ajax.php?a=add_course_vote';
4594
4595
        $stok = Security::get_existing_token();
4596
4597
        foreach ($courses as $courseId) {
4598
            $course_info = api_get_course_info_by_id($courseId['c_id']);
4599
            $courseCode = $course_info['code'];
4600
            $categoryCode = !empty($course_info['categoryCode']) ? $course_info['categoryCode'] : "";
4601
            $my_course['extra_info'] = $course_info;
4602
            $my_course['extra_info']['go_to_course_button'] = '';
4603
            $my_course['extra_info']['register_button'] = '';
4604
4605
            $access_link = self::get_access_link_by_user(
4606
                api_get_user_id(),
4607
                $course_info,
4608
                $my_course_code_list
4609
            );
4610
4611
            //Course visibility
4612 View Code Duplication
            if ($access_link && in_array('register', $access_link)) {
4613
                $my_course['extra_info']['register_button'] = Display::url(
4614
                    Display::returnFontAwesomeIcon('sign-in'),
4615
                    api_get_path(WEB_COURSE_PATH) . $course_info['path'] . '/index.php?action=subscribe&sec_token=' . $stok,
4616
                    array('class' => 'btn btn-success btn-sm', 'title' => get_lang('Subscribe')));
4617
            }
4618
4619 View Code Duplication
            if ($access_link && in_array('enter',
4620
                    $access_link) || $course_info['visibility'] == COURSE_VISIBILITY_OPEN_WORLD
4621
            ) {
4622
                $my_course['extra_info']['go_to_course_button'] = Display::url(
4623
                    Display::returnFontAwesomeIcon('share'),
4624
                    api_get_path(WEB_COURSE_PATH) . $course_info['path'] . '/index.php',
4625
                    array('class' => 'btn btn-default btn-sm', 'title' => get_lang('GoToCourse')));
4626
            }
4627
4628
            if ($access_link && in_array('unsubscribe', $access_link)) {
4629
                $my_course['extra_info']['unsubscribe_button'] = Display::url(
4630
                    Display::returnFontAwesomeIcon('sign-out'),
4631
                    api_get_path(WEB_CODE_PATH) . 'auth/courses.php?action=unsubscribe&unsubscribe=' . $courseCode . '&sec_token=' . $stok . '&category_code=' . $categoryCode,
4632
                    array('class' => 'btn btn-danger btn-sm', 'title' => get_lang('Unreg')));
4633
            }
4634
4635
            //Description
4636
            $my_course['extra_info']['description_button'] = '';
4637
            /* if ($course_info['visibility'] == COURSE_VISIBILITY_OPEN_WORLD || in_array($course_info['real_id'],
4638
                    $my_course_code_list)
4639
            ) { */
4640
                $my_course['extra_info']['description_button'] = Display::url(
4641
                    Display::returnFontAwesomeIcon('info-circle'),
4642
                    api_get_path(WEB_AJAX_PATH) . 'course_home.ajax.php?a=show_course_information&code=' . $course_info['code'],
4643
                    [
4644
                        'class' => 'btn btn-default btn-sm ajax',
4645
                        'data-title' => get_lang('Description'),
4646
                        'title' => get_lang('Description')
4647
                    ]
4648
                );
4649
            //}
4650
            /* get_lang('Description') */
4651
            $my_course['extra_info']['teachers'] = CourseManager::get_teacher_list_from_course_code_to_string($course_info['code']);
4652
            $point_info = self::get_course_ranking($course_info['real_id'], 0);
4653
            $my_course['extra_info']['rating_html'] = Display::return_rating_system('star_' . $course_info['real_id'],
4654
                $ajax_url . '&course_id=' . $course_info['real_id'], $point_info);
4655
            
4656
            $plugin = BuyCoursesPlugin::create();
4657
            $includeServices = $plugin->get('include_services') === 'true';
4658
            $serviceNode = null;
4659
            if ($includeServices) {
4660
                $serviceNode = $plugin->CheckServiceSubscribed(BuyCoursesPlugin::SERVICE_TYPE_COURSE, $course_info['real_id']);
4661
            }
4662
            
4663
            $my_course['extra_info']['services'] = $serviceNode ? $serviceNode : false;
4664
            $my_course['extra_info']['services_enable'] = $includeServices ? true : false;
4665
4666
            $hotCourses[] = $my_course;
4667
        }
4668
        return $hotCourses;
4669
    }
4670
4671
    /**
4672
     * @param int $limit
4673
     * @return array
4674
     */
4675
    public static function return_most_accessed_courses($limit = 5)
4676
    {
4677
        $table_course_ranking = Database::get_main_table(TABLE_STATISTIC_TRACK_COURSE_RANKING);
4678
        $params['url_id'] = api_get_current_access_url_id();
4679
4680
        $result = Database::select(
4681
            'c_id, accesses, total_score, users',
4682
            $table_course_ranking,
4683
            array('where' => array('url_id = ?' => $params), 'order' => 'accesses DESC', 'limit' => $limit),
4684
            'all',
4685
            true
4686
        );
4687
        return $result;
4688
    }
4689
4690
    /**
4691
     * Get courses count
4692
     * @param int Access URL ID (optional)
4693
     * @param int $visibility
4694
     *
4695
     * @return int Number of courses
4696
     */
4697
    public static function count_courses($access_url_id = null, $visibility = null)
4698
    {
4699
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4700
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4701
        $sql = "SELECT count(id) FROM $table_course c";
4702
        if (!empty($access_url_id) && $access_url_id == intval($access_url_id)) {
4703
            $sql .= ", $table_course_rel_access_url u
4704
                    WHERE c.id = u.c_id AND u.access_url_id = $access_url_id";
4705
            if (!empty($visibility)) {
4706
                $visibility = intval($visibility);
4707
                $sql .= " AND visibility = $visibility ";
4708
            }
4709
        } else {
4710
            if (!empty($visibility)) {
4711
                $visibility = intval($visibility);
4712
                $sql .= " WHERE visibility = $visibility ";
4713
            }
4714
        }
4715
4716
        $res = Database::query($sql);
4717
        $row = Database::fetch_row($res);
4718
        return $row[0];
4719
    }
4720
4721
    /**
4722
     * Get active courses count.
4723
     * Active = all courses except the ones with hidden visibility.
4724
     *
4725
     * @param int $urlId Access URL ID (optional)
4726
     * @return int Number of courses
4727
     */
4728
    public static function countActiveCourses($urlId = null)
4729
    {
4730
        $table_course = Database::get_main_table(TABLE_MAIN_COURSE);
4731
        $table_course_rel_access_url = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4732
        $sql = "SELECT count(id) FROM $table_course c";
4733
        if (!empty($urlId) && $urlId == intval($urlId)) {
4734
            $sql .= ", $table_course_rel_access_url u
4735
                    WHERE
4736
                        c.id = u.c_id AND
4737
                        u.access_url_id = $urlId AND
4738
                        visibility <> " . COURSE_VISIBILITY_HIDDEN;
4739
        } else {
4740
            $sql .= " WHERE visibility <> " . COURSE_VISIBILITY_HIDDEN;
4741
        }
4742
        $res = Database::query($sql);
4743
        $row = Database::fetch_row($res);
4744
        return $row[0];
4745
    }
4746
4747
    /**
4748
     * Get available le courses count
4749
     * @param int Access URL ID (optional)
4750
     * @return int Number of courses
4751
     */
4752
    public static function countAvailableCourses($accessUrlId = null)
4753
    {
4754
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
4755
        $tableCourseRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
4756
        $specialCourseList = self::get_special_course_list();
4757
4758
        $withoutSpecialCourses = '';
4759
        if (!empty($specialCourseList)) {
4760
            $withoutSpecialCourses = ' AND c.code NOT IN ("' . implode('","', $specialCourseList) . '")';
4761
        }
4762
4763
        $visibilityCondition = null;
4764
4765
        $hidePrivate = api_get_setting('course_catalog_hide_private');
4766 View Code Duplication
        if ($hidePrivate === 'true') {
4767
            $courseInfo = api_get_course_info();
4768
            $courseVisibility = $courseInfo['visibility'];
4769
            $visibilityCondition = ' AND c.visibility <> 1';
4770
        }
4771
        if (!empty($accessUrlId) && $accessUrlId == intval($accessUrlId)) {
4772
            $sql = "SELECT count(c.id) FROM $tableCourse c, $tableCourseRelAccessUrl u
4773
                    WHERE
4774
                        c.id = u.c_id AND
4775
                        u.access_url_id = $accessUrlId AND
4776
                        c.visibility != 0 AND
4777
                        c.visibility != 4
4778
                        $withoutSpecialCourses
4779
                        $visibilityCondition
4780
                    ";
4781
        }
4782
        $res = Database::query($sql);
4783
        $row = Database::fetch_row($res);
4784
4785
        return $row[0];
4786
    }
4787
4788
    /**
4789
     * Return a link to go to the course, validating the visibility of the
4790
     * course and the user status
4791
     * @param int User ID
4792
     * @param array Course details array
4793
     * @param array  List of courses to which the user is subscribed (if not provided, will be generated)
4794
     * @return mixed 'enter' for a link to go to the course or 'register' for a link to subscribe, or false if no access
4795
     */
4796
    static function get_access_link_by_user($uid, $course, $user_courses = array())
4797
    {
4798
        if (empty($uid) or empty($course)) {
4799
            return false;
4800
        }
4801
4802
        if (empty($user_courses)) {
4803
            // get the array of courses to which the user is subscribed
4804
            $user_courses = CourseManager::get_courses_list_by_user_id($uid);
4805
            foreach ($user_courses as $k => $v) {
4806
                $user_courses[$k] = $v['real_id'];
4807
            }
4808
        }
4809
4810
        if (!isset($course['real_id']) && empty($course['real_id'])) {
4811
            $course = api_get_course_info($course['code']);
4812
        }
4813
4814
        if ($course['visibility'] == COURSE_VISIBILITY_HIDDEN) {
4815
            return array();
4816
        }
4817
4818
        $is_admin = api_is_platform_admin_by_id($uid);
4819
        $options = array();
4820
        // Register button
4821
        if (!api_is_anonymous($uid) &&
4822
            (
4823
            ($course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD || $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM)
4824
                //$course['visibility'] == COURSE_VISIBILITY_REGISTERED && $course['subscribe'] == SUBSCRIBE_ALLOWED
4825
            ) &&
4826
            $course['subscribe'] == SUBSCRIBE_ALLOWED &&
4827
            (!in_array($course['real_id'], $user_courses) || empty($user_courses))
4828
        ) {
4829
            $options[] = 'register';
4830
        }
4831
4832
        // Go To Course button (only if admin, if course public or if student already subscribed)
4833 View Code Duplication
        if ($is_admin ||
4834
            $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD && empty($course['registration_code']) ||
4835
            (api_user_is_login($uid) && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM && empty($course['registration_code'])) ||
4836
            (in_array($course['real_id'], $user_courses) && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
4837
        ) {
4838
            $options[] = 'enter';
4839
        }
4840
4841 View Code Duplication
        if ($is_admin ||
4842
            $course['visibility'] == COURSE_VISIBILITY_OPEN_WORLD && empty($course['registration_code']) ||
4843
            (api_user_is_login($uid) && $course['visibility'] == COURSE_VISIBILITY_OPEN_PLATFORM && empty($course['registration_code'])) ||
4844
            (in_array($course['real_id'], $user_courses) && $course['visibility'] != COURSE_VISIBILITY_CLOSED)
4845
        ) {
4846
            $options[] = 'enter';
4847
        }
4848
4849
        if ($course['visibility'] != COURSE_VISIBILITY_HIDDEN && empty($course['registration_code']) && $course['unsubscribe'] == UNSUBSCRIBE_ALLOWED && api_user_is_login($uid) && (in_array($course['real_id'],
4850
                $user_courses))
4851
        ) {
4852
            $options[] = 'unsubscribe';
4853
        }
4854
4855
        return $options;
4856
    }
4857
4858
    /**
4859
     * @param int $courseId
4860
     * @param array $teachers
4861
     * @param bool $deleteTeachersNotInList
4862
     * @param bool $editTeacherInSessions
4863
     * @param bool $deleteSessionTeacherNotInList
4864
     * @return bool
4865
     */
4866
    public static function updateTeachers(
4867
        $courseId,
4868
        $teachers,
4869
        $deleteTeachersNotInList = true,
4870
        $editTeacherInSessions = false,
4871
        $deleteSessionTeacherNotInList = false,
4872
        $teacherBackup = array()
4873
    ) {
4874
        if (empty($teachers)) {
4875
            return false;
4876
        }
4877
        if (!is_array($teachers)) {
4878
            $teachers = array($teachers);
4879
        }
4880
        $courseId = intval($courseId);
4881
        $courseInfo = api_get_course_info_by_id($courseId);
4882
        $course_code = $courseInfo['code'];
4883
4884
        $course_user_table = Database::get_main_table(TABLE_MAIN_COURSE_USER);
4885
        $alreadyAddedTeachers = CourseManager::get_teacher_list_from_course_code($course_code);
4886
4887
        if ($deleteTeachersNotInList) {
4888
4889
            // Delete only teacher relations that doesn't match the selected teachers
4890
            $cond = null;
4891
            if (count($teachers) > 0) {
4892
                foreach ($teachers as $key) {
4893
                    $key = Database::escape_string($key);
4894
                    $cond .= " AND user_id <> '" . $key . "'";
4895
                }
4896
            }
4897
4898
            $sql = 'DELETE FROM ' . $course_user_table . '
4899
                    WHERE c_id ="' . $courseId . '" AND status="1" AND relation_type = 0 ' . $cond;
4900
            Database::query($sql);
4901
        }
4902
4903
        if (count($teachers) > 0) {
4904
            foreach ($teachers as $userId) {
4905
                $userId = intval($userId);
4906
                // We check if the teacher is already subscribed in this course
4907
                $sql = 'SELECT 1 FROM ' . $course_user_table . '
4908
                        WHERE user_id = "' . $userId . '" AND c_id = "' . $courseId . '" ';
4909
                $result = Database::query($sql);
4910
                if (Database::num_rows($result)) {
4911
                    $sql = 'UPDATE ' . $course_user_table . ' SET status = "1"
4912
                            WHERE c_id = "' . $courseId . '" AND user_id = "' . $userId . '"  ';
4913
                } else {
4914
                    $userCourseCategory = '0';
4915 View Code Duplication
                    if (isset($teacherBackup[$userId]) &&
4916
                        isset($teacherBackup[$userId][$course_code])
4917
                    ) {
4918
                        $courseUserData = $teacherBackup[$userId][$course_code];
4919
                        $userCourseCategory = $courseUserData['user_course_cat'];
4920
                    }
4921
4922
                    $sql = "INSERT INTO " . $course_user_table . " SET
4923
                            c_id = " . $courseId . ",
4924
                            user_id = " . $userId . ",
4925
                            status = '1',
4926
                            is_tutor = '0',
4927
                            sort = '0',
4928
                            relation_type = '0',
4929
                            user_course_cat = '$userCourseCategory'
4930
                    ";
4931
                }
4932
                Database::query($sql);
4933
            }
4934
        }
4935
4936
        if ($editTeacherInSessions) {
4937
            $sessions = SessionManager::get_session_by_course($courseId);
4938
4939
            if (!empty($sessions)) {
4940
                foreach ($sessions as $session) {
4941
                    // Remove old and add new
4942
                    if ($deleteSessionTeacherNotInList) {
4943
                        foreach ($teachers as $userId) {
4944
                            SessionManager::set_coach_to_course_session($userId, $session['id'], $courseId);
4945
                        }
4946
4947
                        $teachersToDelete = array();
4948
                        if (!empty($alreadyAddedTeachers)) {
4949
                            $teachersToDelete = array_diff(array_keys($alreadyAddedTeachers), $teachers);
4950
                        }
4951
4952
                        if (!empty($teachersToDelete)) {
4953
                            foreach ($teachersToDelete as $userId) {
4954
                                SessionManager::set_coach_to_course_session($userId, $session['id'], $courseId,
4955
                                    true);
4956
                            }
4957
                        }
4958
                    } else {
4959
                        // Add new teachers only
4960
                        foreach ($teachers as $userId) {
4961
                            SessionManager::set_coach_to_course_session($userId, $session['id'], $courseId);
4962
                        }
4963
                    }
4964
                }
4965
            }
4966
        }
4967
    }
4968
4969
    /**
4970
     * Course available settings variables see c_course_setting table
4971
     * @param AppPlugin $appPlugin
4972
     * @return array
4973
     */
4974
    public static function getCourseSettingVariables(AppPlugin $appPlugin)
4975
    {
4976
        $pluginCourseSettings = $appPlugin->getAllPluginCourseSettings();
4977
        $courseSettings = array(
4978
            // Get allow_learning_path_theme from table
4979
            'allow_learning_path_theme',
4980
            // Get allow_open_chat_window from table
4981
            'allow_open_chat_window',
4982
            'allow_public_certificates',
4983
            // Get allow_user_edit_agenda from table
4984
            'allow_user_edit_agenda',
4985
            // Get allow_user_edit_announcement from table
4986
            'allow_user_edit_announcement',
4987
            // Get allow_user_image_forum from table
4988
            'allow_user_image_forum',
4989
            //Get allow show user list
4990
            'allow_user_view_user_list',
4991
            // Get course_theme from table
4992
            'course_theme',
4993
            //Get allow show user list
4994
            'display_info_advance_inside_homecourse',
4995
            'documents_default_visibility',
4996
            // Get send_mail_setting (work)from table
4997
            'email_alert_manager_on_new_doc',
4998
            // Get send_mail_setting (work)from table
4999
            'email_alert_manager_on_new_quiz',
5000
            // Get send_mail_setting (dropbox) from table
5001
            'email_alert_on_new_doc_dropbox',
5002
            'email_alert_students_on_new_homework',
5003
            // Get send_mail_setting (auth)from table
5004
            'email_alert_to_teacher_on_new_user_in_course',
5005
            'enable_lp_auto_launch',
5006
            'pdf_export_watermark_text',
5007
            'show_system_folders'
5008
        );
5009
5010
        $allowLPReturnLink = api_get_setting('allow_lp_return_link');
5011
        if ($allowLPReturnLink === 'true') {
5012
            $courseSettings[] = 'lp_return_link';
5013
        }
5014
5015
        if (!empty($pluginCourseSettings)) {
5016
            $courseSettings = array_merge(
5017
                $courseSettings,
5018
                $pluginCourseSettings
5019
            );
5020
        }
5021
5022
        return $courseSettings;
5023
    }
5024
5025
    /**
5026
     * @param AppPlugin $appPlugin
5027
     * @param string $variable
5028
     * @param string $value
5029
     * @param int $courseId
5030
     * @return bool
5031
     */
5032
    public static function saveCourseConfigurationSetting(AppPlugin $appPlugin, $variable, $value, $courseId)
5033
    {
5034
        $settingList = self::getCourseSettingVariables($appPlugin);
5035
5036
        if (!in_array($variable, $settingList)) {
5037
            return false;
5038
        }
5039
5040
        $courseSettingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5041
5042
        if (self::hasCourseSetting($variable, $courseId)) {
5043
            // Update
5044
            Database::update(
5045
                $courseSettingTable,
5046
                array('value' => $value),
5047
                array('variable = ? AND c_id = ?' => array($variable, $courseId))
5048
            );
5049
        } else {
5050
            // Create
5051
            Database::insert(
5052
                $courseSettingTable,
5053
                array('value' => $value, 'c_id' => $courseId, 'variable' => $variable)
5054
            );
5055
        }
5056
        return true;
5057
    }
5058
5059
    /**
5060
     * Check if course setting exists
5061
     * @param string $variable
5062
     * @param int $courseId
5063
     * @return bool
5064
     */
5065
    public static function hasCourseSetting($variable, $courseId)
5066
    {
5067
        $courseSetting = Database::get_course_table(TABLE_COURSE_SETTING);
5068
        $courseId = intval($courseId);
5069
        $variable = Database::escape_string($variable);
5070
        $sql = "SELECT variable FROM $courseSetting
5071
                WHERE c_id = $courseId AND variable = '$variable'";
5072
        $result = Database::query($sql);
5073
        return Database::num_rows($result) > 0;
5074
    }
5075
5076
    /**
5077
     * Get information from the track_e_course_access table
5078
     * @param int $sessionId
5079
     * @param int $userId
5080
     * @return array
5081
     */
5082 View Code Duplication
    public static function getCourseAccessPerSessionAndUser($sessionId, $userId, $limit = null)
5083
    {
5084
        $table = Database:: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5085
5086
        $sessionId = intval($sessionId);
5087
        $userId = intval($userId);
5088
5089
        $sql = "SELECT * FROM $table
5090
                WHERE session_id = $sessionId AND user_id = $userId";
5091
5092
        if (!empty($limit)) {
5093
            $limit = intval($limit);
5094
            $sql .= " LIMIT $limit";
5095
        }
5096
        $result = Database::query($sql);
5097
5098
        return Database::store_result($result);
5099
    }
5100
5101
    /**
5102
     * Get information from the track_e_course_access table
5103
     * @param int $courseId
5104
     * @param int $sessionId
5105
     * @param string $startDate
5106
     * @param string $endDate
5107
     * @return array
5108
     */
5109
    public static function getCourseAccessPerCourseAndSession(
5110
        $courseId,
5111
        $sessionId,
5112
        $startDate,
5113
        $endDate
5114
    ) {
5115
        $table = Database:: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5116
        $courseId = intval($courseId);
5117
        $sessionId = intval($sessionId);
5118
        $startDate = Database::escape_string($startDate);
5119
        $endDate = Database::escape_string($endDate);
5120
5121
        $sql = "SELECT * FROM $table
5122
                WHERE
5123
                    c_id = $courseId AND
5124
                    session_id = $sessionId AND
5125
                    login_course_date BETWEEN '$startDate' AND '$endDate'
5126
                ";
5127
5128
        $result = Database::query($sql);
5129
5130
        return Database::store_result($result);
5131
    }
5132
5133
    /**
5134
     * Get login information from the track_e_course_access table, for any
5135
     * course in the given session
5136
     * @param int $sessionId
5137
     * @param int $userId
5138
     * @return array
5139
     */
5140
    public static function getFirstCourseAccessPerSessionAndUser($sessionId, $userId)
5141
    {
5142
        $sessionId = intval($sessionId);
5143
        $userId = intval($userId);
5144
5145
        $table = Database:: get_main_table(TABLE_STATISTIC_TRACK_E_COURSE_ACCESS);
5146
        $sql = "SELECT * FROM $table
5147
                WHERE session_id = $sessionId AND user_id = $userId
5148
                ORDER BY login_course_date ASC
5149
                LIMIT 1";
5150
5151
        $result = Database::query($sql);
5152
        $courseAccess = array();
5153
        if (Database::num_rows($result)) {
5154
            $courseAccess = Database::fetch_array($result, 'ASSOC');
5155
        }
5156
        return $courseAccess;
5157
    }
5158
5159
    /**
5160
     * @param int $courseId
5161
     * @param int $sessionId
5162
     * @param bool $getAllSessions
5163
     * @return mixed
5164
     */
5165
    public static function getCountForum(
5166
        $courseId,
5167
        $sessionId = 0,
5168
        $getAllSessions = false
5169
    ) {
5170
        $forum = Database::get_course_table(TABLE_FORUM);
5171
        if ($getAllSessions) {
5172
            $sql = "SELECT count(*) as count
5173
                    FROM $forum f
5174
                    WHERE f.c_id = %s";
5175
        } else {
5176
            $sql = "SELECT count(*) as count
5177
                    FROM $forum f
5178
                    WHERE f.c_id = %s and f.session_id = %s";
5179
        }
5180
5181
        $sql = sprintf($sql, intval($courseId), intval($sessionId));
5182
        $result = Database::query($sql);
5183
        $row = Database::fetch_array($result);
5184
5185
        return $row['count'];
5186
    }
5187
5188
    /**
5189
     * @param int $userId
5190
     * @param int $courseId
5191
     * @param int $sessionId
5192
     * @return mixed
5193
     */
5194
    public static function getCountPostInForumPerUser(
5195
        $userId,
5196
        $courseId,
5197
        $sessionId = 0
5198
    ) {
5199
        $forum = Database::get_course_table(TABLE_FORUM);
5200
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5201
5202
        $sql = "SELECT count(distinct post_id) as count
5203
                FROM $forum_post p
5204
                INNER JOIN $forum f
5205
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5206
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5207
5208
        $sql = sprintf(
5209
            $sql,
5210
            intval($userId),
5211
            intval($sessionId),
5212
            intval($courseId)
5213
        );
5214
5215
        $result = Database::query($sql);
5216
        $row = Database::fetch_array($result);
5217
        return $row['count'];
5218
    }
5219
5220
    /**
5221
     * @param int $userId
5222
     * @param int $courseId
5223
     * @param int $sessionId
5224
     * @return mixed
5225
     */
5226
    public static function getCountForumPerUser(
5227
        $userId,
5228
        $courseId,
5229
        $sessionId = 0
5230
    ) {
5231
        $forum = Database::get_course_table(TABLE_FORUM);
5232
        $forum_post = Database::get_course_table(TABLE_FORUM_POST);
5233
5234
        $sql = "SELECT count(distinct f.forum_id) as count
5235
                FROM $forum_post p
5236
                INNER JOIN $forum f
5237
                ON f.forum_id = p.forum_id AND f.c_id = p.c_id
5238
                WHERE p.poster_id = %s and f.session_id = %s and p.c_id = %s";
5239
5240
        $sql = sprintf(
5241
            $sql,
5242
            intval($userId),
5243
            intval($sessionId),
5244
            intval($courseId)
5245
        );
5246
5247
        $result = Database::query($sql);
5248
        $row = Database::fetch_array($result);
5249
        return $row['count'];
5250
    }
5251
5252
    /**
5253
     * Returns the course name from a given code
5254
     * @param string $code
5255
     */
5256
    public static function getCourseNameFromCode($code)
5257
    {
5258
        $tbl_main_categories = Database:: get_main_table(TABLE_MAIN_COURSE);
5259
        $sql = 'SELECT title
5260
                FROM ' . $tbl_main_categories . '
5261
                WHERE code = "' . Database::escape_string($code) . '"';
5262
        $result = Database::query($sql);
5263
        if ($col = Database::fetch_array($result)) {
5264
            return $col['title'];
5265
        }
5266
    }
5267
5268
    /**
5269
     * Generates a course code from a course title
5270
     * @todo Such a function might be useful in other places too. It might be moved in the CourseManager class.
5271
     * @todo the function might be upgraded for avoiding code duplications (currently, it might suggest a code that is already in use)
5272
     * @param string $title A course title
5273
     * @return string A proposed course code
5274
     * +
5275
     * @assert (null,null) === false
5276
     * @assert ('ABC_DEF', null) === 'ABCDEF'
5277
     * @assert ('ABC09*^[%A', null) === 'ABC09A'
5278
     */
5279
    public static function generate_course_code($title)
5280
    {
5281
        return substr(
5282
            preg_replace('/[^A-Z0-9]/', '', strtoupper(api_replace_dangerous_char($title))),
5283
            0,
5284
            CourseManager::MAX_COURSE_LENGTH_CODE
5285
        );
5286
    }
5287
5288
    /**
5289
     * @param $courseId
5290
     * @return array
5291
     */
5292
    public static function getCourseSettings($courseId)
5293
    {
5294
        $settingTable = Database::get_course_table(TABLE_COURSE_SETTING);
5295
        $courseId = intval($courseId);
5296
        $sql = "SELECT * FROM $settingTable WHERE c_id = $courseId";
5297
        $result = Database::query($sql);
5298
        $settings = array();
5299
        if (Database::num_rows($result)) {
5300
            while ($row = Database::fetch_array($result, 'ASSOC')) {
5301
                $settings[$row['variable']] = $row;
5302
            }
5303
        }
5304
        return $settings;
5305
    }
5306
5307
    /**
5308
     * this function gets all the users of the course,
5309
     * including users from linked courses
5310
     */
5311 View Code Duplication
    public static function getCourseUsers()
5312
    {
5313
        //this would return only the users from real courses:
5314
        $session_id = api_get_session_id();
5315
        if ($session_id != 0) {
5316
            $user_list = self::get_real_and_linked_user_list(api_get_course_id(), true, $session_id);
5317
        } else {
5318
            $user_list = self::get_real_and_linked_user_list(api_get_course_id(), false, 0);
5319
        }
5320
5321
        return $user_list;
5322
    }
5323
5324
    /**
5325
     * this function gets all the groups of the course,
5326
     * not including linked courses
5327
     */
5328 View Code Duplication
    public static function getCourseGroups()
5329
    {
5330
        $session_id = api_get_session_id();
5331
        if ($session_id != 0) {
5332
            $new_group_list = self::get_group_list_of_course(api_get_course_id(), $session_id, 1);
5333
        } else {
5334
            $new_group_list = self::get_group_list_of_course(api_get_course_id(), 0, 1);
5335
        }
5336
5337
        return $new_group_list;
5338
    }
5339
5340
    /**
5341
     * @param FormValidator $form
5342
     * @param array $to_already_selected
5343
     *
5344
     * @return HTML_QuickForm_element
5345
     */
5346 View Code Duplication
    public static function addUserGroupMultiSelect(&$form, $to_already_selected)
5347
    {
5348
        $user_list = self::getCourseUsers();
5349
        $group_list = self::getCourseGroups();
5350
        $array = self::buildSelectOptions($group_list, $user_list, $to_already_selected);
5351
5352
        $result = array();
5353
        foreach ($array as $content) {
5354
            $result[$content['value']] = $content['content'];
5355
        }
5356
5357
        return $form->addElement(
5358
            'advmultiselect',
5359
            'users',
5360
            get_lang('Users'),
5361
            $result,
5362
            array('select_all_checkbox' => true)
5363
        );
5364
    }
5365
5366
    /**
5367
     * This function separates the users from the groups
5368
     * users have a value USER:XXX (with XXX the groups id have a value
5369
     *  GROUP:YYY (with YYY the group id)
5370
     * @param  array $to Array of strings that define the type and id of each destination
5371
     * @return array Array of groups and users (each an array of IDs)
5372
     */
5373
    public static function separateUsersGroups($to)
5374
    {
5375
        $grouplist = array();
5376
        $userlist = array();
5377
5378
        foreach ($to as $to_item) {
5379
            if (!empty($to_item)) {
5380
                $parts = explode(':', $to_item);
5381
                $type = isset($parts[0]) ? $parts[0] : '';
5382
                $id = isset($parts[1]) ? $parts[1] : '';
5383
5384
                switch ($type) {
5385
                    case 'GROUP':
5386
                        $grouplist[] = intval($id);
5387
                        break;
5388
                    case 'USER':
5389
                        $userlist[] = intval($id);
5390
                        break;
5391
                }
5392
            }
5393
        }
5394
5395
        $send_to['groups'] = $grouplist;
5396
        $send_to['users'] = $userlist;
5397
5398
        return $send_to;
5399
    }
5400
5401
    /**
5402
     * this function shows the form for sending a message to a specific group or user.
5403
     */
5404
    /**
5405
     * @param FormValidator $form
5406
     * @param int $group_id
5407
     * @param array $to
5408
     */
5409 View Code Duplication
    public static function addGroupMultiSelect($form, $group_id, $to = array())
5410
    {
5411
        $group_users = GroupManager::get_subscribed_users($group_id);
5412
        $array = self::buildSelectOptions(null, $group_users, $to);
5413
5414
        $result = array();
5415
        foreach ($array as $content) {
5416
            $result[$content['value']] = $content['content'];
5417
        }
5418
5419
        $form->addElement('advmultiselect', 'users', get_lang('Users'), $result);
5420
    }
5421
5422
    /**
5423
     * this function shows the form for sending a message to a specific group or user.
5424
     * @param array $group_list
5425
     * @param array $user_list
5426
     * @param array $to_already_selected
5427
     * @return array
5428
     */
5429
    public static function buildSelectOptions(
5430
        $group_list = array(),
5431
        $user_list = array(),
5432
        $to_already_selected = array()
5433
    ) {
5434
        if (empty($to_already_selected)) {
5435
            $to_already_selected = array();
5436
        }
5437
5438
        $result = array();
5439
        // adding the groups to the select form
5440
        if ($group_list) {
5441
            foreach ($group_list as $this_group) {
5442
                if (is_array($to_already_selected)) {
5443
                    if (!in_array(
5444
                        "GROUP:" . $this_group['id'],
5445
                        $to_already_selected
5446
                    )
5447
                    ) { // $to_already_selected is the array containing the groups (and users) that are already selected
5448
                        $user_label = ($this_group['userNb'] > 0) ? get_lang('Users') : get_lang('LowerCaseUser');
5449
                        $user_disabled = ($this_group['userNb'] > 0) ? "" : "disabled=disabled";
5450
                        $result[] = array(
5451
                            'disabled' => $user_disabled,
5452
                            'value' => "GROUP:" . $this_group['id'],
5453
                            'content' => "G: " . $this_group['name'] . " - " . $this_group['userNb'] . " " . $user_label
5454
                        );
5455
                    }
5456
                }
5457
            }
5458
        }
5459
5460
        // adding the individual users to the select form
5461
        if ($user_list) {
5462
            foreach ($user_list as $user) {
5463
                if (is_array($to_already_selected)) {
5464
                    if (!in_array(
5465
                        "USER:" . $user['user_id'],
5466
                        $to_already_selected
5467
                    )
5468
                    ) { // $to_already_selected is the array containing the users (and groups) that are already selected
5469
5470
                        $result[] = array(
5471
                            'value' => "USER:" . $user['user_id'],
5472
                            'content' => api_get_person_name($user['firstname'], $user['lastname'])
5473
                        );
5474
                    }
5475
                }
5476
            }
5477
        }
5478
5479
        return $result;
5480
    }
5481
5482
    /**
5483
     * @return array a list (array) of all courses.
5484
     */
5485
    public static function get_course_list()
5486
    {
5487
        $table = Database::get_main_table(TABLE_MAIN_COURSE);
5488
        return Database::store_result(Database::query("SELECT *, id as real_id FROM $table"));
0 ignored issues
show
Bug introduced by
It seems like \Database::query("SELECT...real_id FROM {$table}") can be null; however, store_result() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
5489
    }
5490
5491
    /**
5492
     * Returns course code from a given gradebook category's id
5493
     * @param int  Category ID
5494
     * @return string  Course code
5495
     */
5496
    public static function get_course_by_category($category_id)
5497
    {
5498
        $category_id = intval($category_id);
5499
        $info = Database::fetch_array(
5500
            Database::query('SELECT course_code FROM ' . Database::get_main_table(TABLE_MAIN_GRADEBOOK_CATEGORY) . '
0 ignored issues
show
Bug introduced by
It seems like \Database::query('SELECT...RE id=' . $category_id) can be null; however, fetch_array() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
5501
            WHERE id=' . $category_id), 'ASSOC'
5502
        );
5503
        return $info ? $info['course_code'] : false;
5504
    }
5505
5506
    /**
5507
     * This function gets all the courses that are not in a session
5508
     * @param date Start date
5509
     * @param date End date
5510
     * @param   bool    $includeClosed Whether to include closed and hidden courses
5511
     * @return array Not-in-session courses
5512
     */
5513
    public static function getCoursesWithoutSession($startDate = null, $endDate = null, $includeClosed = false)
5514
    {
5515
        $dateConditional = ($startDate && $endDate) ?
5516
            " WHERE session_id IN (SELECT id FROM " . Database::get_main_table(TABLE_MAIN_SESSION) .
5517
            " WHERE access_start_date = '$startDate' AND access_end_date = '$endDate')" :
5518
            null;
5519
        $visibility = ($includeClosed ? '' : 'visibility NOT IN (0, 4) AND ');
5520
5521
        $query = "SELECT id, code, title
5522
                FROM " . Database::get_main_table(TABLE_MAIN_COURSE). "
5523
                WHERE $visibility code NOT IN (
5524
                    SELECT DISTINCT course_code FROM " . Database::get_main_table(TABLE_MAIN_SESSION_COURSE) . $dateConditional . ")
5525
                ORDER BY id";
5526
5527
        $result = Database::query($query);
5528
        $courses = array();
5529
        while ($row = Database::fetch_array($result)) {
5530
            $courses[] = $row;
5531
        }
5532
        return $courses;
5533
    }
5534
5535
    /**
5536
     * Get list of courses based on users of a group for a group admin
5537
     * @param int $userId The user id
5538
     * @return array
5539
     */
5540 View Code Duplication
    public static function getCoursesFollowedByGroupAdmin($userId)
5541
    {
5542
        $coursesList = [];
5543
5544
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
5545
        $courseUserTable = Database::get_main_table(TABLE_MAIN_COURSE_USER);
5546
        $userGroup = new UserGroup();
5547
        $userIdList = $userGroup->getGroupUsersByUser($userId);
5548
5549
        if (empty($userIdList)) {
5550
            return [];
5551
        }
5552
5553
        $sql = "SELECT DISTINCT(c.id), c.title
5554
                FROM $courseTable c
5555
                INNER JOIN $courseUserTable cru ON c.id = cru.c_id
5556
                WHERE (
5557
                    cru.user_id IN (" . implode(', ', $userIdList) . ")
5558
                    AND cru.relation_type = 0
5559
                )";
5560
5561
        if (api_is_multiple_url_enabled()) {
5562
            $courseAccessUrlTable = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5563
            $accessUrlId = api_get_current_access_url_id();
5564
5565
            if ($accessUrlId != -1) {
5566
                $sql = "SELECT DISTINCT(c.id), c.title
5567
                        FROM $courseTable c
5568
                        INNER JOIN $courseUserTable cru ON c.id = cru.c_id
5569
                        INNER JOIN $courseAccessUrlTable crau ON c.id = crau.c_id
5570
                        WHERE crau.access_url_id = $accessUrlId
5571
                            AND (
5572
                            cru.id_user IN (" . implode(', ', $userIdList) . ") AND
5573
                            cru.relation_type = 0
5574
                        )";
5575
            }
5576
        }
5577
5578
        $result = Database::query($sql);
5579
5580
        while ($row = Database::fetch_assoc($result)) {
5581
            $coursesList[] = $row;
5582
        }
5583
5584
        return $coursesList;
5585
    }
5586
5587
    /**
5588
     * Direct course link see #5299
5589
     *
5590
     * You can send to your students an URL like this
5591
     * http://chamilodev.beeznest.com/main/auth/inscription.php?c=ABC&e=3
5592
     * Where "c" is the course code and "e" is the exercise Id, after a successful
5593
     * registration the user will be sent to the course or exercise
5594
     *
5595
     */
5596
    public static function redirectToCourse($form_data)
5597
    {
5598
        $course_code_redirect = Session::read('course_redirect');
5599
        $_user = api_get_user_info();
5600
        $user_id = api_get_user_id();
5601
5602
        if (!empty($course_code_redirect)) {
5603
            $course_info = api_get_course_info($course_code_redirect);
5604
            if (!empty($course_info)) {
5605
                if (in_array($course_info['visibility'],
5606
                    array(COURSE_VISIBILITY_OPEN_PLATFORM, COURSE_VISIBILITY_OPEN_WORLD))
5607
                ) {
5608
5609
                    if (CourseManager::is_user_subscribed_in_course($user_id, $course_info['code'])) {
5610
5611
                        $form_data['action'] = $course_info['course_public_url'];
5612
                        $form_data['message'] = sprintf(get_lang('YouHaveBeenRegisteredToCourseX'), $course_info['title']);
5613
                        $form_data['button'] = Display::button(
5614
                            'next',
5615
                            get_lang('GoToCourse', null, $_user['language']),
5616
                            array('class' => 'btn btn-primary btn-large')
5617
                        );
5618
5619
                        $exercise_redirect = intval(Session::read('exercise_redirect'));
5620
                        // Specify the course id as the current context does not
5621
                        // hold a global $_course array
5622
                        $objExercise = new Exercise($course_info['real_id']);
5623
                        $result = $objExercise->read($exercise_redirect);
5624
5625
                        if (!empty($exercise_redirect) && !empty($result)) {
5626
                            $form_data['action'] = api_get_path(WEB_CODE_PATH).'exercice/overview.php?exerciseId='.$exercise_redirect.'&cidReq='.$course_info['code'];
5627
                            $form_data['message'] .= '<br />'.get_lang('YouCanAccessTheExercise');
5628
                            $form_data['button'] = Display::button(
5629
                                'next',
5630
                                get_lang('Go', null, $_user['language']),
5631
                                array('class' => 'btn btn-primary btn-large')
5632
                            );
5633
                        }
5634
5635
                        if (!empty($form_data['action'])) {
5636
                            header('Location: '.$form_data['action']);
5637
                            exit;
5638
                        }
5639
                    }
5640
                }
5641
            }
5642
        }
5643
5644
        return $form_data;
5645
    }
5646
5647
    /**
5648
     * return html code for displaying a course title in the standard view (not the Session view)
5649
     * @param $courseId
5650
     * @param bool $loadDirs
5651
     * @return string
5652
     */
5653
    public static function displayCourseHtml($courseId, $loadDirs = false)
5654
    {
5655
        $params = self::getCourseParamsForDisplay($courseId, $loadDirs);
5656
        $html = self::course_item_html($params, false);
0 ignored issues
show
Bug introduced by
It seems like $params defined by self::getCourseParamsFor...y($courseId, $loadDirs) on line 5655 can also be of type string; however, CourseManager::course_item_html() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
5657
        return $html;
5658
    }
5659
5660
    /**
5661
     * Return tab of params to display a course title in the My Courses tab
5662
     * Check visibility, right, and notification icons, and load_dirs option
5663
     * @param $courseId
5664
     * @param bool $loadDirs
5665
     * @return array
5666
     */
5667
    public static function getCourseParamsForDisplay($courseId, $loadDirs = false)
5668
    {
5669
        $user_id = api_get_user_id();
5670
        // Table definitions
5671
        $TABLECOURS = Database :: get_main_table(TABLE_MAIN_COURSE);
5672
        $TABLECOURSUSER = Database :: get_main_table(TABLE_MAIN_COURSE_USER);
5673
        $TABLE_ACCESS_URL_REL_COURSE = Database :: get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
5674
        $current_url_id = api_get_current_access_url_id();
5675
5676
        // Get course list auto-register
5677
        $special_course_list = self::get_special_course_list();
5678
5679
        $without_special_courses = '';
5680
        if (!empty($special_course_list)) {
5681
            $without_special_courses = ' AND course.code NOT IN ("'.implode('","',$special_course_list).'")';
5682
        }
5683
5684
        //AND course_rel_user.relation_type<>".COURSE_RELATION_TYPE_RRHH."
5685
        $sql = "SELECT course.id, course.title, course.code, course.subscribe subscr, course.unsubscribe unsubscr, course_rel_user.status status,
5686
                course_rel_user.sort sort, course_rel_user.user_course_cat user_course_cat
5687
                FROM
5688
                $TABLECOURS course,
5689
                $TABLECOURSUSER  course_rel_user, ".$TABLE_ACCESS_URL_REL_COURSE." url
5690
                WHERE
5691
                    course.id=".intval($courseId)." AND
5692
                    course.id = course_rel_user.c_id AND
5693
                    url.c_id = course.id AND
5694
                    course_rel_user.user_id = ".intval($user_id)."
5695
                    $without_special_courses
5696
                ";
5697
5698
        // If multiple URL access mode is enabled, only fetch courses
5699
        // corresponding to the current URL.
5700
        if (api_get_multiple_access_url() && $current_url_id != -1) {
5701
            $sql .= " AND url.course_code=course.code AND access_url_id=".intval($current_url_id);
5702
        }
5703
        // Use user's classification for courses (if any).
5704
        $sql .= " ORDER BY course_rel_user.user_course_cat, course_rel_user.sort ASC";
5705
5706
        $result = Database::query($sql);
5707
5708
        // Browse through all courses. We can only have one course because
5709
        // of the  course.id=".intval($courseId) in sql query
5710
        $course = Database::fetch_array($result);
5711
        $course_info = api_get_course_info_by_id($courseId);
5712
        if (empty($course_info)) {
5713
            return '';
5714
        }
5715
5716
        //$course['id_session'] = null;
5717
        $course_info['id_session'] = null;
5718
        $course_info['status'] = $course['status'];
5719
5720
        // For each course, get if there is any notification icon to show
5721
        // (something that would have changed since the user's last visit).
5722
        $show_notification = Display::show_notification($course_info);
5723
5724
        // New code displaying the user's status in respect to this course.
5725
        $status_icon = Display::return_icon(
5726
            'blackboard.png',
5727
            $course_info['title'],
5728
            array(),
5729
            ICON_SIZE_LARGE
5730
        );
5731
5732
        $params = array();
5733
        $params['right_actions'] = '';
5734
5735 View Code Duplication
        if (api_is_platform_admin()) {
5736
            if ($loadDirs) {
5737
                $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'), array('align' => 'absmiddle'),ICON_SIZE_SMALL).'</a>';
5738
                $params['right_actions'] .= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.Display::return_icon('edit.png', get_lang('Edit'), array('align' => 'absmiddle'),ICON_SIZE_SMALL).'</a>';
5739
                $params['right_actions'] .= Display::div('', array('id' => 'document_result_'.$course_info['real_id'].'_0', 'class'=>'document_preview_container'));
5740
            } else {
5741
                $params['right_actions'].= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.Display::return_icon('edit.png', get_lang('Edit'), array('align' => 'absmiddle'),ICON_SIZE_SMALL).'</a>';
5742
            }
5743
5744
            if ($course_info['status'] == COURSEMANAGER) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
5745
                //echo Display::return_icon('teachers.gif', get_lang('Status').': '.get_lang('Teacher'), array('style'=>'width: 11px; height: 11px;'));
5746
            }
5747
        } else {
5748
            if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
5749
                if ($loadDirs) {
5750
                    $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'), array('align' => 'absmiddle'),ICON_SIZE_SMALL).'</a>';
5751
                    $params['right_actions'] .= Display::div('', array('id' => 'document_result_'.$course_info['real_id'].'_0', 'class'=>'document_preview_container'));
5752
                } else {
5753
                    if ($course_info['status'] == COURSEMANAGER) {
5754
                        $params['right_actions'].= '<a href="'.api_get_path(WEB_CODE_PATH).'course_info/infocours.php?cidReq='.$course['code'].'">'.Display::return_icon('edit.png', get_lang('Edit'), array('align' => 'absmiddle'),ICON_SIZE_SMALL).'</a>';
5755
                    }
5756
                }
5757
            }
5758
        }
5759
5760
        $course_title_url = '';
5761 View Code Duplication
        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED || $course['status'] == COURSEMANAGER) {
5762
            $course_title_url = api_get_path(WEB_COURSE_PATH).$course_info['path'].'/?id_session=0';
5763
            $course_title = Display::url($course_info['title'], $course_title_url);
5764
        } else {
5765
            $course_title = $course_info['title']." ".Display::tag('span',get_lang('CourseClosed'), array('class'=>'item_closed'));
5766
        }
5767
5768
        // Start displaying the course block itself
5769
        if (api_get_setting('display_coursecode_in_courselist') == 'true') {
5770
            $course_title .= ' ('.$course_info['visual_code'].') ';
5771
        }
5772
        $teachers = '';
5773 View Code Duplication
        if (api_get_setting('display_teacher_in_courselist') == 'true') {
5774
            $teachers = CourseManager::get_teacher_list_from_course_code_to_string($course['code'], self::USER_SEPARATOR, true);
5775
        }
5776
        $params['link'] = $course_title_url;
5777
        $params['icon'] = $status_icon;
5778
        $params['title'] = $course_title;
5779
        $params['teachers'] = $teachers;
5780
        if ($course_info['visibility'] != COURSE_VISIBILITY_CLOSED) {
5781
            $params['notifications'] = $show_notification;
5782
        }
5783
5784
        return $params;
5785
    }
5786
5787
    /**
5788
     * Get the course id based on the original id and field name in the extra fields.
5789
     * Returns 0 if course was not found
5790
     *
5791
     * @param string $original_course_id_value Original course id
5792
     * @param string $original_course_id_name Original field name
5793
     * @return int Course id
5794
     */
5795
    public static function get_course_id_from_original_id($original_course_id_value, $original_course_id_name)
5796
    {
5797
        $extraFieldValue = new ExtraFieldValue('course');
5798
        $value = $extraFieldValue->get_item_id_from_field_variable_and_field_value(
5799
            $original_course_id_name,
5800
            $original_course_id_value
5801
        );
5802
5803
        if ($value) {
5804
            return $value['item_id'];
5805
        }
5806
        return 0;
5807
    }
5808
}
5809