Passed
Pull Request — 1.11.x (#4488)
by Angel Fernando Quiroz
12:12
created

CourseManager::get_courses_list()   F

Complexity

Conditions 23
Paths 10368

Size

Total Lines 115
Code Lines 71

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 23
eloc 71
nc 10368
nop 10
dl 0
loc 115
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity    Many Parameters   

Long Method

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

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

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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