Completed
Push — master ( 1fcdba...966b12 )
by Julito
12:06
created

CourseManager::get_special_course_list()   B

Complexity

Conditions 8
Paths 7

Size

Total Lines 55
Code Lines 35

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 35
nc 7
nop 0
dl 0
loc 55
rs 8.1155
c 0
b 0
f 0

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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