Passed
Push — 1.11.x ( 9d98b4...9cf9e7 )
by Julito
10:13
created

CourseManager::get_courses_list()   F

Complexity

Conditions 22
Paths 6912

Size

Total Lines 110
Code Lines 67

Duplication

Lines 0
Ratio 0 %

Importance

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

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

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

There are several approaches to avoid long parameter lists:

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