Completed
Push — master ( f77763...d3c71d )
by Julito
11:18
created

CourseManager::autoSubscribeToCourse()   D

Complexity

Conditions 15
Paths 13

Size

Total Lines 142
Code Lines 88

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 15
eloc 88
nc 13
nop 2
dl 0
loc 142
rs 4.9951
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

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

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

Commonly applied refactorings include:

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

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

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

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

    return false;
}

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

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