Completed
Push — master ( d335b1...a46bba )
by Julito
10:51
created

get_details_course_description_html()   B

Complexity

Conditions 6
Paths 2

Size

Total Lines 43
Code Lines 30

Duplication

Lines 0
Ratio 0 %

Importance

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