Completed
Push — master ( a73e85...13dd2e )
by Julito
08:28
created

CourseManager::getExtraFieldsToBePresented()   B

Complexity

Conditions 7
Paths 2

Size

Total Lines 17
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

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