Passed
Push — master ( 65d552...4599b6 )
by Angel Fernando Quiroz
10:41
created

CoursesAndSessionsCatalog::getPageNumberItem()   A

Complexity

Conditions 6
Paths 6

Size

Total Lines 29
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
eloc 11
nc 6
nop 8
dl 0
loc 29
rs 9.2222
c 0
b 0
f 0

How to fix   Many Parameters   

Many Parameters

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

There are several approaches to avoid long parameter lists:

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