Passed
Push — 1.11.x ( 234566...95de4c )
by Julito
13:47 queued 01:32
created

getRegisteredInSessionButton()   B

Complexity

Conditions 7
Paths 26

Size

Total Lines 74
Code Lines 46

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 46
c 0
b 0
f 0
nc 26
nop 5
dl 0
loc 74
rs 8.2448

How to fix   Long Method   

Long Method

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

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

Commonly applied refactorings include:

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