Passed
Pull Request — 1.11.x (#4232)
by Angel Fernando Quiroz
08:37
created

CoursesAndSessionsCatalog::getSessionIcon()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 5
nc 1
nop 1
dl 0
loc 7
rs 10
c 0
b 0
f 0
1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\ExtraField;
6
use Chamilo\CoreBundle\Entity\Repository\SequenceResourceRepository;
7
use Chamilo\CoreBundle\Entity\SequenceResource;
8
use Chamilo\CoreBundle\Entity\SessionRelCourse;
9
use Chamilo\CoreBundle\Entity\Tag;
10
use Doctrine\ORM\Query\Expr\Join;
11
use ExtraField as ExtraFieldModel;
12
13
/**
14
 * @todo change class name
15
 */
16
class CoursesAndSessionsCatalog
17
{
18
    public const PAGE_LENGTH = 12;
19
20
    /**
21
     * Check the configuration for the courses and sessions catalog.
22
     */
23
    public static function is(int $value = CATALOG_COURSES): bool
24
    {
25
        $showCoursesSessions = (int) api_get_setting('catalog_show_courses_sessions');
26
27
        return $showCoursesSessions == $value;
28
    }
29
30
    /**
31
     * Check whether to display the sessions list.
32
     */
33
    public static function showSessions(): bool
34
    {
35
        $catalogShow = (int) api_get_setting('catalog_show_courses_sessions');
36
37
        return $catalogShow == CATALOG_SESSIONS || $catalogShow == CATALOG_COURSES_SESSIONS;
38
    }
39
40
    /**
41
     * Check whether to display the courses list.
42
     */
43
    public static function showCourses(): bool
44
    {
45
        $catalogShow = (int) api_get_setting('catalog_show_courses_sessions');
46
47
        return $catalogShow == CATALOG_COURSES || $catalogShow == CATALOG_COURSES_SESSIONS;
48
    }
49
50
    /**
51
     * @return array
52
     */
53
    public static function getCoursesToAvoid()
54
    {
55
        $TABLE_COURSE_FIELD = Database::get_main_table(TABLE_EXTRA_FIELD);
56
        $TABLE_COURSE_FIELD_VALUE = Database::get_main_table(TABLE_EXTRA_FIELD_VALUES);
57
58
        // Check special courses
59
        $courseListToAvoid = CourseManager::get_special_course_list();
60
61
        $categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model');
62
        if (!empty($categoryToAvoid) && api_is_student()) {
63
            $coursesInCategoryToAvoid = CourseCategory::getCoursesInCategory($categoryToAvoid, '', false);
64
            if (!empty($coursesInCategoryToAvoid)) {
65
                foreach ($coursesInCategoryToAvoid as $courseToAvoid) {
66
                    $courseListToAvoid[] = $courseToAvoid['id'];
67
                }
68
            }
69
        }
70
71
        // Checks "hide_from_catalog" extra field
72
        $extraFieldType = ExtraField::COURSE_FIELD_TYPE;
73
74
        $sql = "SELECT item_id FROM $TABLE_COURSE_FIELD_VALUE tcfv
75
                INNER JOIN $TABLE_COURSE_FIELD tcf
76
                ON tcfv.field_id =  tcf.id
77
                WHERE
78
                    tcf.extra_field_type = $extraFieldType AND
79
                    tcf.variable = 'hide_from_catalog' AND
80
                    tcfv.value = 1
81
                ";
82
83
        $result = Database::query($sql);
84
        if (Database::num_rows($result) > 0) {
85
            while ($row = Database::fetch_array($result)) {
86
                $courseListToAvoid[] = $row['item_id'];
87
            }
88
        }
89
90
        return $courseListToAvoid;
91
    }
92
93
    /**
94
     * @return string
95
     */
96
    public static function getAvoidCourseCondition()
97
    {
98
        $courseListToAvoid = self::getCoursesToAvoid();
99
        $condition = '';
100
        if (!empty($courseListToAvoid)) {
101
            $courses = [];
102
            foreach ($courseListToAvoid as $courseId) {
103
                $courses[] = '"'.$courseId.'"';
104
            }
105
            $condition = ' AND course.id NOT IN ('.implode(',', $courses).')';
106
        }
107
108
        return $condition;
109
    }
110
111
    /**
112
     * Get available le courses count.
113
     *
114
     * @param int $accessUrlId (optional)
115
     *
116
     * @return int Number of courses
117
     */
118
    public static function countAvailableCoursesToShowInCatalog($accessUrlId = 1)
119
    {
120
        $tableCourse = Database::get_main_table(TABLE_MAIN_COURSE);
121
        $tableCourseRelAccessUrl = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
122
        $courseToAvoidCondition = self::getAvoidCourseCondition();
123
        $visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true);
124
125
        $accessUrlId = (int) $accessUrlId;
126
        if (empty($accessUrlId)) {
127
            $accessUrlId = 1;
128
        }
129
130
        $sql = "SELECT count(course.id)
131
                FROM $tableCourse course
132
                INNER JOIN $tableCourseRelAccessUrl u
133
                ON (course.id = u.c_id)
134
                WHERE
135
                    u.access_url_id = $accessUrlId AND
136
                    course.visibility != 0 AND
137
                    course.visibility != 4
138
                    $courseToAvoidCondition
139
                    $visibilityCondition
140
                ";
141
142
        $res = Database::query($sql);
143
        $row = Database::fetch_row($res);
144
145
        return $row[0];
146
    }
147
148
    public static function getCourseCategoriesTree()
149
    {
150
        $urlId = 1;
151
        if (api_is_multiple_url_enabled()) {
152
            $urlId = api_get_current_access_url_id();
153
        }
154
155
        $countCourses = self::countAvailableCoursesToShowInCatalog($urlId);
156
        $categories = [];
157
        $list = [];
158
159
        $categories['ALL'] = [
160
            'id' => 0,
161
            'name' => get_lang('DisplayAll'),
162
            'code' => 'ALL',
163
            'parent_id' => null,
164
            'tree_pos' => 0,
165
            'number_courses' => $countCourses,
166
            'level' => 0,
167
        ];
168
169
        $allCategories = CourseCategory::getAllCategories();
170
        $categoryToAvoid = '';
171
        if (api_is_student()) {
172
            $categoryToAvoid = api_get_configuration_value('course_category_code_to_use_as_model');
173
        }
174
        foreach ($allCategories as $category) {
175
            $categoryCode = $category['code'];
176
            if (!empty($categoryToAvoid) && $categoryToAvoid == $categoryCode) {
177
                continue;
178
            }
179
180
            if (empty($category['parent_id'])) {
181
                $list[$categoryCode] = $category;
182
                $list[$categoryCode]['level'] = 0;
183
                list($subList, $childrenCount) = self::buildCourseCategoryTree($allCategories, $categoryCode, 0);
184
                foreach ($subList as $item) {
185
                    $list[$item['code']] = $item;
186
                }
187
                // Real course count
188
                $countCourses = CourseCategory::countCoursesInCategory($categoryCode);
189
                $list[$categoryCode]['number_courses'] = $childrenCount + $countCourses;
190
            }
191
        }
192
193
        // count courses that are in no category
194
        $countCourses = CourseCategory::countCoursesInCategory('NONE');
195
        $categories['NONE'] = [
196
            'id' => 0,
197
            'name' => get_lang('WithoutCategory'),
198
            'code' => 'NONE',
199
            'parent_id' => null,
200
            'tree_pos' => 0,
201
            'children_count' => 0,
202
            'auth_course_child' => true,
203
            'auth_cat_child' => true,
204
            'number_courses' => $countCourses,
205
            'level' => 0,
206
        ];
207
208
        return array_merge($list, $categories);
209
    }
210
211
    /**
212
     * Return LIMIT to filter SQL query.
213
     *
214
     * @param array $limit
215
     *
216
     * @return string
217
     */
218
    public static function getLimitFilterFromArray($limit)
219
    {
220
        $limitFilter = '';
221
        if (!empty($limit) && is_array($limit)) {
222
            $limitStart = isset($limit['start']) ? (int) $limit['start'] : 0;
223
            $limitLength = isset($limit['length']) ? (int) $limit['length'] : 12;
224
            $limitFilter = 'LIMIT '.$limitStart.', '.$limitLength;
225
        }
226
227
        return $limitFilter;
228
    }
229
230
    /**
231
     * @param string $categoryCode
232
     * @param int    $randomValue
233
     * @param array  $limit        will be used if $randomValue is not set.
234
     *                             This array should contains 'start' and 'length' keys
235
     *
236
     * @return array
237
     */
238
    public static function getCoursesInCategory($categoryCode, $randomValue = null, $limit = [])
239
    {
240
        $tbl_course = Database::get_main_table(TABLE_MAIN_COURSE);
241
        $avoidCoursesCondition = self::getAvoidCourseCondition();
242
        $visibilityCondition = CourseManager::getCourseVisibilitySQLCondition('course', true);
243
244
        if (!empty($randomValue)) {
245
            $randomValue = (int) $randomValue;
246
247
            $sql = "SELECT COUNT(*) FROM $tbl_course";
248
            $result = Database::query($sql);
249
            list($num_records) = Database::fetch_row($result);
250
251
            if (api_is_multiple_url_enabled()) {
252
                $urlId = api_get_current_access_url_id();
253
                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
254
255
                $urlCondition = ' access_url_id = '.$urlId.' ';
256
                $allowBaseCategories = api_get_configuration_value('allow_base_course_category');
257
                if ($allowBaseCategories) {
258
                    $urlCondition = ' (access_url_id = '.$urlId.' OR access_url_id = 1)  ';
259
                }
260
261
                $sql = "SELECT COUNT(*)
262
                        FROM $tbl_course course
263
                        INNER JOIN $tbl_url_rel_course as url_rel_course
264
                        ON (url_rel_course.c_id = course.id)
265
                        WHERE access_url_id = $urlId";
266
                $result = Database::query($sql);
267
                list($num_records) = Database::fetch_row($result);
268
269
                $sql = "SELECT course.id, course.id as real_id
270
                        FROM $tbl_course course
271
                        INNER JOIN $tbl_url_rel_course as url_rel_course
272
                        ON (url_rel_course.c_id = course.id)
273
                        WHERE
274
                            $urlCondition AND
275
                            RAND()*$num_records< $randomValue
276
                            $avoidCoursesCondition
277
                            $visibilityCondition
278
                        ORDER BY RAND()
279
                        LIMIT 0, $randomValue";
280
            } else {
281
                $sql = "SELECT id, id as real_id
282
                        FROM $tbl_course course
283
                        WHERE
284
                            RAND()*$num_records< $randomValue
285
                            $avoidCoursesCondition
286
                            $visibilityCondition
287
                        ORDER BY RAND()
288
                        LIMIT 0, $randomValue";
289
            }
290
291
            $result = Database::query($sql);
292
            $id_in = null;
293
            while (list($id) = Database::fetch_row($result)) {
294
                if ($id_in) {
295
                    $id_in .= ",$id";
296
                } else {
297
                    $id_in = "$id";
298
                }
299
            }
300
            if (null === $id_in) {
301
                return [];
302
            }
303
            $sql = "SELECT *, id as real_id FROM $tbl_course WHERE id IN($id_in)";
304
        } else {
305
            $limitFilter = self::getLimitFilterFromArray($limit);
306
            $categoryCode = Database::escape_string($categoryCode);
307
            $listCode = self::childrenCategories($categoryCode);
308
            $conditionCode = ' ';
309
310
            if (empty($listCode)) {
311
                if ($categoryCode === 'NONE') {
312
                    $conditionCode .= " category_code='' ";
313
                } else {
314
                    $conditionCode .= " category_code='$categoryCode' ";
315
                }
316
            } else {
317
                foreach ($listCode as $code) {
318
                    $conditionCode .= " category_code='$code' OR ";
319
                }
320
                $conditionCode .= " category_code='$categoryCode' ";
321
            }
322
323
            if (empty($categoryCode) || $categoryCode === 'ALL') {
324
                $sql = "SELECT *, id as real_id
325
                        FROM $tbl_course course
326
                        WHERE
327
                          1=1
328
                          $avoidCoursesCondition
329
                          $visibilityCondition
330
                        ORDER BY title $limitFilter ";
331
            } else {
332
                $sql = "SELECT *, id as real_id FROM $tbl_course course
333
                        WHERE
334
                            $conditionCode
335
                            $avoidCoursesCondition
336
                            $visibilityCondition
337
                        ORDER BY title $limitFilter ";
338
            }
339
340
            // Showing only the courses of the current Chamilo access_url_id
341
            if (api_is_multiple_url_enabled()) {
342
                $urlId = api_get_current_access_url_id();
343
                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
344
345
                $urlCondition = ' access_url_id = '.$urlId.' ';
346
                if ($categoryCode !== 'ALL') {
347
                    $sql = "SELECT *, course.id real_id
348
                            FROM $tbl_course as course
349
                            INNER JOIN $tbl_url_rel_course as url_rel_course
350
                            ON (url_rel_course.c_id = course.id)
351
                            WHERE
352
                                $urlCondition AND
353
                                $conditionCode
354
                                $avoidCoursesCondition
355
                                $visibilityCondition
356
                            ORDER BY title $limitFilter";
357
                } else {
358
                    $sql = "SELECT *, course.id real_id FROM $tbl_course as course
359
                            INNER JOIN $tbl_url_rel_course as url_rel_course
360
                            ON (url_rel_course.c_id = course.id)
361
                            WHERE
362
                                $urlCondition
363
                                $avoidCoursesCondition
364
                                $visibilityCondition
365
                            ORDER BY title $limitFilter";
366
                }
367
            }
368
        }
369
370
        $result = Database::query($sql);
371
        $courses = [];
372
        while ($row = Database::fetch_array($result)) {
373
            $row['registration_code'] = !empty($row['registration_code']);
374
            $count_users = CourseManager::get_users_count_in_course($row['code']);
375
            $connectionsLastMonth = Tracking::get_course_connections_count(
376
                $row['id'],
377
                0,
378
                api_get_utc_datetime(time() - (30 * 86400))
379
            );
380
381
            if ($row['tutor_name'] == '0') {
382
                $row['tutor_name'] = get_lang('NoManager');
383
            }
384
385
            $courses[] = [
386
                'real_id' => $row['real_id'],
387
                'point_info' => CourseManager::get_course_ranking($row['id'], 0),
388
                'code' => $row['code'],
389
                'directory' => $row['directory'],
390
                'visual_code' => $row['visual_code'],
391
                'title' => $row['title'],
392
                'tutor' => $row['tutor_name'],
393
                'subscribe' => $row['subscribe'],
394
                'unsubscribe' => $row['unsubscribe'],
395
                'registration_code' => $row['registration_code'],
396
                'creation_date' => $row['creation_date'],
397
                'visibility' => $row['visibility'],
398
                'category' => $row['category_code'],
399
                'count_users' => $count_users,
400
                'count_connections' => $connectionsLastMonth,
401
            ];
402
        }
403
404
        return $courses;
405
    }
406
407
    /**
408
     * Search the courses database for a course that matches the search term.
409
     * The search is done on the code, title and tutor field of the course table.
410
     *
411
     * @param string $categoryCode
412
     * @param string $keyword      The string that the user submitted
413
     * @param array  $limit
414
     * @param bool   $justVisible  search only on visible courses in the catalogue
415
     * @param array  $conditions
416
     *
417
     * @return array an array containing a list of all the courses matching the the search term
418
     */
419
    public static function searchCourses($categoryCode, $keyword, $limit, $justVisible = false, $conditions = [])
420
    {
421
        $courseTable = Database::get_main_table(TABLE_MAIN_COURSE);
422
        $limitFilter = self::getLimitFilterFromArray($limit);
423
        $avoidCoursesCondition = self::getAvoidCourseCondition();
424
        $visibilityCondition = $justVisible ? CourseManager::getCourseVisibilitySQLCondition('course', true) : '';
425
426
        $keyword = Database::escape_string($keyword);
427
        $categoryCode = Database::escape_string($categoryCode);
428
429
        $sqlInjectJoins = '';
430
        $where = 'AND 1 = 1 ';
431
        $sqlInjectWhere = '';
432
        $injectExtraFields = '1';
433
        if (!empty($conditions)) {
434
            $sqlInjectJoins = $conditions['inject_joins'];
435
            $where = $conditions['where'];
436
            $sqlInjectWhere = $conditions['inject_where'];
437
            $injectExtraFields = !empty($conditions['inject_extra_fields']) ? $conditions['inject_extra_fields'] : 1;
438
            $injectExtraFields = rtrim($injectExtraFields, ', ');
439
        }
440
441
        $categoryFilter = '';
442
        if ($categoryCode === 'ALL' || empty($categoryCode)) {
443
            // Nothing to do
444
        } elseif ($categoryCode === 'NONE') {
445
            $categoryFilter = ' AND category_code = "" ';
446
        } else {
447
            $categoryFilter = ' AND category_code = "'.$categoryCode.'" ';
448
        }
449
450
        //$sql = "SELECT DISTINCT course.*, $injectExtraFields
451
        $sql = "SELECT DISTINCT(course.id)
452
                FROM $courseTable course
453
                $sqlInjectJoins
454
                WHERE (
455
                        course.code LIKE '%".$keyword."%' OR
456
                        course.title LIKE '%".$keyword."%' OR
457
                        course.tutor_name LIKE '%".$keyword."%'
458
                    )
459
                    $where
460
                    $categoryFilter
461
                    $sqlInjectWhere
462
                    $avoidCoursesCondition
463
                    $visibilityCondition
464
                ORDER BY title, visual_code ASC
465
                $limitFilter
466
                ";
467
468
        if (api_is_multiple_url_enabled()) {
469
            $urlId = api_get_current_access_url_id();
470
            if (-1 != $urlId) {
471
                $tbl_url_rel_course = Database::get_main_table(TABLE_MAIN_ACCESS_URL_REL_COURSE);
472
                $urlCondition = ' access_url_id = '.$urlId.' AND';
473
                $allowBaseCategories = api_get_configuration_value('allow_base_course_category');
474
                if ($allowBaseCategories) {
475
                    $urlCondition = ' (access_url_id = '.$urlId.' OR access_url_id = 1) AND ';
476
                }
477
                //SELECT DISTINCT course.*, $injectExtraFields
478
                $sql = "SELECT DISTINCT(course.id)
479
                        FROM $courseTable as course
480
                        INNER JOIN $tbl_url_rel_course as url_rel_course
481
                        ON (url_rel_course.c_id = course.id)
482
                        $sqlInjectJoins
483
                        WHERE
484
                            access_url_id = $urlId AND
485
                            (
486
                                code LIKE '%".$keyword."%' OR
487
                                title LIKE '%".$keyword."%' OR
488
                                tutor_name LIKE '%".$keyword."%'
489
                            )
490
                            $where
491
                            $categoryFilter
492
                            $sqlInjectWhere
493
                            $avoidCoursesCondition
494
                            $visibilityCondition
495
                        ORDER BY title, visual_code ASC
496
                        $limitFilter
497
                       ";
498
            }
499
        }
500
501
        $result = Database::query($sql);
502
        $courses = [];
503
        while ($row = Database::fetch_array($result)) {
504
            $courseId = $row['id'];
505
            $courseInfo = api_get_course_info_by_id($courseId);
506
            if (empty($courseInfo)) {
507
                continue;
508
            }
509
            $courseCode = $courseInfo['code'];
510
511
            $countUsers = CourseManager::get_user_list_from_course_code(
512
                $courseCode,
513
                0,
514
                null,
515
                null,
516
                null,
517
                true
518
            );
519
            $connectionsLastMonth = Tracking::get_course_connections_count(
520
                $courseId,
521
                0,
522
                api_get_utc_datetime(time() - (30 * 86400))
523
            );
524
525
            $courseInfo['point_info'] = CourseManager::get_course_ranking($courseId, 0);
526
            $courseInfo['tutor'] = $courseInfo['tutor_name'];
527
            $courseInfo['registration_code'] = !empty($courseInfo['registration_code']);
528
            $courseInfo['count_users'] = $countUsers;
529
            $courseInfo['count_connections'] = $connectionsLastMonth;
530
531
            $courses[] = $courseInfo;
532
        }
533
534
        return $courses;
535
    }
536
537
    /**
538
     * Gets extra fields listed in configuration option course_catalog_settings/extra_field_sort_options sorting order.
539
     *
540
     * @return array "extra_field_$id" => order (1 = ascending, -1 = descending)
541
     */
542
    public static function courseExtraFieldSortingOrder()
543
    {
544
        $order = [];
545
        $variableOrder = api_get_configuration_sub_value('course_catalog_settings/extra_field_sort_options', []);
546
        foreach (self::getCourseExtraFieldsAvailableForSorting() as $extraField) {
547
            $order['extra_field_'.$extraField->getId()] = $variableOrder[$extraField->getVariable()];
548
        }
549
550
        return $order;
551
    }
552
553
    /**
554
     * Gets the extra fields listed in configuration option course_catalog_settings/extra_field_sort_options.
555
     *
556
     * @return ExtraField[]
557
     */
558
    public static function getCourseExtraFieldsAvailableForSorting()
559
    {
560
        $variables = array_keys(
561
            api_get_configuration_sub_value('course_catalog_settings/extra_field_sort_options', [])
562
        );
563
        if (is_array($variables) && !empty($variables)) {
564
            return ExtraField::getExtraFieldsFromVariablesOrdered($variables, ExtraField::COURSE_FIELD_TYPE);
565
        }
566
567
        return [];
568
    }
569
570
    /**
571
     * Builds the list of possible course standard sort criteria.
572
     *
573
     * @return array option name => order (1 = ascending, -1 = descending)
574
     */
575
    public static function courseStandardSortOrder()
576
    {
577
        return api_get_configuration_sub_value(
578
            'course_catalog_settings/standard_sort_options',
579
            [
580
                'title' => 1,
581
                'creation_date' => -1,
582
                'count_users' => -1, // subscription count
583
                'point_info/point_average' => -1, // average score
584
                'point_info/total_score' => -1, // score sum
585
                'point_info/users' => -1, // vote count
586
            ]
587
        );
588
    }
589
590
    /**
591
     * Builds the list of possible course sort criteria to be used in an HTML select element.
592
     *
593
     * @return array select option name => display text
594
     */
595
    public static function courseSortOptions()
596
    {
597
        /** @var $extraFields ExtraField[] */
598
        $standardLabels = [
599
            'title' => get_lang('Title'),
600
            'creation_date' => get_lang('CreationDate'),
601
            'count_users' => get_lang('SubscriptionCount'),
602
            'point_info/point_average' => get_lang('PointAverage'),
603
            'point_info/total_score' => get_lang('TotalScore'),
604
            'point_info/users' => get_lang('VoteCount'),
605
        ];
606
        $options = [];
607
        foreach (array_keys(self::courseStandardSortOrder()) as $name) {
608
            $options[$name] = $standardLabels[$name] ?: $name;
609
        }
610
        foreach (self::getCourseExtraFieldsAvailableForSorting() as $extraField) {
611
            $options['extra_field_'.$extraField->getId()] = $extraField->getDisplayText();
612
        }
613
614
        return $options;
615
    }
616
617
    public static function courseSortOrder()
618
    {
619
        return self::courseStandardSortOrder() + self::courseExtraFieldSortingOrder();
620
    }
621
622
    /**
623
     * Wrapper for self::searchCourses which locally sorts the results according to $sortKey.
624
     *
625
     * @param string   $categoryCode can be 'ALL', 'NONE' or any existing course category code
626
     * @param string   $keyword      search pattern to be found in course code, title or tutor_name
627
     * @param array    $limit        associative array generated by \CoursesAndSessionsCatalog::getLimitArray()
628
     * @param bool     $justVisible  search only on visible courses in the catalogue
629
     * @param array    $conditions   associative array generated using \ExtraField::parseConditions
630
     * @param string[] $sortKeys     a subset of the keys of the array returned by courseSortOptions()
631
     *
632
     * @return array list of all the courses matching the the search term
633
     */
634
    public static function searchAndSortCourses(
635
        $categoryCode,
636
        $keyword,
637
        $limit,
638
        $justVisible = false,
639
        $conditions = [],
640
        $sortKeys = []
641
    ) {
642
        // Get ALL matching courses (no limit)
643
        $courses = self::searchCourses($categoryCode, $keyword, null, $justVisible, $conditions);
644
        // Do we have extra fields to sort on ?
645
        $extraFieldsToSortOn = [];
646
        foreach (self::getCourseExtraFieldsAvailableForSorting() as $extraField) {
647
            if (in_array('extra_field_'.$extraField->getId(), $sortKeys)) {
648
                $extraFieldsToSortOn[] = $extraField;
649
            }
650
        }
651
        if (!empty($extraFieldsToSortOn)) {
652
            // load extra field values and store them in $courses
653
            $courseIds = [];
654
            foreach ($courses as $course) {
655
                $courseIds[] = $course['real_id'];
656
            }
657
            $values = ExtraField::getValueForEachExtraFieldForEachItem($extraFieldsToSortOn, $courseIds);
658
            foreach ($courses as &$course) {
659
                $courseId = $course['real_id'];
660
                if (array_key_exists($courseId, $values)) {
661
                    foreach ($values[$courseId] as $extraFieldId => $value) {
662
                        $course['extra_field_'.$extraFieldId] = $value;
663
                    }
664
                }
665
            }
666
            unset($course);
667
        }
668
669
        // do we have $course['groupKey']['subKey'] to sort on, such as 'point_info/users' ?
670
        foreach ($sortKeys as $key) {
671
            if (false !== strpos($key, '/')) {
672
                foreach ($courses as &$course) {
673
                    $subValue = api_array_sub_value($course, $key);
674
                    if (!is_null($subValue)) {
675
                        $course[$key] = $subValue;
676
                    }
677
                }
678
                unset($course);
679
            }
680
        }
681
        $sortOrder = self::courseSortOrder();
682
        usort($courses, function ($a, $b) use ($sortKeys, $sortOrder) {
683
            foreach ($sortKeys as $key) {
684
                $valueA = array_key_exists($key, $a) ? $a[$key] : null;
685
                $valueB = array_key_exists($key, $b) ? $b[$key] : null;
686
                if ($valueA !== $valueB) {
687
                    $aIsLessThanB = (is_string($valueA) && is_string($valueB))
688
                        ? strtolower($valueA) < strtolower($valueB)
689
                        : $valueA < $valueB;
690
                    $reverseOrder = (array_key_exists($key, $sortOrder) && -1 === $sortOrder[$key]);
691
                    $aIsBeforeB = ($aIsLessThanB xor $reverseOrder);
692
693
                    return $aIsBeforeB ? -1 : 1;
694
                }
695
            }
696
697
            return 0;
698
        });
699
700
        return array_slice($courses, $limit['start'], $limit['length']);
701
    }
702
703
    /**
704
     * List the sessions.
705
     *
706
     * @param string $date
707
     * @param array  $limit
708
     * @param bool   $returnQueryBuilder
709
     * @param bool   $getCount
710
     *
711
     * @return array|\Doctrine\ORM\Query The session list
712
     */
713
    public static function browseSessions($date = null, $limit = [], $returnQueryBuilder = false, $getCount = false)
714
    {
715
        $urlId = api_get_current_access_url_id();
716
        $em = Database::getManager();
717
        $qb = $em->createQueryBuilder();
718
        $qb2 = $em->createQueryBuilder();
719
720
        $qb = $qb
721
            ->select('s')
722
            ->from('ChamiloCoreBundle:Session', 's')
723
            ->where(
724
                $qb->expr()->in(
725
                    's',
726
                    $qb2
727
                        ->select('s2')
728
                        ->from('ChamiloCoreBundle:AccessUrlRelSession', 'url')
729
                        ->join('ChamiloCoreBundle:Session', 's2')
730
                        ->where(
731
                            $qb->expr()->eq('url.sessionId ', 's2.id')
732
                        )->andWhere(
733
                            $qb->expr()->eq('url.accessUrlId ', $urlId))
734
                        ->getDQL()
735
                )
736
            )
737
            ->andWhere($qb->expr()->gt('s.nbrCourses', 0))
738
        ;
739
740
        if (!empty($date)) {
741
            $qb->andWhere(
742
                $qb->expr()->orX(
743
                    $qb->expr()->isNull('s.accessEndDate'),
744
                    $qb->expr()->andX(
745
                        $qb->expr()->isNotNull('s.accessStartDate'),
746
                        $qb->expr()->isNotNull('s.accessEndDate'),
747
                        $qb->expr()->lte('s.accessStartDate', $date),
748
                        $qb->expr()->gte('s.accessEndDate', $date)
749
                    ),
750
                    $qb->expr()->andX(
751
                        $qb->expr()->isNull('s.accessStartDate'),
752
                        $qb->expr()->isNotNull('s.accessEndDate'),
753
                        $qb->expr()->gte('s.accessEndDate', $date)
754
                    )
755
                )
756
            );
757
        }
758
759
        if ($getCount) {
760
            $qb->select('count(s)');
761
        }
762
763
        $qb = self::hideFromSessionCatalogCondition($qb);
764
765
        if (!empty($limit)) {
766
            $qb
767
                ->setFirstResult($limit['start'])
768
                ->setMaxResults($limit['length'])
769
            ;
770
        }
771
772
        $query = $qb->getQuery();
773
774
        if ($returnQueryBuilder) {
775
            return $query;
776
        }
777
778
        if ($getCount) {
779
            return $query->getSingleScalarResult();
780
        }
781
782
        return $query->getResult();
783
    }
784
785
    /**
786
     * @param \Doctrine\ORM\QueryBuilder $qb
787
     *
788
     * @return mixed
789
     */
790
    public static function hideFromSessionCatalogCondition($qb)
791
    {
792
        $em = Database::getManager();
793
        $qb3 = $em->createQueryBuilder();
794
795
        $extraField = new ExtraFieldModel('session');
796
        $extraFieldInfo = $extraField->get_handler_field_info_by_field_variable('hide_from_catalog');
797
        if (!empty($extraFieldInfo)) {
798
            $qb->andWhere(
799
                $qb->expr()->notIn(
800
                    's',
801
                    $qb3
802
                        ->select('s3')
803
                        ->from('ChamiloCoreBundle:ExtraFieldValues', 'fv')
804
                        ->innerJoin('ChamiloCoreBundle:Session', 's3', Join::WITH, 'fv.itemId = s3.id')
805
                        ->where(
806
                            $qb->expr()->eq('fv.field', $extraFieldInfo['id'])
807
                        )->andWhere(
808
                            $qb->expr()->eq('fv.value ', 1)
809
                        )
810
                        ->getDQL()
811
                )
812
            );
813
        }
814
815
        return $qb;
816
    }
817
818
    /**
819
     * Search sessions by the tags in their courses.
820
     *
821
     * @param string $termTag Term for search in tags
822
     * @param array  $limit   Limit info
823
     *
824
     * @return array The sessions
825
     */
826
    public static function browseSessionsByTags($termTag, array $limit, $getCount = false)
827
    {
828
        $em = Database::getManager();
829
        $qb = $em->createQueryBuilder();
830
831
        $urlId = api_get_current_access_url_id();
832
833
        $qb->select('s')
834
            ->distinct()
835
            ->from('ChamiloCoreBundle:Session', 's')
836
            ->innerJoin(
837
                'ChamiloCoreBundle:SessionRelCourse',
838
                'src',
839
                Join::WITH,
840
                's.id = src.session'
841
            )
842
            ->innerJoin(
843
                'ChamiloCoreBundle:AccessUrlRelSession',
844
                'url',
845
                Join::WITH,
846
                'url.sessionId = s.id'
847
            )
848
            ->innerJoin(
849
                'ChamiloCoreBundle:ExtraFieldRelTag',
850
                'frt',
851
                Join::WITH,
852
                'src.course = frt.itemId'
853
            )
854
            ->innerJoin(
855
                'ChamiloCoreBundle:Tag',
856
                't',
857
                Join::WITH,
858
                'frt.tagId = t.id'
859
            )
860
            ->innerJoin(
861
                'ChamiloCoreBundle:ExtraField',
862
                'f',
863
                Join::WITH,
864
                'frt.fieldId = f.id'
865
            )
866
            ->where(
867
                $qb->expr()->like('t.tag', ':tag')
868
            )
869
            ->andWhere(
870
                $qb->expr()->eq('f.extraFieldType', ExtraField::COURSE_FIELD_TYPE)
871
            )
872
            ->andWhere($qb->expr()->gt('s.nbrCourses', 0))
873
            ->andWhere($qb->expr()->eq('url.accessUrlId', $urlId))
874
            ->setParameter('tag', "$termTag%")
875
        ;
876
877
        if (!empty($limit)) {
878
            $qb
879
                ->setFirstResult($limit['start'])
880
                ->setMaxResults($limit['length'])
881
            ;
882
        }
883
884
        $qb = self::hideFromSessionCatalogCondition($qb);
885
886
        if ($getCount) {
887
            $qb->select('count(s)');
888
889
            return $qb->getQuery()->getSingleScalarResult();
890
        }
891
892
        return $qb->getQuery()->getResult();
893
    }
894
895
    /**
896
     * Search sessions by the title.
897
     *
898
     * @param string $keyword
899
     * @param array  $limit   Limit info
900
     *
901
     * @return array The sessions
902
     */
903
    public static function getSessionsByName($keyword, array $limit, $getCount = false)
904
    {
905
        $em = Database::getManager();
906
        $qb = $em->createQueryBuilder();
907
        $urlId = api_get_current_access_url_id();
908
909
        $qb->select('s')
910
            ->distinct()
911
            ->from('ChamiloCoreBundle:Session', 's')
912
            ->innerJoin(
913
                'ChamiloCoreBundle:SessionRelCourse',
914
                'src',
915
                Join::WITH,
916
                's.id = src.session'
917
            )
918
            ->innerJoin(
919
                'ChamiloCoreBundle:AccessUrlRelSession',
920
                'url',
921
                Join::WITH,
922
                'url.sessionId = s.id'
923
            )
924
            ->andWhere($qb->expr()->eq('url.accessUrlId', $urlId))
925
            ->andWhere('s.name LIKE :keyword')
926
            ->andWhere($qb->expr()->gt('s.nbrCourses', 0))
927
            ->setParameter('keyword', "%$keyword%")
928
        ;
929
930
        if (!empty($limit)) {
931
            $qb
932
                ->setFirstResult($limit['start'])
933
                ->setMaxResults($limit['length']);
934
        }
935
936
        $qb = self::hideFromSessionCatalogCondition($qb);
937
938
        if ($getCount) {
939
            $qb->select('count(s)');
940
941
            return $qb->getQuery()->getSingleScalarResult();
942
        }
943
944
        return $qb->getQuery()->getResult();
945
    }
946
947
    /**
948
     * Build a recursive tree of course categories.
949
     *
950
     * @param array $categories
951
     * @param int   $parentId
952
     * @param int   $level
953
     *
954
     * @return array
955
     */
956
    public static function buildCourseCategoryTree($categories, $parentId = 0, $level = 0)
957
    {
958
        $list = [];
959
        $count = 0;
960
        $level++;
961
        foreach ($categories as $category) {
962
            if (empty($category['parent_id'])) {
963
                continue;
964
            }
965
            if ($category['parent_id'] == $parentId) {
966
                $list[$category['code']] = $category;
967
                $count += $category['number_courses'];
968
                $list[$category['code']]['level'] = $level;
969
                list($subList, $childrenCount) = self::buildCourseCategoryTree(
970
                    $categories,
971
                    $category['code'],
972
                    $level
973
                );
974
                $list[$category['code']]['number_courses'] += $childrenCount;
975
                foreach ($subList as $item) {
976
                    $list[$item['code']] = $item;
977
                }
978
                $count += $childrenCount;
979
            }
980
        }
981
982
        return [$list, $count];
983
    }
984
985
    /**
986
     * List Code Search Category.
987
     *
988
     * @param string $code
989
     *
990
     * @return array
991
     */
992
    public static function childrenCategories($code)
993
    {
994
        $allCategories = CourseCategory::getAllCategories();
995
        $list = [];
996
        $row = [];
997
998
        if ($code !== 'ALL' && $code !== 'NONE') {
999
            foreach ($allCategories as $category) {
1000
                if ($category['code'] === $code) {
1001
                    $list = self::buildCourseCategoryTree($allCategories, $category['code'], 0);
1002
                }
1003
            }
1004
            foreach ($list[0] as $item) {
1005
                $row[] = $item['code'];
1006
            }
1007
        }
1008
1009
        return $row;
1010
    }
1011
1012
    /**
1013
     * Get the image of a course for the catalog.
1014
     */
1015
    public static function returnThumbnail(array $course): string
1016
    {
1017
        $course_path = api_get_path(SYS_COURSE_PATH).$course['directory'];
1018
1019
        if (file_exists($course_path.'/course-pic.png')) {
1020
            // redimensioned image 85x85
1021
            return api_get_path(WEB_COURSE_PATH).$course['directory'].'/course-pic.png';
1022
        }
1023
1024
        // without picture
1025
        return Display::return_icon(
1026
            'session_default.png',
1027
            null,
1028
            null,
1029
            null,
1030
            null,
1031
            true
1032
        );
1033
    }
1034
1035
    public static function return_teacher(array $courseInfo): string
1036
    {
1037
        $teachers = CourseManager::getTeachersFromCourse($courseInfo['real_id']);
1038
        $length = count($teachers);
1039
1040
        if (!$length) {
1041
            return '';
1042
        }
1043
1044
        $html = '<div class="block-author">';
1045
        if ($length > 6) {
1046
            $html .= '<a
1047
            id="plist"
1048
            data-trigger="focus"
1049
            tabindex="0" role="button"
1050
            class="btn btn-default panel_popover"
1051
            data-toggle="popover"
1052
            title="'.addslashes(get_lang('CourseTeachers')).'"
1053
            data-html="true"
1054
        >
1055
            <i class="fa fa-graduation-cap" aria-hidden="true"></i>
1056
        </a>';
1057
            $html .= '<div id="popover-content-plist" class="hide">';
1058
            foreach ($teachers as $value) {
1059
                $name = $value['firstname'].' '.$value['lastname'];
1060
                $html .= '<div class="popover-teacher">';
1061
                $html .= '<a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">
1062
                        <img src="'.$value['avatar'].'" title="'.$name.'" alt="'.get_lang('UserPicture').'"/></a>';
1063
                $html .= '<div class="teachers-details"><h5>
1064
                        <a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">'
1065
                    .$name.'</a></h5></div>';
1066
                $html .= '</div>';
1067
            }
1068
            $html .= '</div>';
1069
        } else {
1070
            foreach ($teachers as $value) {
1071
                $name = $value['firstname'].' '.$value['lastname'];
1072
                if ($length > 2) {
1073
                    $html .= '<a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">
1074
                        <img src="'.$value['avatar'].'" title="'.$name.'" alt="'.get_lang('UserPicture').'"/></a>';
1075
                } else {
1076
                    $html .= '<a href="'.$value['url'].'" class="ajax" data-title="'.$name.'" title="'.$name.'">
1077
                        <img src="'.$value['avatar'].'" title="'.$name.'" alt="'.get_lang('UserPicture').'"/></a>';
1078
                    $html .= '<div class="teachers-details"><h5>
1079
                        <a href="'.$value['url'].'" class="ajax" data-title="'.$name.'">'
1080
                        .$name.'</a></h5><p>'.get_lang('Teacher').'</p></div>';
1081
                }
1082
            }
1083
        }
1084
        $html .= '</div>';
1085
1086
        return $html;
1087
    }
1088
1089
    /**
1090
     * Display the already registerd text in a course in the course catalog.
1091
     *
1092
     * @param $status
1093
     *
1094
     * @return string HTML string
1095
     */
1096
    public static function return_already_registered_label($status)
1097
    {
1098
        $icon = '<em class="fa fa-check"></em>';
1099
        $title = get_lang('YouAreATeacherOfThisCourse');
1100
        if ($status === 'student') {
1101
            $icon = '<em class="fa fa-check"></em>';
1102
            $title = get_lang('AlreadySubscribed');
1103
        }
1104
1105
        $html = Display::tag(
1106
            'span',
1107
            $icon.' '.$title,
1108
            [
1109
                'id' => 'register',
1110
                'class' => 'label-subscribed text-success',
1111
                'title' => $title,
1112
                'aria-label' => $title,
1113
            ]
1114
        );
1115
1116
        return $html.PHP_EOL;
1117
    }
1118
1119
    /**
1120
     * Display the register button of a course in the course catalog.
1121
     *
1122
     * @param $course
1123
     * @param $stok
1124
     * @param $categoryCode
1125
     * @param $search_term
1126
     *
1127
     * @return string
1128
     */
1129
    public static function return_register_button($course, $stok, $categoryCode, $search_term)
1130
    {
1131
        $title = get_lang('Subscribe');
1132
        $action = 'subscribe_course';
1133
        if (!empty($course['registration_code'])) {
1134
            $action = 'subscribe_course_validation';
1135
        }
1136
1137
        return Display::url(
1138
            Display::returnFontAwesomeIcon('check').PHP_EOL.$title,
1139
            api_get_path(WEB_CODE_PATH).'auth/courses.php'
1140
                .'?action='.$action.'&sec_token='.$stok
1141
                .'&course_code='.$course['code'].'&search_term='.$search_term.'&category_code='.$categoryCode,
1142
            ['class' => 'btn btn-success btn-sm', 'title' => $title, 'aria-label' => $title]
1143
        );
1144
    }
1145
1146
    /**
1147
     * Display the unregister button of a course in the course catalog.
1148
     *
1149
     * @param array  $course
1150
     * @param string $stok
1151
     * @param string $search_term
1152
     * @param string $categoryCode
1153
     * @param int    $sessionId
1154
     *
1155
     * @return string
1156
     */
1157
    public static function return_unregister_button($course, $stok, $search_term, $categoryCode, $sessionId = 0)
1158
    {
1159
        $title = get_lang('Unsubscription');
1160
        $search_term = Security::remove_XSS($search_term);
1161
        $categoryCode = Security::remove_XSS($categoryCode);
1162
        $sessionId = (int) $sessionId;
1163
1164
        $url = api_get_path(WEB_CODE_PATH).'auth/courses.php'
1165
            .'?action=unsubscribe&sec_token='.$stok.'&sid='.$sessionId.'&course_code='.$course['code'].
1166
            '&search_term='.$search_term.'&category_code='.$categoryCode;
1167
1168
        return Display::url(
1169
            Display::returnFontAwesomeIcon('sign-in').PHP_EOL.$title,
1170
            $url,
1171
            ['class' => 'btn btn-danger btn-sm', 'title' => $title, 'aria-label' => $title]
1172
        );
1173
    }
1174
1175
    /**
1176
     * Get a HTML button for subscribe to session.
1177
     *
1178
     * @param int    $sessionId         The session ID
1179
     * @param string $sessionName       The session name
1180
     * @param bool   $checkRequirements Optional.
1181
     *                                  Whether the session has requirement. Default is false
1182
     * @param bool   $includeText       Optional. Whether show the text in button
1183
     * @param bool   $btnBing
1184
     *
1185
     * @return string The button HTML
1186
     */
1187
    public static function getRegisteredInSessionButton(
1188
        $sessionId,
1189
        $sessionName,
1190
        $checkRequirements = false,
1191
        $includeText = false,
1192
        $btnBing = false
1193
    ) {
1194
        $sessionId = (int) $sessionId;
1195
        $class = 'btn-sm';
1196
        if ($btnBing) {
1197
            $class = 'btn-lg btn-block';
1198
        }
1199
1200
        if ($checkRequirements) {
1201
            return self::getRequirements($sessionId, SequenceResource::SESSION_TYPE, $includeText, $class);
1202
        }
1203
1204
        $catalogSessionAutoSubscriptionAllowed = false;
1205
        if (api_get_setting('catalog_allow_session_auto_subscription') === 'true') {
1206
            $catalogSessionAutoSubscriptionAllowed = true;
1207
        }
1208
1209
        $url = api_get_path(WEB_CODE_PATH);
1210
1211
        if ($catalogSessionAutoSubscriptionAllowed) {
1212
            $url .= 'auth/courses.php?';
1213
            $url .= http_build_query([
1214
                'action' => 'subscribe_to_session',
1215
                'session_id' => $sessionId,
1216
            ]);
1217
1218
            $result = Display::toolbarButton(
1219
                get_lang('Subscribe'),
1220
                $url,
1221
                'pencil',
1222
                'primary',
1223
                [
1224
                    'class' => $class.' ajax',
1225
                    'data-title' => get_lang('AreYouSureToSubscribe'),
1226
                    'data-size' => 'md',
1227
                    'title' => get_lang('Subscribe'),
1228
                ],
1229
                $includeText
1230
            );
1231
        } else {
1232
            $url .= 'inc/email_editor.php?';
1233
            $url .= http_build_query([
1234
                'action' => 'subscribe_me_to_session',
1235
                'session' => Security::remove_XSS($sessionName),
1236
            ]);
1237
1238
            $result = Display::toolbarButton(
1239
                get_lang('SubscribeToSessionRequest'),
1240
                $url,
1241
                'pencil',
1242
                'primary',
1243
                ['class' => $class],
1244
                $includeText
1245
            );
1246
        }
1247
1248
        $hook = HookResubscribe::create();
1249
        if (!empty($hook)) {
1250
            $hook->setEventData([
1251
                'session_id' => $sessionId,
1252
            ]);
1253
            try {
1254
                $hook->notifyResubscribe(HOOK_EVENT_TYPE_PRE);
1255
            } catch (Exception $exception) {
1256
                $result = $exception->getMessage();
1257
            }
1258
        }
1259
1260
        return $result;
1261
    }
1262
1263
    public static function getRequirements($id, $type, $includeText, $class, $sessionId = 0)
1264
    {
1265
        $id = (int) $id;
1266
        $type = (int) $type;
1267
        $url = api_get_path(WEB_AJAX_PATH).'sequence.ajax.php?';
1268
        $url .= http_build_query(
1269
            [
1270
                'a' => 'get_requirements',
1271
                'id' => $id,
1272
                'type' => $type,
1273
                'sid' => $sessionId,
1274
            ]
1275
        );
1276
1277
        return Display::toolbarButton(
1278
            get_lang('CheckRequirements'),
1279
            $url,
1280
            'shield',
1281
            'info',
1282
            [
1283
                'class' => $class.' ajax',
1284
                'data-title' => get_lang('CheckRequirements'),
1285
                'data-size' => 'md',
1286
                'title' => get_lang('CheckRequirements'),
1287
            ],
1288
            $includeText
1289
        );
1290
    }
1291
1292
    /**
1293
     * Generate a label if the user has been  registered in session.
1294
     *
1295
     * @return string The label
1296
     */
1297
    public static function getAlreadyRegisteredInSessionLabel()
1298
    {
1299
        $icon = '<em class="fa fa-graduation-cap"></em>';
1300
1301
        return Display::div(
1302
            $icon,
1303
            [
1304
                'class' => 'btn btn-default btn-sm registered',
1305
                'title' => get_lang("AlreadyRegisteredToSession"),
1306
            ]
1307
        );
1308
    }
1309
1310
    public static function getSessionPagination($action, $countSessions, $limit)
1311
    {
1312
        $pageTotal = ceil($countSessions / $limit['length']);
1313
        $pagination = '';
1314
        // Do NOT show pagination if only one page or less
1315
        if ($pageTotal > 1) {
1316
            $pagination = self::getCatalogPagination(
1317
                $limit['current'],
1318
                $limit['length'],
1319
                $pageTotal,
1320
                null,
1321
                $action
1322
            );
1323
        }
1324
1325
        return $pagination;
1326
    }
1327
1328
    /**
1329
     * Return Session catalog rendered view.
1330
     */
1331
    public static function sessionList(bool $returnHtml = false): ?string
1332
    {
1333
        $date = $_POST['date'] ?? '';
1334
        $limit = self::getLimitArray();
1335
1336
        $countSessions = self::browseSessions($date, [], false, true);
1337
        $sessions = self::browseSessions($date, $limit);
1338
1339
        $pagination = self::getSessionPagination('display_sessions', $countSessions, $limit);
1340
        $sessionsBlocks = self::getFormattedSessionsBlock($sessions);
1341
1342
        // Get session search catalogue URL
1343
        $courseUrl = self::getCatalogUrl(
1344
            1,
1345
            $limit['length'],
1346
            null,
1347
            'subscribe'
1348
        );
1349
1350
        $tpl = new Template();
1351
        $tpl->assign('actions', self::getTabList(2));
1352
        $tpl->assign('show_courses', self::showCourses());
1353
        $tpl->assign('show_sessions', self::showSessions());
1354
        $tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true');
1355
        $tpl->assign('course_url', $courseUrl);
1356
        $tpl->assign('catalog_pagination', $pagination);
1357
        $tpl->assign('search_token', Security::get_token());
1358
        $tpl->assign('search_date', $date);
1359
        $tpl->assign('web_session_courses_ajax_url', api_get_path(WEB_AJAX_PATH).'course.ajax.php');
1360
        $tpl->assign('sessions', $sessionsBlocks);
1361
        $tpl->assign('already_subscribed_label', self::getAlreadyRegisteredInSessionLabel());
1362
        $tpl->assign('catalog_settings', self::getCatalogSearchSettings());
1363
1364
        $templateContent = $tpl->fetch(
1365
            $tpl->get_template('catalog/session_catalog.tpl')
1366
        );
1367
1368
        if ($returnHtml) {
1369
            return $templateContent;
1370
        }
1371
1372
        $tpl->assign('content', $templateContent);
1373
        $tpl->display_one_col_template();
1374
1375
        return null;
1376
    }
1377
1378
    /**
1379
     * Show the Session Catalogue with filtered session by course tags.
1380
     */
1381
    public static function sessionsListByName()
1382
    {
1383
        $limit = self::getLimitArray();
1384
        $keyword = $_REQUEST['keyword'] ?? null;
1385
        $courseUrl = self::getCatalogUrl(
1386
            1,
1387
            $limit['length'],
1388
            null,
1389
            'subscribe'
1390
        );
1391
1392
        $count = self::getSessionsByName($keyword, [], true);
1393
        $sessions = self::getSessionsByName($keyword, $limit);
1394
        $sessionsBlocks = self::getFormattedSessionsBlock($sessions);
1395
        $pagination = self::getSessionPagination('search_session_title', $count, $limit);
1396
1397
        $tpl = new Template();
1398
        $tpl->assign('catalog_pagination', $pagination);
1399
        $tpl->assign('actions', self::getTabList(2));
1400
        $tpl->assign('show_courses', self::showCourses());
1401
        $tpl->assign('show_sessions', self::showSessions());
1402
        $tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true');
1403
        $tpl->assign('course_url', $courseUrl);
1404
        $tpl->assign('already_subscribed_label', self::getAlreadyRegisteredInSessionLabel());
1405
        $tpl->assign('search_token', Security::get_token());
1406
        $tpl->assign('keyword', Security::remove_XSS($keyword));
1407
        $tpl->assign('sessions', $sessionsBlocks);
1408
        $tpl->assign('catalog_settings', self::getCatalogSearchSettings());
1409
1410
        $templateContent = $tpl->fetch(
1411
            $tpl->get_template('catalog/session_catalog.tpl')
1412
        );
1413
1414
        $tpl->assign('content', $templateContent);
1415
        $tpl->display_one_col_template();
1416
    }
1417
1418
    public static function getCatalogSearchSettings()
1419
    {
1420
        $settings = api_get_configuration_value('catalog_settings');
1421
        if (empty($settings)) {
1422
            // Default everything is visible
1423
            $settings = [
1424
                'sessions' => [
1425
                    'by_title' => true,
1426
                    'by_date' => true,
1427
                    'by_tag' => true,
1428
                    'show_session_info' => true,
1429
                    'show_session_date' => true,
1430
                ],
1431
                'courses' => [
1432
                    'by_title' => true,
1433
                ],
1434
            ];
1435
        }
1436
1437
        return $settings;
1438
    }
1439
1440
    /**
1441
     * @param int $active
1442
     *
1443
     * @return string
1444
     */
1445
    public static function getTabList($active = 1)
1446
    {
1447
        $pageLength = isset($_GET['pageLength']) ? (int) $_GET['pageLength'] : self::PAGE_LENGTH;
1448
1449
        $url = self::getCatalogUrl(1, $pageLength, null, 'display_sessions');
1450
        $headers = [];
1451
        if (self::showCourses()) {
1452
            $headers[] = [
1453
                'url' => api_get_path(WEB_CODE_PATH).'auth/courses.php',
1454
                'content' => get_lang('CourseManagement'),
1455
            ];
1456
        }
1457
1458
        if (self::showSessions()) {
1459
            $headers[] = [
1460
                'url' => $url,
1461
                'content' => get_lang('SessionList'),
1462
            ];
1463
        }
1464
1465
        // If only one option hide menu.
1466
        if (1 === count($headers)) {
1467
            return '';
1468
        }
1469
1470
        return Display::tabsOnlyLink($headers, $active);
1471
    }
1472
1473
    /**
1474
     * Show the Session Catalogue with filtered session by course tags.
1475
     */
1476
    public static function sessionsListByCoursesTag()
1477
    {
1478
        $limit = self::getLimitArray();
1479
        $searchTag = $_REQUEST['search_tag'] ?? '';
1480
        $searchDate = $_REQUEST['date'] ?? date('Y-m-d');
1481
        $courseUrl = self::getCatalogUrl(
1482
            1,
1483
            $limit['length'],
1484
            null,
1485
            'subscribe'
1486
        );
1487
1488
        $sessions = self::browseSessionsByTags($searchTag, $limit);
1489
        $sessionsBlocks = self::getFormattedSessionsBlock($sessions);
1490
1491
        $count = self::browseSessionsByTags($searchTag, [], true);
1492
        $pagination = self::getSessionPagination('search_tag', $count, $limit);
1493
1494
        $tpl = new Template();
1495
        $tpl->assign('catalog_pagination', $pagination);
1496
        $tpl->assign('show_courses', self::showCourses());
1497
        $tpl->assign('show_sessions', self::showSessions());
1498
        $tpl->assign('show_tutor', api_get_setting('show_session_coach') === 'true');
1499
        $tpl->assign('course_url', $courseUrl);
1500
        $tpl->assign('already_subscribed_label', self::getAlreadyRegisteredInSessionLabel());
1501
        $tpl->assign('search_token', Security::get_token());
1502
        $tpl->assign('search_date', Security::remove_XSS($searchDate));
1503
        $tpl->assign('search_tag', Security::remove_XSS($searchTag));
1504
        $tpl->assign('sessions', $sessionsBlocks);
1505
1506
        $templateContent = $tpl->fetch(
1507
            $tpl->get_template('catalog/session_catalog.tpl')
1508
        );
1509
1510
        $tpl->assign('content', $templateContent);
1511
        $tpl->display_one_col_template();
1512
    }
1513
1514
    /**
1515
     * @return array
1516
     */
1517
    public static function getLimitArray()
1518
    {
1519
        $pageCurrent = isset($_REQUEST['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
1520
        $pageLength = isset($_REQUEST['pageLength']) ? (int) $_GET['pageLength'] : self::PAGE_LENGTH;
1521
1522
        return [
1523
            'start' => ($pageCurrent - 1) * $pageLength,
1524
            'current' => $pageCurrent,
1525
            'length' => $pageLength,
1526
        ];
1527
    }
1528
1529
    /**
1530
     * Get the formatted data for sessions block to be displayed on Session Catalog page.
1531
     *
1532
     * @param array $sessions The session list
1533
     *
1534
     * @return array
1535
     */
1536
    public static function getFormattedSessionsBlock(array $sessions)
1537
    {
1538
        $extraFieldValue = new ExtraFieldValue('session');
1539
        $userId = api_get_user_id();
1540
        $sessionsBlocks = [];
1541
        $entityManager = Database::getManager();
1542
        $sessionRelCourseRepo = $entityManager->getRepository('ChamiloCoreBundle:SessionRelCourse');
1543
        $extraFieldRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraField');
1544
        $extraFieldRelTagRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldRelTag');
1545
1546
        $tagsField = $extraFieldRepo->findOneBy([
1547
            'extraFieldType' => Chamilo\CoreBundle\Entity\ExtraField::COURSE_FIELD_TYPE,
1548
            'variable' => 'tags',
1549
        ]);
1550
1551
        /** @var \Chamilo\CoreBundle\Entity\Session $session */
1552
        foreach ($sessions as $session) {
1553
            $sessionDates = SessionManager::parseSessionDates([
1554
                'display_start_date' => $session->getDisplayStartDate(),
1555
                'display_end_date' => $session->getDisplayEndDate(),
1556
                'access_start_date' => $session->getAccessStartDate(),
1557
                'access_end_date' => $session->getAccessEndDate(),
1558
                'coach_access_start_date' => $session->getCoachAccessStartDate(),
1559
                'coach_access_end_date' => $session->getCoachAccessEndDate(),
1560
            ]);
1561
1562
            $imageField = $extraFieldValue->get_values_by_handler_and_field_variable(
1563
                $session->getId(),
1564
                'image'
1565
            );
1566
            $sessionCourseTags = [];
1567
            if (!is_null($tagsField)) {
1568
                $sessionRelCourses = $sessionRelCourseRepo->findBy([
1569
                    'session' => $session,
1570
                ]);
1571
                /** @var SessionRelCourse $sessionRelCourse */
1572
                foreach ($sessionRelCourses as $sessionRelCourse) {
1573
                    $courseTags = $extraFieldRelTagRepo->getTags(
1574
                        $tagsField,
1575
                        $sessionRelCourse->getCourse()->getId()
1576
                    );
1577
                    /** @var Tag $tag */
1578
                    foreach ($courseTags as $tag) {
1579
                        $sessionCourseTags[] = $tag->getTag();
1580
                    }
1581
                }
1582
            }
1583
1584
            if (!empty($sessionCourseTags)) {
1585
                $sessionCourseTags = array_unique($sessionCourseTags);
1586
            }
1587
1588
            /** @var SequenceResourceRepository $repo */
1589
            $repo = $entityManager->getRepository('ChamiloCoreBundle:SequenceResource');
1590
            $sequences = $repo->getRequirementsAndDependenciesWithinSequences(
1591
                $session->getId(),
1592
                SequenceResource::SESSION_TYPE
1593
            );
1594
1595
            $hasRequirements = false;
1596
            foreach ($sequences as $sequence) {
1597
                if (count($sequence['requirements']) === 0) {
1598
                    continue;
1599
                }
1600
                $hasRequirements = true;
1601
                break;
1602
            }
1603
            $cat = $session->getCategory();
1604
            if (empty($cat)) {
1605
                $cat = null;
1606
                $catName = '';
1607
            } else {
1608
                $catName = $cat->getName();
1609
            }
1610
1611
            $generalCoach = $session->getGeneralCoach();
1612
            $coachId = $generalCoach ? $generalCoach->getId() : 0;
1613
            $coachName = $generalCoach ? UserManager::formatUserFullName($session->getGeneralCoach()) : '';
1614
1615
            $actions = null;
1616
            if (api_is_platform_admin()) {
1617
                $actions = api_get_path(WEB_CODE_PATH).'session/resume_session.php?id_session='.$session->getId();
1618
            }
1619
1620
            $plugin = \BuyCoursesPlugin::create();
1621
            $isThisSessionOnSale = $plugin->getBuyCoursePluginPrice($session);
1622
1623
            $sessionsBlock = [
1624
                'id' => $session->getId(),
1625
                'name' => $session->getName(),
1626
                'image' => isset($imageField['value']) ? $imageField['value'] : null,
1627
                'nbr_courses' => $session->getNbrCourses(),
1628
                'nbr_users' => $session->getNbrUsers(),
1629
                'coach_id' => $coachId,
1630
                'coach_url' => $generalCoach
1631
                    ? api_get_path(WEB_AJAX_PATH).'user_manager.ajax.php?a=get_user_popup&user_id='.$coachId
1632
                    : '',
1633
                'coach_name' => $coachName,
1634
                'coach_avatar' => UserManager::getUserPicture($coachId, USER_IMAGE_SIZE_SMALL),
1635
                'is_subscribed' => SessionManager::isUserSubscribedAsStudent($session->getId(), $userId),
1636
                '' => Display::return_icon(
1637
                    'window_list.png',
1638
                    $session->getName(),
1639
                    [],
1640
                    ICON_SIZE_MEDIUM
1641
                ),
1642
                'date' => $sessionDates['display'],
1643
                'price' => !empty($isThisSessionOnSale['html']) ? $isThisSessionOnSale['html'] : '',
1644
                'subscribe_button' => isset($isThisSessionOnSale['buy_button']) ? $isThisSessionOnSale['buy_button'] : self::getRegisteredInSessionButton(
1645
                    $session->getId(),
1646
                    $session->getName(),
1647
                    $hasRequirements
1648
                ),
1649
                'show_description' => $session->getShowDescription(),
1650
                'description' => $session->getDescription(),
1651
                'category' => $catName,
1652
                'tags' => $sessionCourseTags,
1653
                'edit_actions' => $actions,
1654
                'duration' => SessionManager::getDayLeftInSession(
1655
                    ['id' => $session->getId(), 'duration' => $session->getDuration()],
1656
                    $userId
1657
                ),
1658
            ];
1659
1660
            $sessionsBlocks[] = array_merge($sessionsBlock, $sequences);
1661
        }
1662
1663
        return $sessionsBlocks;
1664
    }
1665
1666
    /**
1667
     * Get Pagination HTML div.
1668
     *
1669
     * @param int    $pageCurrent
1670
     * @param int    $pageLength
1671
     * @param int    $pageTotal
1672
     * @param string $categoryCode
1673
     * @param string $action
1674
     * @param array  $fields
1675
     * @param array  $sortKeys
1676
     *
1677
     * @return string
1678
     */
1679
    public static function getCatalogPagination(
1680
        $pageCurrent,
1681
        $pageLength,
1682
        $pageTotal,
1683
        $categoryCode = '',
1684
        $action = '',
1685
        $fields = [],
1686
        $sortKeys = []
1687
    ) {
1688
        // Start empty html
1689
        $pageDiv = '';
1690
        $html = '';
1691
        $pageBottom = max(1, $pageCurrent - 3);
1692
        $pageTop = min($pageTotal, $pageCurrent + 3);
1693
1694
        if ($pageBottom > 1) {
1695
            $pageDiv .= self::getPageNumberItem(1, $pageLength);
1696
            if ($pageBottom > 2) {
1697
                $pageDiv .= self::getPageNumberItem(
1698
                    $pageBottom - 1,
1699
                    $pageLength,
1700
                    null,
1701
                    '...',
1702
                    $categoryCode,
1703
                    $action,
1704
                    $fields,
1705
                    $sortKeys
1706
                );
1707
            }
1708
        }
1709
1710
        // For each page add its page button to html
1711
        for ($i = $pageBottom; $i <= $pageTop; $i++) {
1712
            if ($i === $pageCurrent) {
1713
                $pageItemAttributes = ['class' => 'active'];
1714
            } else {
1715
                $pageItemAttributes = [];
1716
            }
1717
            $pageDiv .= self::getPageNumberItem(
1718
                $i,
1719
                $pageLength,
1720
                $pageItemAttributes,
1721
                '',
1722
                $categoryCode,
1723
                $action,
1724
                $fields,
1725
                $sortKeys
1726
            );
1727
        }
1728
1729
        // Check if current page is the last page
1730
        if ($pageTop < $pageTotal) {
1731
            if ($pageTop < ($pageTotal - 1)) {
1732
                $pageDiv .= self::getPageNumberItem(
1733
                    $pageTop + 1,
1734
                    $pageLength,
1735
                    null,
1736
                    '...',
1737
                    $categoryCode,
1738
                    $action,
1739
                    $fields,
1740
                    $sortKeys
1741
                );
1742
            }
1743
            $pageDiv .= self::getPageNumberItem(
1744
                $pageTotal,
1745
                $pageLength,
1746
                [],
1747
                '',
1748
                $categoryCode,
1749
                $action,
1750
                $fields,
1751
                $sortKeys
1752
            );
1753
        }
1754
1755
        // Complete pagination html
1756
        $pageDiv = Display::tag('ul', $pageDiv, ['class' => 'pagination']);
1757
        $html .= '<nav>'.$pageDiv.'</nav>';
1758
1759
        return $html;
1760
    }
1761
1762
    /**
1763
     * Get li HTML of page number.
1764
     *
1765
     * @param $pageNumber
1766
     * @param $pageLength
1767
     * @param array  $liAttributes
1768
     * @param string $content
1769
     * @param string $categoryCode
1770
     * @param string $action
1771
     * @param array  $fields
1772
     * @param array  $sortKeys
1773
     *
1774
     * @return string
1775
     */
1776
    public static function getPageNumberItem(
1777
        $pageNumber,
1778
        $pageLength,
1779
        $liAttributes = [],
1780
        $content = '',
1781
        $categoryCode = '',
1782
        $action = '',
1783
        $fields = [],
1784
        $sortKeys = []
1785
    ) {
1786
        // Get page URL
1787
        $url = self::getCatalogUrl($pageNumber, $pageLength, $categoryCode, $action, $fields, $sortKeys);
1788
1789
        // If is current page ('active' class) clear URL
1790
        if (isset($liAttributes) && is_array($liAttributes) && isset($liAttributes['class'])) {
1791
            if (strpos('active', $liAttributes['class']) !== false) {
1792
                $url = '';
1793
            }
1794
        }
1795
1796
        $content = !empty($content) ? $content : $pageNumber;
1797
1798
        return Display::tag(
1799
            'li',
1800
            Display::url(
1801
                $content,
1802
                $url
1803
            ),
1804
            $liAttributes
1805
        );
1806
    }
1807
1808
    /**
1809
     * Return URL to course catalog.
1810
     *
1811
     * @param int    $pageCurrent
1812
     * @param int    $pageLength
1813
     * @param string $categoryCode
1814
     * @param string $action
1815
     * @param array  $extraFields
1816
     * @param array  $sortKeys
1817
     *
1818
     * @return string
1819
     */
1820
    public static function getCatalogUrl(
1821
        $pageCurrent,
1822
        $pageLength,
1823
        $categoryCode = null,
1824
        $action = null,
1825
        $extraFields = [],
1826
        $sortKeys = []
1827
    ) {
1828
        $requestAction = isset($_REQUEST['action']) ? Security::remove_XSS($_REQUEST['action']) : '';
1829
        $action = isset($action) ? Security::remove_XSS($action) : $requestAction;
1830
        $searchTerm = isset($_REQUEST['search_term']) ? Security::remove_XSS($_REQUEST['search_term']) : '';
1831
        $keyword = isset($_REQUEST['keyword']) ? Security::remove_XSS($_REQUEST['keyword']) : '';
1832
        $searchTag = $_REQUEST['search_tag'] ?? '';
1833
1834
        if ($action === 'subscribe_user_with_password') {
1835
            $action = 'subscribe';
1836
        }
1837
1838
        $categoryCode = !empty($categoryCode) ? Security::remove_XSS($categoryCode) : 'ALL';
1839
1840
        // Start URL with params
1841
        $pageUrl = api_get_path(WEB_CODE_PATH).'auth/courses.php'.
1842
            '?action='.$action.
1843
            '&search_term='.$searchTerm.
1844
            '&keyword='.$keyword.
1845
            '&search_tag='.$searchTag.
1846
            '&category_code='.$categoryCode.
1847
            '&pageCurrent='.$pageCurrent.
1848
            '&pageLength='.$pageLength;
1849
1850
        if (!empty($extraFields)) {
1851
            $params = [];
1852
            foreach ($extraFields as $variable => $value) {
1853
                $params[Security::remove_XSS($variable)] = Security::remove_XSS($value);
1854
            }
1855
            if (!empty($params)) {
1856
                $pageUrl .= '&'.http_build_query($params);
1857
            }
1858
        }
1859
1860
        if (!empty($sortKeys)) {
1861
            foreach ($sortKeys as $sortKey) {
1862
                $pageUrl .= '&sortKeys%5B%5D='.Security::remove_XSS($sortKey);
1863
            }
1864
        }
1865
1866
        switch ($action) {
1867
            case 'subscribe':
1868
                // for search
1869
                $pageUrl .=
1870
                    '&sec_token='.Security::getTokenFromSession();
1871
                break;
1872
            case 'display_courses':
1873
            default:
1874
                break;
1875
        }
1876
1877
        return $pageUrl;
1878
    }
1879
1880
    public static function generateRedirectUrlAfterSubscription(string $coursePublicUrl): string
1881
    {
1882
        $settings = api_get_configuration_value('course_catalog_settings');
1883
1884
        $redirectAfterSubscription = 'course_home';
1885
1886
        if (!empty($settings) && isset($settings['redirect_after_subscription'])) {
1887
            $redirectAfterSubscription = $settings['redirect_after_subscription'];
1888
        }
1889
1890
        if ('course_home' !== $redirectAfterSubscription) {
1891
            return api_get_path(WEB_CODE_PATH).'auth/courses.php';
1892
        }
1893
1894
        if (api_get_configuration_value('catalog_course_subscription_in_user_s_session')) {
1895
            $user = api_get_user_entity(api_get_user_id());
1896
1897
            if ($user && $accesibleSessions = $user->getCurrentlyAccessibleSessions()) {
1898
                return $coursePublicUrl.'?id_session='.$accesibleSessions[0]->getId();
1899
            }
1900
        }
1901
1902
        return $coursePublicUrl;
1903
    }
1904
1905
    /**
1906
     * @throws Exception
1907
     */
1908
    public static function displayCoursesList(
1909
        string $action = '',
1910
        string $searchTerm = '',
1911
        string $categoryCode = '',
1912
        bool $returnHtml = false
1913
    ): ?string {
1914
        $settings = api_get_configuration_value('course_catalog_settings');
1915
1916
        $courseCatalogSettings = [
1917
            'info_url' => 'course_description_popup',
1918
            'title_url' => 'course_home',
1919
            'image_url' => 'course_about',
1920
        ];
1921
        // By default, all extra fields are shown (visible and filterable)
1922
        $extraFieldsInSearchForm = [];
1923
        $extraFieldsInCourseBlock = [];
1924
1925
        if (!empty($settings)) {
1926
            if (isset($settings['link_settings'])) {
1927
                $courseCatalogSettings = $settings['link_settings'];
1928
            }
1929
1930
            if (isset($settings['extra_fields_in_search_form'])) {
1931
                $extraFieldsInSearchForm = $settings['extra_fields_in_search_form'];
1932
            }
1933
1934
            if (isset($settings['extra_fields_in_course_block'])) {
1935
                $extraFieldsInCourseBlock = $settings['extra_fields_in_course_block'];
1936
            }
1937
        }
1938
1939
        $settings = CoursesAndSessionsCatalog::getCatalogSearchSettings();
1940
1941
        $form = new FormValidator('search', 'get', '', null, null, FormValidator::LAYOUT_GRID);
1942
        $form->addHidden('action', 'search_course');
1943
1944
        if (isset($settings['courses']) && true === $settings['courses']['by_title']) {
1945
            $form->addText('search_term', get_lang('Title'));
1946
        }
1947
1948
        $select = $form->addSelect(
1949
            'category_code',
1950
            get_lang('CourseCategories'),
1951
            [],
1952
            ['placeholder' => get_lang('SelectAnOption')]
1953
        );
1954
1955
        $defaults = [];
1956
        $listCategories = CoursesAndSessionsCatalog::getCourseCategoriesTree();
1957
1958
        foreach ($listCategories as $category) {
1959
            $countCourse = (int) $category['number_courses'];
1960
            if (empty($countCourse)) {
1961
                continue;
1962
            }
1963
1964
            $categoryCodeItem = Security::remove_XSS($category['code']);
1965
            $categoryName = Security::remove_XSS($category['name']);
1966
            $level = $category['level'];
1967
            $separate = '';
1968
            if ($level > 0) {
1969
                $separate = str_repeat('--', $level);
1970
            }
1971
            $select->addOption($separate.' '.$categoryName.' ('.$countCourse.')', $categoryCodeItem);
1972
        }
1973
1974
        $allowExtraFields = api_get_configuration_value('allow_course_extra_field_in_catalog');
1975
1976
        $jqueryReadyContent = '';
1977
        if ($allowExtraFields) {
1978
            $extraField = new ExtraFieldModel('course');
1979
            $returnParams = $extraField->addElements($form, null, [], true, false, $extraFieldsInSearchForm);
1980
            $jqueryReadyContent = $returnParams['jquery_ready_content'];
1981
        }
1982
1983
        $sortKeySelect = $form->addSelect(
1984
            'sortKeys',
1985
            get_lang('SortKeys'),
1986
            CoursesAndSessionsCatalog::courseSortOptions(),
1987
            ['multiple' => true]
1988
        );
1989
1990
        $sortKeys = isset($_REQUEST['sortKeys']) ? Security::remove_XSS($_REQUEST['sortKeys']) : '';
1991
        $defaults['sortKeys'] = $sortKeys;
1992
        $defaults['search_term'] = $searchTerm;
1993
        $defaults['category_code'] = $categoryCode;
1994
1995
        $conditions = [];
1996
        $fields = [];
1997
1998
        if ('display_random_courses' === $action) {
1999
            // Random value is used instead limit filter
2000
            $courses = CoursesAndSessionsCatalog::getCoursesInCategory(null, 12);
2001
            $countCoursesInCategory = count($courses);
2002
        } else {
2003
            $values = $_REQUEST;
2004
            if ($allowExtraFields) {
2005
                $extraResult = $extraField->processExtraFieldSearch($values, $form, 'course', 'AND');
2006
                $conditions = $extraResult['condition'];
2007
                $fields = $extraResult['fields'];
2008
                $defaults = $extraResult['defaults'];
2009
2010
                $defaults['sortKeys'] = $sortKeys;
2011
                $defaults['search_term'] = $searchTerm;
2012
                $defaults['category_code'] = $categoryCode;
2013
            }
2014
2015
            $courses = CoursesAndSessionsCatalog::searchAndSortCourses(
2016
                $categoryCode,
2017
                $searchTerm,
2018
                self::getLimitArray(),
2019
                true,
2020
                $conditions,
2021
                $sortKeySelect->getValue()
2022
            );
2023
            $countCoursesInCategory = CourseCategory::countCoursesInCategory(
2024
                $categoryCode,
2025
                $searchTerm,
2026
                true,
2027
                true,
2028
                $conditions
2029
            );
2030
        }
2031
2032
        $pageCurrent = isset($_GET['pageCurrent']) ? (int) $_GET['pageCurrent'] : 1;
2033
        $pageLength = isset($_GET['pageLength']) ? (int) $_GET['pageLength'] : CoursesAndSessionsCatalog::PAGE_LENGTH;
2034
        $pageTotal = (int) ceil($countCoursesInCategory / $pageLength);
2035
2036
        $url = CoursesAndSessionsCatalog::getCatalogUrl(1, $pageLength, 'ALL', 'search_course', $fields);
2037
        $urlNoExtraFields = CoursesAndSessionsCatalog::getCatalogUrl(1, $pageLength, 'ALL', 'search_course');
2038
        $urlNoCategory = CoursesAndSessionsCatalog::getCatalogUrl(1, $pageLength, '', 'search_course', $fields);
2039
        $urlNoCategory = str_replace('&category_code=ALL', '', $urlNoCategory);
2040
2041
        $form->setAttribute('action', $url);
2042
        $form->addButtonSearch(get_lang('Search'));
2043
        $form->setDefaults($defaults);
2044
2045
        $catalogPagination = '';
2046
2047
        if ($pageTotal > 1) {
2048
            $catalogPagination = CoursesAndSessionsCatalog::getCatalogPagination(
2049
                $pageCurrent,
2050
                $pageLength,
2051
                $pageTotal,
2052
                $categoryCode,
2053
                $action,
2054
                $fields,
2055
                $sortKeySelect->getValue()
2056
            );
2057
        }
2058
2059
        $stok = Security::get_token();
2060
2061
        $showTeacher = 'true' === api_get_setting('display_teacher_in_courselist');
2062
        $ajax_url = api_get_path(WEB_AJAX_PATH).'course.ajax.php?a=add_course_vote';
2063
        $user_id = api_get_user_id();
2064
        $categoryListFromDatabase = CourseCategory::getAllCategories();
2065
2066
        $categoryList = [];
2067
        if (!empty($categoryListFromDatabase)) {
2068
            foreach ($categoryListFromDatabase as $categoryItem) {
2069
                $categoryList[$categoryItem['code']] = $categoryItem['name'];
2070
            }
2071
        }
2072
2073
        $courseUrl = api_get_path(WEB_COURSE_PATH);
2074
        $hideRating = api_get_configuration_value('hide_course_rating');
2075
2076
        if (!empty($courses)) {
2077
            foreach ($courses as &$course) {
2078
                $courseId = $course['real_id'];
2079
                if (COURSE_VISIBILITY_HIDDEN == $course['visibility']) {
2080
                    continue;
2081
                }
2082
2083
                $aboutPage = api_get_path(WEB_PATH).'course/'.$course['real_id'].'/about';
2084
                $settingsUrl = [
2085
                    'course_description_popup' => api_get_path(WEB_CODE_PATH).'inc/ajax/course_home.ajax.php?a=show_course_information&code='.$course['code'],
2086
                    'course_about' => $aboutPage,
2087
                    'course_home' => $courseUrl.$course['directory'].'/index.php?id_session=0',
2088
                ];
2089
2090
                $infoUrl = $settingsUrl[$courseCatalogSettings['info_url']];
2091
                $course['title_url'] = $settingsUrl[$courseCatalogSettings['title_url']];
2092
                $course['image_url'] = $settingsUrl[$courseCatalogSettings['image_url']];
2093
2094
                $userRegisteredInCourse = CourseManager::is_user_subscribed_in_course($user_id, $course['code']);
2095
                $userRegisteredInCourseAsTeacher = CourseManager::is_course_teacher($user_id, $course['code']);
2096
2097
                $course_private = COURSE_VISIBILITY_REGISTERED == $course['visibility'];
2098
                $courseClosed = COURSE_VISIBILITY_CLOSED == $course['visibility'];
2099
                $course_subscribe_allowed = 1 == $course['subscribe'];
2100
                $course_unsubscribe_allowed = 1 == $course['unsubscribe'];
2101
2102
                // display the course bloc
2103
                $course['category_title'] = '';
2104
2105
                if (!empty($course['category_code'])) {
2106
                    $course['category_title'] = $categoryList[$course['category_code']] ?? '';
2107
                    $course['category_code_link'] = $urlNoCategory.'&category_code='.$course['category_code'];
2108
                }
2109
2110
                // Display thumbnail
2111
                $course['thumbnail'] = CoursesAndSessionsCatalog::returnThumbnail($course);
2112
                $course['description_button'] = CourseManager::returnDescriptionButton($course, $infoUrl);
2113
                $subscribeButton = CoursesAndSessionsCatalog::return_register_button(
2114
                    $course,
2115
                    $stok,
2116
                    $categoryCode,
2117
                    $searchTerm
2118
                );
2119
2120
                // Start buy course validation
2121
                // display the course price and buy button if the buycourses plugin is enabled and this course is configured
2122
                $plugin = BuyCoursesPlugin::create();
2123
                $isThisCourseInSale = $plugin->buyCoursesForGridCatalogValidator(
2124
                    $courseId,
2125
                    BuyCoursesPlugin::PRODUCT_TYPE_COURSE
2126
                );
2127
2128
                $separator = '';
2129
2130
                if ($isThisCourseInSale) {
2131
                    // set the Price label
2132
                    $separator = $isThisCourseInSale['html'];
2133
                    // set the Buy button instead register.
2134
                    if ($isThisCourseInSale['verificator']) {
2135
                        $subscribeButton = $plugin->returnBuyCourseButton(
2136
                            $courseId,
2137
                            BuyCoursesPlugin::PRODUCT_TYPE_COURSE
2138
                        );
2139
                    }
2140
                }
2141
2142
                $course['rating'] = '';
2143
2144
                if ($hideRating === false) {
2145
                    $rating = Display::return_rating_system(
2146
                        'star_'.$course['real_id'],
2147
                        $ajax_url.'&course_id='.$course['real_id'],
2148
                        $course['point_info']
2149
                    );
2150
                    $course['rating'] = '<div class="ranking">'.$rating.'</div>';
2151
                }
2152
2153
                if ($showTeacher) {
2154
                    $course['teacher_info'] = CoursesAndSessionsCatalog::return_teacher($course);
2155
                }
2156
2157
                // display button line
2158
                $course['buy_course'] = $separator;
2159
                $course['extra_data'] = '';
2160
2161
                if ($allowExtraFields) {
2162
                    $course['extra_data'] = $extraField->getDataAndFormattedValues(
2163
                        $courseId,
2164
                        true,
2165
                        $extraFieldsInCourseBlock
2166
                    );
2167
                }
2168
2169
                // if user registered as student
2170
                if ($userRegisteredInCourse) {
2171
                    $course['already_registered_formatted'] = Display::url(
2172
                        Display::returnFontAwesomeIcon('external-link').PHP_EOL.
2173
                        get_lang('GoToCourse'),
2174
                        $courseUrl.$course['directory'].'/index.php?id_session=0',
2175
                        ['class' => 'btn btn-primary btn-sm']
2176
                    );
2177
2178
                    if (!$courseClosed && $course_unsubscribe_allowed
2179
                        && false === $userRegisteredInCourseAsTeacher
2180
                    ) {
2181
                        $course['unregister_formatted'] = CoursesAndSessionsCatalog::return_unregister_button(
2182
                            $course,
2183
                            $stok,
2184
                            $searchTerm,
2185
                            $categoryCode
2186
                        );
2187
                    }
2188
                } elseif ($userRegisteredInCourseAsTeacher) {
2189
                    // if user registered as teacher
2190
                    // Updated teacher cannot unregister himself.
2191
                    /*if ($course_unsubscribe_allowed) {
2192
                        $course['unregister_formatted'] = CoursesAndSessionsCatalog::return_unregister_button(
2193
                            $course,
2194
                            $stok,
2195
                            $searchTerm,
2196
                            $categoryCode
2197
                        );
2198
                    }*/
2199
                } else {
2200
                    // if user not registered in the course
2201
                    if (!$courseClosed && !$course_private && $course_subscribe_allowed) {
2202
                        $course['subscribe_formatted'] = $subscribeButton;
2203
                    }
2204
                }
2205
            }
2206
        } else {
2207
            if (!isset($_REQUEST['subscribe_user_with_password']) &&
2208
                !isset($_REQUEST['subscribe_course'])
2209
            ) {
2210
                Display::addFlash(Display::return_message(get_lang('NoResults'), 'warning'));
2211
            }
2212
        }
2213
2214
        if (api_is_course_admin()) {
2215
            foreach ($courses as &$course) {
2216
                $course['admin_url'] = api_get_path(WEB_CODE_PATH).'/admin/course_list.php?keyword='.$course['code'];
2217
            }
2218
        }
2219
2220
        $toolTitle = get_lang('CourseCatalog');
2221
2222
        $template = new Template($toolTitle, true, true, false, false, false);
2223
        $template->assign('tabs', CoursesAndSessionsCatalog::getTabList());
2224
        $template->assign('frm_filter', $form->returnForm());
2225
        $template->assign('courses', $courses);
2226
        $template->assign(
2227
            'total_number_of_courses',
2228
            CoursesAndSessionsCatalog::countAvailableCoursesToShowInCatalog(
2229
                api_get_current_access_url_id()
2230
            )
2231
        );
2232
        $template->assign('total_number_of_matching_courses', $countCoursesInCategory);
2233
        $template->assign('catalog_url_no_extra_fields', $urlNoExtraFields);
2234
        $template->assign('pagination', $catalogPagination);
2235
        $template->assign('jquery_ready_content', $jqueryReadyContent);
2236
2237
        $templateContent = $template->fetch(
2238
            $template->get_template('catalog/course_catalog.tpl')
2239
        );
2240
2241
        if ($returnHtml) {
2242
            return $templateContent;
2243
        }
2244
2245
        $template->assign('content', $templateContent);
2246
        $template->display_one_col_template();
2247
2248
        return null;
2249
    }
2250
2251
    public static function userCanView(): bool
2252
    {
2253
        // For students
2254
        $userCanViewPage = true;
2255
2256
        if ('false' === api_get_setting('allow_students_to_browse_courses')) {
2257
            $userCanViewPage = false;
2258
        }
2259
2260
        //For teachers/admins
2261
        if (api_is_platform_admin() || api_is_course_admin() || api_is_allowed_to_create_course()) {
2262
            $userCanViewPage = true;
2263
        }
2264
2265
        return $userCanViewPage;
2266
    }
2267
}
2268