Passed
Push — master ( e852e9...c6d6bf )
by Julito
08:04
created

CourseManager::getCourseVisibilitySQLCondition()   A

Complexity

Conditions 6
Paths 24

Size

Total Lines 31
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

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