Passed
Push — master ( a5a5d7...80355d )
by Julito
09:20
created

CourseManager::getEntityManager()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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