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