Passed
Push — master ( 34bdad...b152c5 )
by Julito
20:20
created

Display::panel()   B

Complexity

Conditions 7
Paths 64

Size

Total Lines 33
Code Lines 16

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 7
eloc 16
nc 64
nop 8
dl 0
loc 33
rs 8.8333
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;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, ExtraField. Consider defining an alias.

Let?s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let?s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
5
use Chamilo\CoreBundle\Framework\Container;
6
use ChamiloSession as Session;
7
use Symfony\Component\HttpFoundation\Response;
8
9
/**
10
 * Class Display
11
 * Contains several public functions dealing with the display of
12
 * table data, messages, help topics, ...
13
 *
14
 * Include/require it in your code to use its public functionality.
15
 * There are also several display public functions in the main api library.
16
 *
17
 * All public functions static public functions inside a class called Display,
18
 * so you use them like this: e.g.
19
 * Display::return_message($message)
20
 *
21
 * @package chamilo.library
22
 */
23
class Display
24
{
25
    /** @var Template */
26
    public static $global_template;
27
    public static $preview_style = null;
28
29
    /**
30
     * Constructor.
31
     */
32
    public function __construct()
33
    {
34
    }
35
36
    /**
37
     * @return array
38
     */
39
    public static function toolList()
40
    {
41
        return [
42
            'group',
43
            'work',
44
            'glossary',
45
            'forum',
46
            'course_description',
47
            'gradebook',
48
            'attendance',
49
            'course_progress',
50
            'notebook',
51
        ];
52
    }
53
54
    /**
55
     * Displays the page header.
56
     *
57
     * @param string The name of the page (will be showed in the page title)
58
     * @param string Optional help file name
59
     * @param string $page_header
60
     */
61
    public static function display_header(
62
        $tool_name = '',
0 ignored issues
show
Unused Code introduced by
The parameter $tool_name is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

62
        /** @scrutinizer ignore-unused */ $tool_name = '',

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
63
        $help = null,
0 ignored issues
show
Unused Code introduced by
The parameter $help is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

63
        /** @scrutinizer ignore-unused */ $help = null,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
64
        $page_header = null
0 ignored issues
show
Unused Code introduced by
The parameter $page_header is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

64
        /** @scrutinizer ignore-unused */ $page_header = null

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
65
    ) {
66
        ob_start();
67
68
        return true;
69
70
        $origin = api_get_origin();
0 ignored issues
show
Unused Code introduced by
$origin = api_get_origin() is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
71
        $showHeader = true;
72
        if (isset($origin) && $origin == 'learnpath') {
73
            $showHeader = false;
74
        }
75
76
        self::$global_template = new Template($tool_name, $showHeader, $showHeader);
77
78
        // Fixing tools with any help it takes xxx part of main/xxx/index.php
79
        if (empty($help)) {
80
            $currentURL = api_get_self();
81
            preg_match('/main\/([^*\/]+)/', $currentURL, $matches);
82
            $toolList = self::toolList();
83
            if (!empty($matches)) {
84
                foreach ($matches as $match) {
85
                    if (in_array($match, $toolList)) {
86
                        $help = explode('_', $match);
87
                        $help = array_map('ucfirst', $help);
88
                        $help = implode('', $help);
89
                        break;
90
                    }
91
                }
92
            }
93
        }
94
95
        self::$global_template->setHelp($help);
96
97
        if (!empty(self::$preview_style)) {
98
            self::$global_template->preview_theme = self::$preview_style;
99
            self::$global_template->set_system_parameters();
100
            self::$global_template->setCssFiles();
101
            self::$global_template->set_js_files();
102
            self::$global_template->setCssCustomFiles();
103
        }
104
105
        if (!empty($page_header)) {
106
            self::$global_template->assign('header', $page_header);
107
        }
108
109
        echo self::$global_template->show_header_template();
110
    }
111
112
    /**
113
     * Displays the reduced page header (without banner).
114
     */
115
    public static function display_reduced_header()
116
    {
117
        global $show_learnpath, $tool_name;
118
        self::$global_template = new Template(
119
            $tool_name,
120
            false,
121
            false,
122
            $show_learnpath
123
        );
124
        echo self::$global_template->show_header_template();
125
    }
126
127
    /**
128
     * Display no header.
129
     */
130
    public static function display_no_header()
131
    {
132
        global $tool_name, $show_learnpath;
133
        $disable_js_and_css_files = true;
134
        self::$global_template = new Template(
135
            $tool_name,
136
            false,
137
            false,
138
            $show_learnpath
139
        );
140
    }
141
142
    /**
143
     * Display the page footer.
144
     */
145
    public static function display_footer()
146
    {
147
        $contents = ob_get_contents();
148
        ob_end_clean();
149
        $tpl = '@ChamiloTheme/Layout/layout_one_col.html.twig';
150
        $response = new Response();
151
        $params['content'] = $contents;
0 ignored issues
show
Comprehensibility Best Practice introduced by
$params was never initialized. Although not strictly required by PHP, it is generally a good practice to add $params = array(); before regardless.
Loading history...
152
        global $interbreadcrumb, $htmlHeadXtra;
153
        $params['legacy_javascript'] = $htmlHeadXtra;
154
        $params['legacy_breadcrumb'] = $interbreadcrumb;
155
156
        $flash = Display::getFlashToString();
157
        Display::cleanFlashMessages();
158
        $params['flash_messages'] = $flash;
159
160
        $content = Container::getTemplating()->render($tpl, $params);
161
        $response->setContent($content);
162
        $response->send();
163
        exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
164
    }
165
166
    /**
167
     * Display the page footer.
168
     */
169
    public static function display_reduced_footer()
170
    {
171
        echo self::$global_template->show_footer_js_template();
172
        echo '</body></html>';
173
    }
174
175
    /**
176
     * Displays the tool introduction of a tool.
177
     *
178
     * @author Patrick Cool <[email protected]>, Ghent University
179
     *
180
     * @param string $tool          these are the constants that are used for indicating the tools
181
     * @param array  $editor_config Optional configuration settings for the online editor.
182
     *                              return: $tool return a string array list with the "define" in main_api.lib
183
     *
184
     * @return string html code for adding an introduction
185
     */
186
    public static function display_introduction_section(
187
        $tool,
188
        $editor_config = null
189
    ) {
190
        echo self::return_introduction_section($tool, $editor_config);
0 ignored issues
show
Bug introduced by
Are you sure the usage of self::return_introductio...($tool, $editor_config) targeting Display::return_introduction_section() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
191
    }
192
193
    /**
194
     * @param string $tool
195
     * @param array  $editor_config
196
     */
197
    public static function return_introduction_section(
198
        $tool,
199
        $editor_config = null
200
    ) {
201
        $moduleId = $tool;
202
        if (api_get_setting('enable_tool_introduction') == 'true' || $tool == TOOL_COURSE_HOMEPAGE) {
203
            $introduction_section = null;
204
            require api_get_path(SYS_INC_PATH).'introductionSection.inc.php';
205
206
            return $introduction_section;
207
        }
208
    }
209
210
    /**
211
     * Displays a table.
212
     *
213
     * @param array $header          Titles for the table header
214
     *                               each item in this array can contain 3 values
215
     *                               - 1st element: the column title
216
     *                               - 2nd element: true or false (column sortable?)
217
     *                               - 3th element: additional attributes for
218
     *                               th-tag (eg for column-width)
219
     *                               - 4the element: additional attributes for the td-tags
220
     * @param array $content         2D-array with the tables content
221
     * @param array $sorting_options Keys are:
222
     *                               'column' = The column to use as sort-key
223
     *                               'direction' = SORT_ASC or SORT_DESC
224
     * @param array $paging_options  Keys are:
225
     *                               'per_page_default' = items per page when switching from
226
     *                               full-    list to per-page-view
227
     *                               'per_page' = number of items to show per page
228
     *                               'page_nr' = The page to display
229
     * @param array $query_vars      Additional variables to add in the query-string
230
     * @param string The style that the table will show. You can set 'table' or 'grid'
231
     *
232
     * @author [email protected]
233
     */
234
    public static function display_sortable_table(
235
        $header,
236
        $content,
237
        $sorting_options = [],
238
        $paging_options = [],
239
        $query_vars = null,
240
        $form_actions = [],
241
        $style = 'table'
242
    ) {
243
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
244
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
245
        $table = new SortableTableFromArray($content, $column, $default_items_per_page);
246
        if (is_array($query_vars)) {
247
            $table->set_additional_parameters($query_vars);
248
        }
249
        if ($style == 'table') {
250
            if (is_array($header) && count($header) > 0) {
251
                foreach ($header as $index => $header_item) {
252
                    $table->set_header(
253
                        $index,
254
                        isset($header_item[0]) ? $header_item[0] : null,
255
                        isset($header_item[1]) ? $header_item[1] : null,
256
                        isset($header_item[2]) ? $header_item[2] : null,
257
                        isset($header_item[3]) ? $header_item[3] : null
258
                    );
259
                }
260
            }
261
            $table->set_form_actions($form_actions);
262
            $table->display();
263
        } else {
264
            $table->display_grid();
265
        }
266
    }
267
268
    /**
269
     * Returns an HTML table with sortable column (through complete page refresh).
270
     *
271
     * @param array  $header
272
     * @param array  $content         Array of row arrays
273
     * @param array  $sorting_options
274
     * @param array  $paging_options
275
     * @param array  $query_vars
276
     * @param array  $form_actions
277
     * @param string $style
278
     *
279
     * @return string HTML string for array
280
     */
281
    public static function return_sortable_table(
282
        $header,
283
        $content,
284
        $sorting_options = [],
285
        $paging_options = [],
286
        $query_vars = null,
287
        $form_actions = [],
288
        $style = 'table'
289
    ) {
290
        ob_start();
291
        self::display_sortable_table(
292
            $header,
293
            $content,
294
            $sorting_options,
295
            $paging_options,
296
            $query_vars,
297
            $form_actions,
298
            $style
299
        );
300
        $content = ob_get_contents();
301
        ob_end_clean();
302
303
        return $content;
304
    }
305
306
    /**
307
     * Shows a nice grid.
308
     *
309
     * @param string grid name (important to create css)
310
     * @param array header content
311
     * @param array array with the information to show
312
     * @param array $paging_options Keys are:
313
     *                              'per_page_default' = items per page when switching from
314
     *                              full-    list to per-page-view
315
     *                              'per_page' = number of items to show per page
316
     *                              'page_nr' = The page to display
317
     *                              'hide_navigation' =  true to hide the navigation
318
     * @param array $query_vars     Additional variables to add in the query-string
319
     * @param array $form           actions Additional variables to add in the query-string
320
     * @param mixed An array with bool values to know which columns show.
321
     * i.e: $visibility_options= array(true, false) we will only show the first column
322
     *                Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
323
     */
324
    public static function display_sortable_grid(
325
        $name,
326
        $header,
327
        $content,
328
        $paging_options = [],
329
        $query_vars = null,
330
        $form_actions = [],
331
        $visibility_options = true,
332
        $sort_data = true,
333
        $grid_class = []
334
    ) {
335
        echo self::return_sortable_grid(
336
            $name,
337
            $header,
338
            $content,
339
            $paging_options,
340
            $query_vars,
341
            $form_actions,
342
            $visibility_options,
343
            $sort_data,
344
            $grid_class
345
        );
346
    }
347
348
    /**
349
     * Gets a nice grid in html string.
350
     *
351
     * @param string grid name (important to create css)
352
     * @param array header content
353
     * @param array array with the information to show
354
     * @param array $paging_options Keys are:
355
     *                              'per_page_default' = items per page when switching from
356
     *                              full-    list to per-page-view
357
     *                              'per_page' = number of items to show per page
358
     *                              'page_nr' = The page to display
359
     *                              'hide_navigation' =  true to hide the navigation
360
     * @param array $query_vars     Additional variables to add in the query-string
361
     * @param array $form           actions Additional variables to add in the query-string
362
     * @param mixed An array with bool values to know which columns show. i.e:
363
     *  $visibility_options= array(true, false) we will only show the first column
364
     *    Can be also only a bool value. TRUE: show all columns, FALSE: show nothing
365
     * @param bool  true for sorting data or false otherwise
366
     * @param array grid classes
367
     *
368
     * @return string html grid
369
     */
370
    public static function return_sortable_grid(
371
        $name,
372
        $header,
0 ignored issues
show
Unused Code introduced by
The parameter $header is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

372
        /** @scrutinizer ignore-unused */ $header,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
373
        $content,
374
        $paging_options = [],
375
        $query_vars = null,
376
        $form_actions = [],
0 ignored issues
show
Unused Code introduced by
The parameter $form_actions is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

376
        /** @scrutinizer ignore-unused */ $form_actions = [],

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
377
        $visibility_options = true,
378
        $sort_data = true,
379
        $grid_class = [],
380
        $elementCount = 0
381
    ) {
382
        $column = 0;
383
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
384
        $table = new SortableTableFromArray($content, $column, $default_items_per_page, $name);
385
        $table->total_number_of_items = intval($elementCount);
386
        if (is_array($query_vars)) {
387
            $table->set_additional_parameters($query_vars);
388
        }
389
390
        return $table->display_simple_grid(
391
            $visibility_options,
392
            $paging_options['hide_navigation'],
393
            $default_items_per_page,
394
            $sort_data,
395
            $grid_class
396
        );
397
    }
398
399
    /**
400
     * Displays a table with a special configuration.
401
     *
402
     * @param array $header          Titles for the table header
403
     *                               each item in this array can contain 3 values
404
     *                               - 1st element: the column title
405
     *                               - 2nd element: true or false (column sortable?)
406
     *                               - 3th element: additional attributes for th-tag (eg for column-width)
407
     *                               - 4the element: additional attributes for the td-tags
408
     * @param array $content         2D-array with the tables content
409
     * @param array $sorting_options Keys are:
410
     *                               'column' = The column to use as sort-key
411
     *                               'direction' = SORT_ASC or SORT_DESC
412
     * @param array $paging_options  Keys are:
413
     *                               'per_page_default' = items per page when switching from full list to per-page-view
414
     *                               'per_page' = number of items to show per page
415
     *                               'page_nr' = The page to display
416
     * @param array $query_vars      Additional variables to add in the query-string
417
     * @param array $column_show     Array of binaries 1= show columns 0. hide a column
418
     * @param array $column_order    An array of integers that let us decide how the columns are going to be sort.
419
     *                               i.e:  $column_order=array('1''4','3','4'); The 2nd column will be order like the
420
     *                               4th column
421
     * @param array $form_actions    Set optional forms actions
422
     *
423
     * @author Julio Montoya
424
     */
425
    public static function display_sortable_config_table(
426
        $table_name,
427
        $header,
428
        $content,
429
        $sorting_options = [],
430
        $paging_options = [],
431
        $query_vars = null,
432
        $column_show = [],
433
        $column_order = [],
434
        $form_actions = []
435
    ) {
436
        $column = isset($sorting_options['column']) ? $sorting_options['column'] : 0;
437
        $default_items_per_page = isset($paging_options['per_page']) ? $paging_options['per_page'] : 20;
438
439
        $table = new SortableTableFromArrayConfig(
440
            $content,
441
            $column,
442
            $default_items_per_page,
443
            $table_name,
444
            $column_show,
445
            $column_order
446
        );
447
448
        if (is_array($query_vars)) {
449
            $table->set_additional_parameters($query_vars);
450
        }
451
        // Show or hide the columns header
452
        if (is_array($column_show)) {
453
            for ($i = 0; $i < count($column_show); $i++) {
0 ignored issues
show
Performance Best Practice introduced by
It seems like you are calling the size function count() as part of the test condition. You might want to compute the size beforehand, and not on each iteration.

If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration:

for ($i=0; $i<count($array); $i++) { // calls count() on each iteration
}

// Better
for ($i=0, $c=count($array); $i<$c; $i++) { // calls count() just once
}
Loading history...
454
                if (!empty($column_show[$i])) {
455
                    $val0 = isset($header[$i][0]) ? $header[$i][0] : null;
456
                    $val1 = isset($header[$i][1]) ? $header[$i][1] : null;
457
                    $val2 = isset($header[$i][2]) ? $header[$i][2] : null;
458
                    $val3 = isset($header[$i][3]) ? $header[$i][3] : null;
459
                    $table->set_header($i, $val0, $val1, $val2, $val3);
460
                }
461
            }
462
        }
463
        $table->set_form_actions($form_actions);
464
        $table->display();
465
    }
466
467
    /**
468
     * Displays a normal message. It is recommended to use this public function
469
     * to display any normal information messages.
470
     *
471
     * @param string $message
472
     * @param bool   $filter      (true) or not (false)
473
     * @param bool   $returnValue
474
     *
475
     * @deprecated Use <code>Display::addFlash(Display::return_message($message, 'normal'));</code>
476
     *  Or <code>echo Display::return_message($message, 'normal')</code>
477
     */
478
    public static function display_normal_message(
479
        $message,
480
        $filter = true,
481
        $returnValue = false
482
    ) {
483
        $message = self::return_message($message, 'normal', $filter);
484
        if ($returnValue) {
485
            return $message;
486
        } else {
487
            echo $message;
488
        }
489
    }
490
491
    /**
492
     * Displays an warning message. Use this if you want to draw attention to something
493
     * This can also be used for instance with the hint in the exercises.
494
     *
495
     * @deprecated use Display::addFlash(Display::return_message($message, 'warning'));
496
     */
497
    public static function display_warning_message(
498
        $message,
499
        $filter = true,
500
        $returnValue = false
501
    ) {
502
        $message = self::return_message($message, 'warning', $filter);
503
        if ($returnValue) {
504
            return $message;
505
        } else {
506
            echo $message;
507
        }
508
    }
509
510
    /**
511
     * Displays an confirmation message. Use this if something has been done successfully.
512
     *
513
     * @param bool    Filter (true) or not (false)
514
     *
515
     * @deprecated use Display::addFlash(Display::return_message($message, 'confirm'));
516
     */
517
    public static function display_confirmation_message(
518
        $message,
519
        $filter = true,
520
        $returnValue = false
521
    ) {
522
        $message = self::return_message($message, 'confirm', $filter);
523
        if ($returnValue) {
524
            return $message;
525
        } else {
526
            echo $message;
527
        }
528
    }
529
530
    /**
531
     * Displays an error message. It is recommended to use this public function if an error occurs.
532
     *
533
     * @param string $message - include any additional html
534
     *                        tags if you need them
535
     * @param bool    Filter (true) or not (false)
536
     *
537
     * @deprecated use Display::addFlash(Display::return_message($message, 'error'));
538
     */
539
    public static function display_error_message(
540
        $message,
541
        $filter = true,
542
        $returnValue = false
543
    ) {
544
        $message = self::return_message($message, 'error', $filter);
545
        if ($returnValue) {
546
            return $message;
547
        } else {
548
            echo $message;
549
        }
550
    }
551
552
    /**
553
     * @param string $message
554
     * @param string $type
555
     * @param bool   $filter
556
     */
557
    public static function return_message_and_translate(
558
        $message,
559
        $type = 'normal',
560
        $filter = true
561
    ) {
562
        $message = get_lang($message);
563
        echo self::return_message($message, $type, $filter);
564
    }
565
566
    /**
567
     * Returns a div html string with.
568
     *
569
     * @param string $message
570
     * @param string $type    Example: confirm, normal, warning, error
571
     * @param bool   $filter  Whether to XSS-filter or not
572
     *
573
     * @return string Message wrapped into an HTML div
574
     */
575
    public static function return_message(
576
        $message,
577
        $type = 'normal',
578
        $filter = true
579
    ) {
580
        if (empty($message)) {
581
            return '';
582
        }
583
584
        if ($filter) {
585
            $message = api_htmlentities(
586
                $message,
587
                ENT_QUOTES,
588
                api_is_xml_http_request() ? 'UTF-8' : api_get_system_encoding()
589
            );
590
        }
591
592
        $class = '';
593
        switch ($type) {
594
            case 'warning':
595
                $class .= 'alert alert-warning';
596
                break;
597
            case 'error':
598
                $class .= 'alert alert-danger';
599
                break;
600
            case 'confirmation':
601
            case 'confirm':
602
            case 'success':
603
                $class .= 'alert alert-success';
604
                break;
605
            case 'normal':
606
            default:
607
                $class .= 'alert alert-info';
608
        }
609
610
        return self::div($message, ['class' => $class]);
611
    }
612
613
    /**
614
     * Returns an encrypted mailto hyperlink.
615
     *
616
     * @param string  e-mail
0 ignored issues
show
Documentation Bug introduced by
The doc comment e-mail at position 0 could not be parsed: Unknown type name 'e-mail' at position 0 in e-mail.
Loading history...
617
     * @param string  clickable text
618
     * @param string  optional, class from stylesheet
619
     *
620
     * @return string encrypted mailto hyperlink
621
     */
622
    public static function encrypted_mailto_link(
623
        $email,
624
        $clickable_text = null,
625
        $style_class = ''
626
    ) {
627
        if (is_null($clickable_text)) {
628
            $clickable_text = $email;
629
        }
630
        // "mailto:" already present?
631
        if (substr($email, 0, 7) != 'mailto:') {
632
            $email = 'mailto:'.$email;
633
        }
634
        // Class (stylesheet) defined?
635
        if ($style_class != '') {
636
            $style_class = ' class="'.$style_class.'"';
637
        }
638
        // Encrypt email
639
        $hmail = '';
640
        for ($i = 0; $i < strlen($email); $i++) {
641
            $hmail .= '&#'.ord($email[
642
            $i]).';';
643
        }
644
        $hclickable_text = null;
645
        // Encrypt clickable text if @ is present
646
        if (strpos($clickable_text, '@')) {
647
            for ($i = 0; $i < strlen($clickable_text); $i++) {
648
                $hclickable_text .= '&#'.ord($clickable_text[
649
                $i]).';';
650
            }
651
        } else {
652
            $hclickable_text = @htmlspecialchars(
653
                $clickable_text,
654
                ENT_QUOTES,
655
                api_get_system_encoding()
656
            );
657
        }
658
        // Return encrypted mailto hyperlink
659
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$hclickable_text.'</a>';
660
    }
661
662
    /**
663
     * Returns an mailto icon hyperlink.
664
     *
665
     * @param string  e-mail
0 ignored issues
show
Documentation Bug introduced by
The doc comment e-mail at position 0 could not be parsed: Unknown type name 'e-mail' at position 0 in e-mail.
Loading history...
666
     * @param string  icon source file from the icon lib
667
     * @param int  icon size from icon lib
668
     * @param string  optional, class from stylesheet
669
     *
670
     * @return string encrypted mailto hyperlink
671
     */
672
    public static function icon_mailto_link(
673
        $email,
674
        $icon_file = "mail.png",
675
        $icon_size = 22,
676
        $style_class = ''
677
    ) {
678
        // "mailto:" already present?
679
        if (substr($email, 0, 7) != 'mailto:') {
680
            $email = 'mailto:'.$email;
681
        }
682
        // Class (stylesheet) defined?
683
        if ($style_class != '') {
684
            $style_class = ' class="'.$style_class.'"';
685
        }
686
        // Encrypt email
687
        $hmail = '';
688
        for ($i = 0; $i < strlen($email); $i++) {
689
            $hmail .= '&#'.ord($email[
690
            $i]).';';
691
        }
692
        // icon html code
693
        $icon_html_source = self::return_icon(
694
            $icon_file,
695
            $hmail,
696
            '',
697
            $icon_size
698
        );
699
        // Return encrypted mailto hyperlink
700
701
        return '<a href="'.$hmail.'"'.$style_class.' class="clickable_email_link">'.$icon_html_source.'</a>';
702
    }
703
704
    /**
705
     * Prints an <option>-list with all letters (A-Z).
706
     *
707
     * @param string $selected_letter The letter that should be selected
708
     *
709
     * @todo This is English language specific implementation.
710
     * It should be adapted for the other languages.
711
     *
712
     * @return string
713
     */
714
    public static function get_alphabet_options($selectedLetter = '')
715
    {
716
        $result = '';
717
        for ($i = 65; $i <= 90; $i++) {
718
            $letter = chr($i);
719
            $result .= '<option value="'.$letter.'"';
720
            if ($selectedLetter == $letter) {
721
                $result .= ' selected="selected"';
722
            }
723
            $result .= '>'.$letter.'</option>';
724
        }
725
726
        return $result;
727
    }
728
729
    /**
730
     * Get the options withing a select box within the given values.
731
     *
732
     * @param int   Min value
733
     * @param int   Max value
734
     * @param int   Default value
735
     *
736
     * @return string HTML select options
737
     */
738
    public static function get_numeric_options($min, $max, $selected_num = 0)
739
    {
740
        $result = '';
741
        for ($i = $min; $i <= $max; $i++) {
742
            $result .= '<option value="'.$i.'"';
743
            if (is_int($selected_num)) {
744
                if ($selected_num == $i) {
745
                    $result .= ' selected="selected"';
746
                }
747
            }
748
            $result .= '>'.$i.'</option>';
749
        }
750
751
        return $result;
752
    }
753
754
    /**
755
     * This public function displays an icon.
756
     *
757
     * @param string   The filename of the file (in the main/img/ folder
758
     * @param string   The alt text (probably a language variable)
759
     * @param array    additional attributes (for instance height, width, onclick, ...)
760
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
761
     */
762
    public static function display_icon(
763
        $image,
764
        $alt_text = '',
765
        $additional_attributes = [],
766
        $size = null
767
    ) {
768
        echo self::return_icon($image, $alt_text, $additional_attributes, $size);
769
    }
770
771
    /**
772
     * Gets the path of an icon.
773
     *
774
     * @param string $icon
775
     * @param int    $size
776
     *
777
     * @return string
778
     */
779
    public static function returnIconPath($icon, $size = ICON_SIZE_SMALL)
780
    {
781
        return self::return_icon($icon, null, null, $size, null, true, false);
782
    }
783
784
    /**
785
     * This public function returns the htmlcode for an icon.
786
     *
787
     * @param string   The filename of the file (in the main/img/ folder
788
     * @param string   The alt text (probably a language variable)
789
     * @param array    Additional attributes (for instance height, width, onclick, ...)
790
     * @param int  The wanted width of the icon (to be looked for in the corresponding img/icons/ folder)
791
     *
792
     * @return string An HTML string of the right <img> tag
793
     *
794
     * @author Patrick Cool <[email protected]>, Ghent University 2006
795
     * @author Julio Montoya 2010 Function improved, adding image constants
796
     * @author Yannick Warnier 2011 Added size handler
797
     *
798
     * @version Feb 2011
799
     */
800
    public static function return_icon(
801
        $image,
802
        $alt_text = '',
803
        $additional_attributes = [],
804
        $size = ICON_SIZE_SMALL,
805
        $show_text = true,
806
        $return_only_path = false,
807
        $loadThemeIcon = true
808
    ) {
809
        $code_path = api_get_path(SYS_PUBLIC_PATH);
810
        $w_code_path = api_get_path(WEB_PUBLIC_PATH);
811
        // The following path is checked to see if the file exist. It's
812
        // important to use the public path (i.e. web/css/) rather than the
813
        // internal path (/app/Resource/public/css/) because the path used
814
        // in the end must be the public path
815
        $alternateCssPath = api_get_path(SYS_PUBLIC_PATH).'css/';
816
        $alternateWebCssPath = api_get_path(WEB_PUBLIC_PATH).'css/';
817
818
        // Avoid issues with illegal string offset for legacy calls to this
819
        // method with an empty string rather than null or an empty array
820
        if (empty($additional_attributes)) {
821
            $additional_attributes = [];
822
        }
823
824
        $image = trim($image);
825
826
        if (isset($size)) {
827
            $size = intval($size);
828
        } else {
829
            $size = ICON_SIZE_SMALL;
830
        }
831
832
        $size_extra = $size.'/';
833
        $icon = $w_code_path.'img/'.$image;
834
        $theme = 'themes/chamilo/icons/';
835
836
        if ($loadThemeIcon) {
837
            // @todo with chamilo 2 code
838
            $theme = 'themes/'.api_get_visual_theme().'/icons/';
839
            if (is_file($alternateCssPath.$theme.$image)) {
840
                $icon = $alternateWebCssPath.$theme.$image;
841
            }
842
            // Checking the theme icons folder example: app/Resources/public/css/themes/chamilo/icons/XXX
843
            if (is_file($alternateCssPath.$theme.$size_extra.$image)) {
844
                $icon = $alternateWebCssPath.$theme.$size_extra.$image;
845
            } elseif (is_file($code_path.'img/icons/'.$size_extra.$image)) {
846
                //Checking the main/img/icons/XXX/ folder
847
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
848
            }
849
        } else {
850
            if (is_file($code_path.'img/icons/'.$size_extra.$image)) {
851
                // Checking the main/img/icons/XXX/ folder
852
                $icon = $w_code_path.'img/icons/'.$size_extra.$image;
853
            }
854
        }
855
856
        // Special code to enable SVG - refs #7359 - Needs more work
857
        // The code below does something else to "test out" SVG: for each icon,
858
        // it checks if there is an SVG version. If so, it uses it.
859
        // When moving this to production, the return_icon() calls should
860
        // ask for the SVG version directly
861
        $svgIcons = api_get_setting('icons_mode_svg');
862
        if ($svgIcons == 'true' && $return_only_path == false) {
863
            $svgImage = substr($image, 0, -3).'svg';
864
            if (is_file($code_path.$theme.'svg/'.$svgImage)) {
865
                $icon = $w_code_path.$theme.'svg/'.$svgImage;
866
            } elseif (is_file($code_path.'img/icons/svg/'.$svgImage)) {
867
                $icon = $w_code_path.'img/icons/svg/'.$svgImage;
868
            }
869
870
            if (empty($additional_attributes['height'])) {
871
                $additional_attributes['height'] = $size;
872
            }
873
            if (empty($additional_attributes['width'])) {
874
                $additional_attributes['width'] = $size;
875
            }
876
        }
877
878
        $icon = api_get_cdn_path($icon);
879
880
        if ($return_only_path) {
881
            return $icon;
882
        }
883
884
        $img = self::img($icon, $alt_text, $additional_attributes);
885
        if (SHOW_TEXT_NEAR_ICONS == true && !empty($alt_text)) {
0 ignored issues
show
Coding Style Best Practice introduced by
It seems like you are loosely comparing two booleans. Considering using the strict comparison === instead.

When comparing two booleans, it is generally considered safer to use the strict comparison operator.

Loading history...
886
            if ($show_text) {
887
                $img = "$img $alt_text";
888
            }
889
        }
890
891
        return $img;
892
    }
893
894
    /**
895
     * Returns the htmlcode for an image.
896
     *
897
     * @param string $image_path            the filename of the file (in the main/img/ folder
898
     * @param string $alt_text              the alt text (probably a language variable)
899
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
900
     * @param bool   $filterPath            Optional. Whether filter the image path. Default is true
901
     *
902
     * @return string
903
     *
904
     * @author Julio Montoya 2010
905
     */
906
    public static function img(
907
        $image_path,
908
        $alt_text = '',
909
        $additional_attributes = null,
910
        $filterPath = true
911
    ) {
912
        if (empty($image_path)) {
913
            // For some reason, the call to img() happened without a proper
914
            // image. Log the error and return an empty string to avoid
915
            // breaking the HTML
916
            $trace = debug_backtrace();
917
            $caller = $trace[1];
918
            //error_log('No image provided in Display::img(). Caller info: '.print_r($caller, 1));
919
            return '';
920
        }
921
        // Sanitizing the parameter $image_path
922
        if ($filterPath) {
923
            $image_path = Security::filter_img_path($image_path);
924
        }
925
926
        // alt text = the image name if there is none provided (for XHTML compliance)
927
        if ($alt_text == '') {
928
            $alt_text = basename($image_path);
929
        }
930
931
        if (empty($additional_attributes)) {
932
            $additional_attributes = [];
933
        }
934
935
        $additional_attributes['src'] = $image_path;
936
937
        if (empty($additional_attributes['alt'])) {
938
            $additional_attributes['alt'] = $alt_text;
939
        }
940
        if (empty($additional_attributes['title'])) {
941
            $additional_attributes['title'] = $alt_text;
942
        }
943
944
        return self::tag('img', '', $additional_attributes);
945
    }
946
947
    /**
948
     * Returns the htmlcode for a tag (h3, h1, div, a, button), etc.
949
     *
950
     * @param string $tag                   the tag name
951
     * @param string $content               the tag's content
952
     * @param array  $additional_attributes (for instance height, width, onclick, ...)
953
     *
954
     * @return string
955
     *
956
     * @author Julio Montoya 2010
957
     */
958
    public static function tag($tag, $content, $additional_attributes = [])
959
    {
960
        $attribute_list = '';
961
        // Managing the additional attributes
962
        if (!empty($additional_attributes) && is_array($additional_attributes)) {
963
            $attribute_list = '';
964
            foreach ($additional_attributes as $key => &$value) {
965
                $attribute_list .= $key.'="'.$value.'" ';
966
            }
967
        }
968
        //some tags don't have this </XXX>
969
        if (in_array($tag, ['img', 'input', 'br'])) {
970
            $return_value = '<'.$tag.' '.$attribute_list.' />';
971
        } else {
972
            $return_value = '<'.$tag.' '.$attribute_list.' >'.$content.'</'.$tag.'>';
973
        }
974
975
        return $return_value;
976
    }
977
978
    /**
979
     * Creates a URL anchor.
980
     *
981
     * @param string $name
982
     * @param string $url
983
     * @param array  $attributes
984
     *
985
     * @return string
986
     */
987
    public static function url($name, $url, $attributes = [])
988
    {
989
        if (!empty($url)) {
990
            $url = preg_replace('#&amp;#', '&', $url);
991
            $url = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
992
            $attributes['href'] = $url;
993
        }
994
995
        return self::tag('a', $name, $attributes);
996
    }
997
998
    /**
999
     * Creates a div tag.
1000
     *
1001
     * @param string $content
1002
     * @param array  $attributes
1003
     *
1004
     * @return string
1005
     */
1006
    public static function div($content, $attributes = [])
1007
    {
1008
        return self::tag('div', $content, $attributes);
1009
    }
1010
1011
    /**
1012
     * Creates a span tag.
1013
     */
1014
    public static function span($content, $attributes = [])
1015
    {
1016
        return self::tag('span', $content, $attributes);
1017
    }
1018
1019
    /**
1020
     * Displays an HTML input tag.
1021
     */
1022
    public static function input($type, $name, $value, $attributes = [])
1023
    {
1024
        if (isset($type)) {
1025
            $attributes['type'] = $type;
1026
        }
1027
        if (isset($name)) {
1028
            $attributes['name'] = $name;
1029
        }
1030
        if (isset($value)) {
1031
            $attributes['value'] = $value;
1032
        }
1033
1034
        return self::tag('input', '', $attributes);
1035
    }
1036
1037
    /**
1038
     * @param $name
1039
     * @param $value
1040
     * @param array $attributes
1041
     *
1042
     * @return string
1043
     */
1044
    public static function button($name, $value, $attributes = [])
1045
    {
1046
        if (!empty($name)) {
1047
            $attributes['name'] = $name;
1048
        }
1049
1050
        return self::tag('button', $value, $attributes);
1051
    }
1052
1053
    /**
1054
     * Displays an HTML select tag.
1055
     *
1056
     * @param string $name
1057
     * @param array  $values
1058
     * @param int    $default
1059
     * @param array  $extra_attributes
1060
     * @param bool   $show_blank_item
1061
     * @param null   $blank_item_text
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $blank_item_text is correct as it would always require null to be passed?
Loading history...
1062
     *
1063
     * @return string
1064
     */
1065
    public static function select(
1066
        $name,
1067
        $values,
1068
        $default = -1,
1069
        $extra_attributes = [],
1070
        $show_blank_item = true,
1071
        $blank_item_text = ''
1072
    ) {
1073
        $html = '';
1074
        $extra = '';
1075
        $default_id = 'id="'.$name.'" ';
1076
        foreach ($extra_attributes as $key => $parameter) {
1077
            if ($key == 'id') {
1078
                $default_id = '';
1079
            }
1080
            $extra .= $key.'="'.$parameter.'" ';
1081
        }
1082
        $html .= '<select name="'.$name.'" '.$default_id.' '.$extra.'>';
1083
1084
        if ($show_blank_item) {
1085
            if (empty($blank_item_text)) {
1086
                $blank_item_text = get_lang('Select');
1087
            } else {
1088
                $blank_item_text = Security::remove_XSS($blank_item_text);
1089
            }
1090
            $html .= self::tag(
1091
                'option',
1092
                '-- '.$blank_item_text.' --',
1093
                ['value' => '-1']
1094
            );
1095
        }
1096
        if ($values) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $values of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1097
            foreach ($values as $key => $value) {
1098
                if (is_array($value) && isset($value['name'])) {
1099
                    $value = $value['name'];
1100
                }
1101
                $html .= '<option value="'.$key.'"';
1102
1103
                if (is_array($default)) {
1104
                    foreach ($default as $item) {
1105
                        if ($item == $key) {
1106
                            $html .= ' selected="selected"';
1107
                            break;
1108
                        }
1109
                    }
1110
                } else {
1111
                    if ($default == $key) {
1112
                        $html .= ' selected="selected"';
1113
                    }
1114
                }
1115
1116
                $html .= '>'.$value.'</option>';
1117
            }
1118
        }
1119
        $html .= '</select>';
1120
1121
        return $html;
1122
    }
1123
1124
    /**
1125
     * Creates a tab menu
1126
     * Requirements: declare the jquery, jquery-ui libraries + the jquery-ui.css
1127
     * in the $htmlHeadXtra variable before the display_header
1128
     * Add this script.
1129
     *
1130
     * @example
1131
     * <script>
1132
                </script>
1133
     * @param array  $headers       list of the tab titles
1134
     * @param array  $items
1135
     * @param string $id            id of the container of the tab in the example "tabs"
1136
     * @param array  $attributes    for the ul
1137
     * @param array  $ul_attributes
1138
     *
1139
     * @return string
1140
     */
1141
    public static function tabs(
1142
        $headers,
1143
        $items,
1144
        $id = 'tabs',
1145
        $attributes = [],
1146
        $ul_attributes = []
0 ignored issues
show
Unused Code introduced by
The parameter $ul_attributes is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1146
        /** @scrutinizer ignore-unused */ $ul_attributes = []

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1147
    ) {
1148
        if (empty($headers) || count($headers) == 0) {
1149
            return '';
1150
        }
1151
1152
        $lis = '';
1153
        $i = 1;
1154
        foreach ($headers as $item) {
1155
            $active = '';
1156
            $selected = 'false';
1157
            if ($i == 1) {
1158
                $active = ' active';
1159
                $selected = 'true';
1160
            }
1161
            $item = self::tag(
1162
                'a',
1163
                $item,
1164
                [
1165
                    'href' => '#'.$id.'-'.$i,
1166
                    'class' => 'nav-item nav-link '.$active,
1167
                    'id' => $id.$i.'-tab',
1168
                    'data-toggle' => 'tab',
1169
                    'role' => 'tab',
1170
                    'aria-controls' => 'aria_'.$id.$i,
1171
                    'aria-selected' => $selected
1172
                ]
1173
            );
1174
            $lis .= $item;
1175
            $i++;
1176
        }
1177
1178
        $ul = self::tag(
1179
            'nav',
1180
            $lis,
1181
            [
1182
                'id' => 'ul_'.$id,
1183
                'class' => 'nav nav-tabs',
1184
                'role' => 'tablist',
1185
            ]
1186
        );
1187
1188
        $i = 1;
1189
        $divs = '';
1190
        foreach ($items as $content) {
1191
            $active = '';
1192
            if ($i == 1) {
1193
                $active = ' show active';
1194
            }
1195
            $divs .= self::tag(
1196
                'div',
1197
                $content,
1198
                [
1199
                    'id' => $id.'-'.$i,
1200
                    'class' => 'tab-pane fade '.$active,
1201
                    'role' => 'tabpanel',
1202
                    'aria-labelledby' => $id.'-'.$i,
1203
                ]
1204
            );
1205
            $i++;
1206
        }
1207
1208
        $attributes['id'] = $id;
1209
        $attributes['class'] = 'tab_wrapper';
1210
1211
        $html = self::tag(
1212
            'div',
1213
            $ul.
1214
            self::tag('div', $divs, ['class' => 'tab-content']),
1215
            $attributes
1216
        );
1217
1218
        return $html;
1219
    }
1220
1221
    /**
1222
     * @param $headers
1223
     * @param null $selected
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $selected is correct as it would always require null to be passed?
Loading history...
1224
     *
1225
     * @return string
1226
     */
1227
    public static function tabsOnlyLink($headers, $selected = null)
1228
    {
1229
        $id = uniqid();
1230
        $i = 1;
1231
        $lis = null;
1232
        foreach ($headers as $item) {
1233
            $class = null;
1234
            if ($i == $selected) {
1235
                $class = 'active';
1236
            }
1237
            $item = self::tag(
1238
                'a',
1239
                $item['content'],
1240
                ['id' => $id.'-'.$i, 'href' => $item['url']]
1241
            );
1242
            $lis .= self::tag('li', $item, ['class' => $class]);
1243
            $i++;
1244
        }
1245
1246
        return self::tag(
1247
            'ul',
1248
            $lis,
1249
            ['class' => 'nav nav-tabs tabs-margin']
1250
        );
1251
    }
1252
1253
    /**
1254
     * In order to display a grid using jqgrid you have to:.
1255
     *
1256
     * @example
1257
     * After your Display::display_header function you have to add the nex javascript code:
1258
     * <script>
1259
     *   echo Display::grid_js('my_grid_name', $url,$columns, $column_model, $extra_params,[]);
1260
     *   // for more information of this function check the grid_js() function
1261
     * </script>
1262
     * //Then you have to call the grid_html
1263
     * echo Display::grid_html('my_grid_name');
1264
     * As you can see both function use the same "my_grid_name" this is very important otherwise nothing will work
1265
     *
1266
     * @param   string  the div id, this value must be the same with the first parameter of Display::grid_js()
1267
     *
1268
     * @return string html
1269
     */
1270
    public static function grid_html($div_id)
1271
    {
1272
        $table = self::tag('table', '', ['id' => $div_id]);
1273
        $table .= self::tag('div', '', ['id' => $div_id.'_pager']);
1274
1275
        return $table;
1276
    }
1277
1278
    /**
1279
     * @param string $label
1280
     * @param string $form_item
1281
     *
1282
     * @return string
1283
     */
1284
    public static function form_row($label, $form_item)
1285
    {
1286
        $label = self::span($label, ['class' => 'control-label']);
1287
        $form_item = self::div($form_item, ['class' => 'controls']);
1288
1289
        return self::div($label.$form_item, ['class' => 'control-group']);
1290
    }
1291
1292
    /**
1293
     * This is a wrapper to use the jqgrid in Chamilo.
1294
     * For the other jqgrid options visit http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options
1295
     * This function need to be in the ready jquery function
1296
     * example --> $(function() { <?php echo Display::grid_js('grid' ...); ?> }
1297
     * In order to work this function needs the Display::grid_html function with the same div id.
1298
     *
1299
     * @param string $div_id       div id
1300
     * @param string $url          url where the jqgrid will ask for data (if datatype = json)
1301
     * @param array  $column_names Visible columns (you should use get_lang).
1302
     *                             An array in which we place the names of the columns.
1303
     *                             This is the text that appears in the head of the grid (Header layer).
1304
     *                             Example: colname   {name:'date',     index:'date',   width:120, align:'right'},
1305
     * @param array  $column_model the column model :  Array which describes the parameters of the columns.
1306
     *                             This is the most important part of the grid.
1307
     *                             For a full description of all valid values see colModel API. See the url above.
1308
     * @param array  $extra_params extra parameters
1309
     * @param array  $data         data that will be loaded
1310
     * @param string $formatter    A string that will be appended to the JSON returned
1311
     * @param bool   $fixed_width  not implemented yet
1312
     *
1313
     * @return string the js code
1314
     */
1315
    public static function grid_js(
1316
        $div_id,
1317
        $url,
1318
        $column_names,
1319
        $column_model,
1320
        $extra_params,
1321
        $data = [],
1322
        $formatter = '',
1323
        $fixed_width = false
0 ignored issues
show
Unused Code introduced by
The parameter $fixed_width is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

1323
        /** @scrutinizer ignore-unused */ $fixed_width = false

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1324
    ) {
1325
        $obj = new stdClass();
1326
        $obj->first = 'first';
1327
1328
        if (!empty($url)) {
1329
            $obj->url = $url;
1330
        }
1331
1332
        //This line should only be used/modified in case of having characters
1333
        // encoding problems - see #6159
1334
        //$column_names = array_map("utf8_encode", $column_names);
1335
        $obj->colNames = $column_names;
1336
        $obj->colModel = $column_model;
1337
        $obj->pager = '#'.$div_id.'_pager';
1338
        $obj->datatype = 'json';
1339
        $obj->viewrecords = 'true';
1340
        $all_value = 10000000;
1341
1342
        // Default row quantity
1343
        if (!isset($extra_params['rowList'])) {
1344
            $extra_params['rowList'] = [20, 50, 100, 500, 1000, $all_value];
1345
        }
1346
1347
        $json = '';
1348
        if (!empty($extra_params['datatype'])) {
1349
            $obj->datatype = $extra_params['datatype'];
1350
        }
1351
1352
        // Row even odd style.
1353
        $obj->altRows = true;
1354
        if (!empty($extra_params['altRows'])) {
1355
            $obj->altRows = $extra_params['altRows'];
1356
        }
1357
1358
        if (!empty($extra_params['sortname'])) {
1359
            $obj->sortname = $extra_params['sortname'];
1360
        }
1361
1362
        if (!empty($extra_params['sortorder'])) {
1363
            $obj->sortorder = $extra_params['sortorder'];
1364
        }
1365
1366
        if (!empty($extra_params['rowList'])) {
1367
            $obj->rowList = $extra_params['rowList'];
1368
        }
1369
1370
        // Sets how many records we want to view in the grid
1371
        $obj->rowNum = 20;
1372
        if (!empty($extra_params['rowNum'])) {
1373
            $obj->rowNum = $extra_params['rowNum'];
1374
        } else {
1375
            // Try to load max rows from Session
1376
            $urlInfo = parse_url($url);
1377
            if (isset($urlInfo['query'])) {
1378
                parse_str($urlInfo['query'], $query);
1379
                if (isset($query['a'])) {
1380
                    $action = $query['a'];
1381
                    // This value is set in model.ajax.php
1382
                    $savedRows = Session::read('max_rows_'.$action);
1383
                    if (!empty($savedRows)) {
1384
                        $obj->rowNum = $savedRows;
1385
                    }
1386
                }
1387
            }
1388
        }
1389
1390
        if (!empty($extra_params['viewrecords'])) {
1391
            $obj->viewrecords = $extra_params['viewrecords'];
1392
        }
1393
1394
        $beforeSelectRow = null;
1395
        if (isset($extra_params['beforeSelectRow'])) {
1396
            $beforeSelectRow = "beforeSelectRow: ".$extra_params['beforeSelectRow'].", ";
1397
            unset($extra_params['beforeSelectRow']);
1398
        }
1399
1400
        // Adding extra params
1401
        if (!empty($extra_params)) {
1402
            foreach ($extra_params as $key => $element) {
1403
                // the groupHeaders key gets a special treatment
1404
                if ($key != 'groupHeaders') {
1405
                    $obj->$key = $element;
1406
                }
1407
            }
1408
        }
1409
1410
        // Adding static data.
1411
        if (!empty($data)) {
1412
            $data_var = $div_id.'_data';
1413
            $json .= ' var '.$data_var.' = '.json_encode($data).';';
1414
            $obj->data = $data_var;
1415
            $obj->datatype = 'local';
1416
            $json .= "\n";
1417
        }
1418
1419
        $obj->end = 'end';
1420
1421
        $json_encode = json_encode($obj);
1422
1423
        if (!empty($data)) {
1424
            //Converts the "data":"js_variable" to "data":js_variable,
1425
            // otherwise it will not work
1426
            $json_encode = str_replace('"data":"'.$data_var.'"', '"data":'.$data_var.'', $json_encode);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $data_var does not seem to be defined for all execution paths leading up to this point.
Loading history...
1427
        }
1428
1429
        // Fixing true/false js values that doesn't need the ""
1430
        $json_encode = str_replace(':"true"', ':true', $json_encode);
1431
        // wrap_cell is not a valid jqgrid attributes is a hack to wrap a text
1432
        $json_encode = str_replace('"wrap_cell":true', 'cellattr : function(rowId, value, rowObject, colModel, arrData) { return \'class = "jqgrid_whitespace"\'; }', $json_encode);
1433
        $json_encode = str_replace(':"false"', ':false', $json_encode);
1434
        $json_encode = str_replace('"formatter":"action_formatter"', 'formatter:action_formatter', $json_encode);
1435
        $json_encode = str_replace('"formatter":"extra_formatter"', 'formatter:extra_formatter', $json_encode);
1436
        $json_encode = str_replace(['{"first":"first",', '"end":"end"}'], '', $json_encode);
1437
1438
        // Creating the jqgrid element.
1439
        $json .= '$("#'.$div_id.'").jqGrid({';
1440
        //$json .= $beforeSelectRow;
1441
        $json .= $json_encode;
1442
        $json .= '});';
1443
1444
        // Grouping headers option
1445
        if (isset($extra_params['groupHeaders'])) {
1446
            $groups = '';
1447
            foreach ($extra_params['groupHeaders'] as $group) {
1448
                //{ "startColumnName" : "courses", "numberOfColumns" : 1, "titleText" : "Order Info" },
1449
                $groups .= '{ "startColumnName" : "'.$group['startColumnName'].'", "numberOfColumns" : '.$group['numberOfColumns'].', "titleText" : "'.$group['titleText'].'" },';
1450
            }
1451
            $json .= '$("#'.$div_id.'").jqGrid("setGroupHeaders", {
1452
                "useColSpanStyle" : false,
1453
                "groupHeaders"    : [
1454
                    '.$groups.'
1455
                ]
1456
            });';
1457
        }
1458
1459
        $all_text = addslashes(get_lang('All'));
1460
        $json .= '$("'.$obj->pager.' option[value='.$all_value.']").text("'.$all_text.'");';
1461
        $json .= "\n";
1462
        // Adding edit/delete icons.
1463
        $json .= $formatter;
1464
1465
        return $json;
1466
    }
1467
1468
    /**
1469
     * @param array $headers
1470
     * @param array $rows
1471
     * @param array $attributes
1472
     *
1473
     * @return string
1474
     */
1475
    public static function table($headers, $rows, $attributes = [])
1476
    {
1477
        if (empty($attributes)) {
1478
            $attributes['class'] = 'data_table';
1479
        }
1480
        $table = new HTML_Table($attributes);
1481
        $row = 0;
1482
        $column = 0;
1483
1484
        // Course headers
1485
        if (!empty($headers)) {
1486
            foreach ($headers as $item) {
1487
                $table->setHeaderContents($row, $column, $item);
1488
                $column++;
1489
            }
1490
            $row = 1;
1491
            $column = 0;
1492
        }
1493
1494
        if (!empty($rows)) {
1495
            foreach ($rows as $content) {
1496
                $table->setCellContents($row, $column, $content);
1497
                $row++;
1498
            }
1499
        }
1500
1501
        return $table->toHtml();
1502
    }
1503
1504
    /**
1505
     * Returns the "what's new" icon notifications.
1506
     *
1507
     * The general logic of this function is to track the last time the user
1508
     * entered the course and compare to what has changed inside this course
1509
     * since then, based on the item_property table inside this course. Note that,
1510
     * if the user never entered the course before, he will not see notification
1511
     * icons. This function takes session ID into account (if any) and only shows
1512
     * the corresponding notifications.
1513
     *
1514
     * @param array $courseInfo Course information array, containing at least elements 'db' and 'k'
1515
     * @param bool  $loadAjax
1516
     *
1517
     * @return string The HTML link to be shown next to the course
1518
     */
1519
    public static function show_notification($courseInfo, $loadAjax = true)
1520
    {
1521
        if (empty($courseInfo)) {
1522
            return '';
1523
        }
1524
1525
        $t_track_e_access = Database::get_main_table(TABLE_STATISTIC_TRACK_E_LASTACCESS);
1526
        $course_tool_table = Database::get_course_table(TABLE_TOOL_LIST);
1527
        $tool_edit_table = Database::get_course_table(TABLE_ITEM_PROPERTY);
1528
        $course_code = Database::escape_string($courseInfo['code']);
1529
1530
        $user_id = api_get_user_id();
1531
        $course_id = (int) $courseInfo['real_id'];
1532
        $sessionId = (int) $courseInfo['id_session'];
1533
        $status = (int) $courseInfo['status'];
1534
1535
        $loadNotificationsByAjax = api_get_configuration_value('user_portal_load_notification_by_ajax');
1536
1537
        if ($loadNotificationsByAjax) {
1538
            if ($loadAjax) {
1539
                $id = 'notification_'.$course_id.'_'.$sessionId.'_'.$status;
1540
                Session::write($id, true);
1541
1542
                return '<span id ="'.$id.'" class="course_notification"></span>';
1543
            }
1544
        }
1545
1546
        // Get the user's last access dates to all tools of this course
1547
        $sql = "SELECT *
1548
                FROM $t_track_e_access
1549
                WHERE
1550
                    c_id = $course_id AND
1551
                    access_user_id = '$user_id' AND
1552
                    access_session_id ='".$sessionId."'
1553
                ORDER BY access_date DESC 
1554
                LIMIT 1
1555
                ";
1556
        $result = Database::query($sql);
1557
1558
        // latest date by default is the creation date
1559
        $latestDate = $courseInfo['creation_date'];
1560
        if (Database::num_rows($result)) {
1561
            $row = Database::fetch_array($result, 'ASSOC');
1562
            $latestDate = $row['access_date'];
1563
        }
1564
1565
        $sessionCondition = api_get_session_condition(
1566
            $sessionId,
1567
            true,
1568
            false,
1569
            'session_id'
1570
        );
1571
1572
        $hideTools = [TOOL_NOTEBOOK, TOOL_CHAT];
1573
        // Get current tools in course
1574
        $sql = "SELECT name, link, image 
1575
                FROM $course_tool_table 
1576
                WHERE 
1577
                    c_id = $course_id AND 
1578
                    visibility = '1' AND
1579
                    name NOT IN ('".implode("','", $hideTools)."')
1580
                ";
1581
        $result = Database::query($sql);
1582
        $tools = Database::store_result($result);
1583
1584
        $group_ids = GroupManager::get_group_ids($courseInfo['real_id'], $user_id);
1585
        $group_ids[] = 0; //add group 'everyone'
1586
        $notifications = [];
1587
        if ($tools) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $tools of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
1588
            foreach ($tools as $tool) {
1589
                $toolName = $tool['name'];
1590
                $toolName = Database::escape_string($toolName);
1591
                // Fix to get student publications
1592
                $toolCondition = " tool = '$toolName' AND ";
1593
                if ($toolName == 'student_publication' || $toolName == 'work') {
1594
                    $toolCondition = " (tool = 'work' OR tool = 'student_publication') AND ";
1595
                }
1596
1597
                $toolName = addslashes($toolName);
1598
1599
                $sql = "SELECT * FROM $tool_edit_table 
1600
                        WHERE
1601
                            c_id = $course_id AND
1602
                            $toolCondition
1603
                            lastedit_type NOT LIKE '%Deleted%' AND
1604
                            lastedit_type NOT LIKE '%deleted%' AND
1605
                            lastedit_type NOT LIKE '%DocumentInvisible%' AND
1606
                            lastedit_date > '$latestDate' AND
1607
                            lastedit_user_id != $user_id $sessionCondition AND
1608
                            visibility != 2 AND
1609
                            (to_user_id IN ('$user_id', '0') OR to_user_id IS NULL) AND
1610
                            (to_group_id IN ('".implode("','", $group_ids)."') OR to_group_id IS NULL)
1611
                        ORDER BY lastedit_date DESC
1612
                        LIMIT 1";
1613
                $result = Database::query($sql);
1614
1615
                $latestChange = Database::fetch_array($result, 'ASSOC');
1616
1617
                if ($latestChange) {
1618
                    $latestChange['link'] = $tool['link'];
1619
                    $latestChange['image'] = $tool['image'];
1620
                    $latestChange['tool'] = $tool['name'];
1621
                    $notifications[$toolName] = $latestChange;
1622
                }
1623
            }
1624
        }
1625
1626
        // Show all tool icons where there is something new.
1627
        $return = '';
1628
        foreach ($notifications as $notification) {
1629
            $toolName = $notification['tool'];
1630
            if (!(
1631
                    $notification['visibility'] == '1' ||
1632
                    ($status == '1' && $notification['visibility'] == '0') ||
1633
                    !isset($notification['visibility'])
1634
                )
1635
            ) {
1636
                continue;
1637
            }
1638
1639
            if ($toolName == TOOL_SURVEY) {
1640
                $survey_info = SurveyManager::get_survey($notification['ref'], 0, $course_code);
1641
                if (!empty($survey_info)) {
1642
                    $invited_users = SurveyUtil::get_invited_users(
1643
                        $survey_info['code'],
1644
                        $course_code
1645
                    );
1646
                    if (!in_array($user_id, $invited_users['course_users'])) {
1647
                        continue;
1648
                    }
1649
                }
1650
            }
1651
1652
            if ($notification['tool'] == TOOL_LEARNPATH) {
1653
                if (!learnpath::is_lp_visible_for_student($notification['ref'], $user_id, $course_code)) {
1654
                    continue;
1655
                }
1656
            }
1657
1658
            if ($notification['tool'] == TOOL_DROPBOX) {
1659
                $notification['link'] = 'dropbox/dropbox_download.php?id='.$notification['ref'];
1660
            }
1661
1662
            if ($notification['tool'] == 'work' &&
1663
                $notification['lastedit_type'] == 'DirectoryCreated'
1664
            ) {
1665
                $notification['lastedit_type'] = 'WorkAdded';
1666
            }
1667
1668
            $lastDate = api_get_local_time($notification['lastedit_date']);
1669
            $type = $notification['lastedit_type'];
1670
            if ($type == 'CalendareventVisible') {
1671
                $type = 'Visible';
1672
            }
1673
            $label = get_lang('TitleNotification').": ".get_lang($type)." ($lastDate)";
1674
1675
            if (strpos($notification['link'], '?') === false) {
1676
                $notification['link'] = $notification['link'].'?notification=1';
1677
            } else {
1678
                $notification['link'] = $notification['link'].'&notification=1';
1679
            }
1680
1681
            $image = substr($notification['image'], 0, -4).'.png';
1682
1683
            $return .= self::url(
1684
                self::return_icon($image, $label),
1685
                api_get_path(WEB_CODE_PATH).
1686
                $notification['link'].'&cidReq='.$course_code.
1687
                '&ref='.$notification['ref'].
1688
                '&gidReq='.$notification['to_group_id'].
1689
                '&id_session='.$sessionId
1690
            ).PHP_EOL;
1691
        }
1692
1693
        return $return;
1694
    }
1695
1696
    /**
1697
     * Get the session box details as an array.
1698
     *
1699
     * @param int       Session ID
1700
     *
1701
     * @return array Empty array or session array
1702
     *               ['title'=>'...','category'=>'','dates'=>'...','coach'=>'...','active'=>true/false,'session_category_id'=>int]
1703
     */
1704
    public static function getSessionTitleBox($session_id)
1705
    {
1706
        global $nosession;
1707
1708
        if (!$nosession) {
1709
            global $now, $date_start, $date_end;
1710
        }
1711
        $output = [];
1712
        if (!$nosession) {
1713
            $main_user_table = Database::get_main_table(TABLE_MAIN_USER);
1714
            $tbl_session = Database::get_main_table(TABLE_MAIN_SESSION);
1715
            // Request for the name of the general coach
1716
            $sql = 'SELECT tu.lastname, tu.firstname, ts.*
1717
                    FROM '.$tbl_session.' ts
1718
                    LEFT JOIN '.$main_user_table.' tu
1719
                    ON ts.id_coach = tu.user_id
1720
                    WHERE ts.id = '.intval($session_id);
1721
            $rs = Database::query($sql);
1722
            $session_info = Database::store_result($rs, 'ASSOC');
1723
            $session_info = $session_info[0];
1724
1725
            $session = [];
1726
            $session['category_id'] = $session_info['session_category_id'];
1727
            $session['title'] = $session_info['name'];
1728
            $session['id_coach'] = $session_info['id_coach'];
1729
            $session['coach'] = '';
1730
            $session['dates'] = '';
1731
1732
            if (api_get_setting('show_session_coach') === 'true') {
1733
                $session['coach'] = get_lang('GeneralCoach').': '.api_get_person_name($session_info['firstname'], $session_info['lastname']);
1734
            }
1735
1736
            if (($session_info['access_end_date'] == '0000-00-00 00:00:00' &&
1737
                $session_info['access_start_date'] == '0000-00-00 00:00:00') ||
1738
                (empty($session_info['access_end_date']) && empty($session_info['access_start_date']))
1739
            ) {
1740
                if (isset($session_info['duration']) && !empty($session_info['duration'])) {
1741
                    $daysLeft = SessionManager::getDayLeftInSession($session_info, api_get_user_id());
1742
                    $session['duration'] = $daysLeft >= 0
1743
                        ? sprintf(get_lang('SessionDurationXDaysLeft'), $daysLeft)
1744
                        : get_lang('YourSessionTimeHasExpired');
1745
                }
1746
                $active = true;
1747
            } else {
1748
                $dates = SessionManager::parseSessionDates($session_info, true);
1749
                $session['dates'] = $dates['access'];
1750
                if (api_get_setting('show_session_coach') === 'true') {
1751
                    $session['coach'] = api_get_person_name(
1752
                        $session_info['firstname'],
1753
                        $session_info['lastname']
1754
                    );
1755
                }
1756
                $active = $date_start <= $now && $date_end >= $now;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $date_start does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $now does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $date_end does not seem to be defined for all execution paths leading up to this point.
Loading history...
1757
            }
1758
            $session['active'] = $active;
1759
            $session['session_category_id'] = $session_info['session_category_id'];
1760
            $session['visibility'] = $session_info['visibility'];
1761
            $session['num_users'] = $session_info['nbr_users'];
1762
            $session['num_courses'] = $session_info['nbr_courses'];
1763
            $session['description'] = $session_info['description'];
1764
            $session['show_description'] = $session_info['show_description'];
1765
1766
            $entityManager = Database::getManager();
1767
            $fieldValuesRepo = $entityManager->getRepository('ChamiloCoreBundle:ExtraFieldValues');
1768
            $extraFieldValues = $fieldValuesRepo->getVisibleValues(ExtraField::SESSION_FIELD_TYPE, $session_id);
1769
1770
            $session['extra_fields'] = [];
1771
            /** @var \Chamilo\CoreBundle\Entity\ExtraFieldValues $value */
1772
            foreach ($extraFieldValues as $value) {
1773
                if (empty($value)) {
1774
                    continue;
1775
                }
1776
                $session['extra_fields'][] = [
1777
                    'field' => [
1778
                        'variable' => $value->getField()->getVariable(),
1779
                        'display_text' => $value->getField()->getDisplayText(),
1780
                    ],
1781
                    'value' => $value->getValue(),
1782
                ];
1783
            }
1784
1785
            $output = $session;
1786
        }
1787
1788
        return $output;
1789
    }
1790
1791
    /**
1792
     * Return the five star HTML.
1793
     *
1794
     * @param string $id              of the rating ul element
1795
     * @param string $url             that will be added (for jquery see hot_courses.tpl)
1796
     * @param array  $point_info      point info array see function CourseManager::get_course_ranking()
1797
     * @param bool   $add_div_wrapper add a div wrapper
1798
     *
1799
     * @return string
1800
     */
1801
    public static function return_rating_system(
1802
        $id,
1803
        $url,
1804
        $point_info = [],
1805
        $add_div_wrapper = true
1806
    ) {
1807
        $number_of_users_who_voted = isset($point_info['users_who_voted']) ? $point_info['users_who_voted'] : null;
1808
        $percentage = isset($point_info['point_average']) ? $point_info['point_average'] : 0;
1809
1810
        if (!empty($percentage)) {
1811
            $percentage = $percentage * 125 / 100;
1812
        }
1813
        $accesses = isset($point_info['accesses']) ? $point_info['accesses'] : 0;
1814
        $star_label = sprintf(get_lang('XStarsOutOf5'), $point_info['point_average_star']);
1815
1816
        $html = '<ul id="'.$id.'" class="star-rating">
1817
                    <li class="current-rating" style="width:'.$percentage.'px;"></li>
1818
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=1" title="'.$star_label.'" class="one-star">1</a></li>
1819
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=2" title="'.$star_label.'" class="two-stars">2</a></li>
1820
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=3" title="'.$star_label.'" class="three-stars">3</a></li>
1821
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=4" title="'.$star_label.'" class="four-stars">4</a></li>
1822
                    <li><a href="javascript:void(0);" data-link="'.$url.'&amp;star=5" title="'.$star_label.'" class="five-stars">5</a></li>
1823
                </ul>';
1824
1825
        $labels = [];
1826
1827
        $labels[] = $number_of_users_who_voted == 1 ? $number_of_users_who_voted.' '.get_lang('Vote') : $number_of_users_who_voted.' '.get_lang('Votes');
1828
        $labels[] = $accesses == 1 ? $accesses.' '.get_lang('Visit') : $accesses.' '.get_lang('Visits');
1829
        $labels[] = $point_info['user_vote'] ? get_lang('YourVote').' ['.$point_info['user_vote'].']' : get_lang('YourVote').' [?] ';
1830
1831
        if (!$add_div_wrapper && api_is_anonymous()) {
1832
            $labels[] = self::tag('span', get_lang('LoginToVote'), ['class' => 'error']);
1833
        }
1834
1835
        $html .= self::div(implode(' | ', $labels), ['id' => 'vote_label_'.$id, 'class' => 'vote_label_info']);
1836
        $html .= ' '.self::span(' ', ['id' => 'vote_label2_'.$id]);
1837
1838
        if ($add_div_wrapper) {
1839
            $html = self::div($html, ['id' => 'rating_wrapper_'.$id]);
1840
        }
1841
1842
        return $html;
1843
    }
1844
1845
    /**
1846
     * @param string $title
1847
     * @param string $second_title
1848
     * @param string $size
1849
     * @param bool   $filter
1850
     *
1851
     * @return string
1852
     */
1853
    public static function page_header($title, $second_title = null, $size = 'h2', $filter = true)
1854
    {
1855
        if ($filter) {
1856
            $title = Security::remove_XSS($title);
1857
        }
1858
1859
        if (!empty($second_title)) {
1860
            if ($filter) {
1861
                $second_title = Security::remove_XSS($second_title);
1862
            }
1863
            $title .= "<small> $second_title</small>";
1864
        }
1865
1866
        return '<'.$size.' class="page-header">'.$title.'</'.$size.'>';
1867
    }
1868
1869
    public static function page_header_and_translate($title, $second_title = null)
1870
    {
1871
        $title = get_lang($title);
1872
1873
        return self::page_header($title, $second_title);
1874
    }
1875
1876
    public static function page_subheader_and_translate($title, $second_title = null)
1877
    {
1878
        $title = get_lang($title);
1879
1880
        return self::page_subheader($title, $second_title);
1881
    }
1882
1883
    public static function page_subheader($title, $second_title = null, $size = 'h3')
1884
    {
1885
        if (!empty($second_title)) {
1886
            $second_title = Security::remove_XSS($second_title);
1887
            $title .= "<small> $second_title<small>";
1888
        }
1889
1890
        return '<'.$size.'>'.Security::remove_XSS($title).'</'.$size.'>';
1891
    }
1892
1893
    public static function page_subheader2($title, $second_title = null)
1894
    {
1895
        return self::page_header($title, $second_title, 'h4');
1896
    }
1897
1898
    public static function page_subheader3($title, $second_title = null)
1899
    {
1900
        return self::page_header($title, $second_title, 'h5');
1901
    }
1902
1903
    /**
1904
     * @param array $list
1905
     *
1906
     * @return null|string
1907
     */
1908
    public static function description($list)
1909
    {
1910
        $html = null;
1911
        if (!empty($list)) {
1912
            $html = '<dl class="dl-horizontal">';
1913
            foreach ($list as $item) {
1914
                $html .= '<dt>'.$item['title'].'</dt>';
1915
                $html .= '<dd>'.$item['content'].'</dd>';
1916
            }
1917
            $html .= '</dl>';
1918
        }
1919
1920
        return $html;
1921
    }
1922
1923
    /**
1924
     * @param $percentage
1925
     * @param bool $show_percentage
1926
     * @param null $extra_info
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $extra_info is correct as it would always require null to be passed?
Loading history...
1927
     *
1928
     * @return string
1929
     */
1930
    public static function bar_progress($percentage, $show_percentage = true, $extra_info = null)
1931
    {
1932
        $percentage = intval($percentage);
1933
        $div = '<div class="progress">
1934
                <div
1935
                    class="progress-bar progress-bar-striped"
1936
                    role="progressbar"
1937
                    aria-valuenow="'.$percentage.'"
1938
                    aria-valuemin="0"
1939
                    aria-valuemax="100"
1940
                    style="width: '.$percentage.'%;"
1941
                >';
1942
        if ($show_percentage) {
1943
            $div .= $percentage.'%';
1944
        } else {
1945
            if (!empty($extra_info)) {
1946
                $div .= $extra_info;
1947
            }
1948
        }
1949
        $div .= '</div>';
1950
1951
        return $div;
1952
    }
1953
1954
    /**
1955
     * @param string $count
1956
     * @param string $type
1957
     *
1958
     * @return null|string
1959
     */
1960
    public static function badge($count, $type = "warning")
1961
    {
1962
        $class = '';
1963
1964
        switch ($type) {
1965
            case 'success':
1966
                $class = 'badge-success';
1967
                break;
1968
            case 'warning':
1969
                $class = 'badge-warning';
1970
                break;
1971
            case 'important':
1972
                $class = 'badge-important';
1973
                break;
1974
            case 'info':
1975
                $class = 'badge-info';
1976
                break;
1977
            case 'inverse':
1978
                $class = 'badge-inverse';
1979
                break;
1980
        }
1981
1982
        if (!empty($count)) {
1983
            return ' <span class="badge '.$class.'">'.$count.'</span>';
1984
        }
1985
1986
        return null;
1987
    }
1988
1989
    /**
1990
     * @param array $badge_list
1991
     *
1992
     * @return string
1993
     */
1994
    public static function badge_group($badge_list)
1995
    {
1996
        $html = '<div class="badge-group">';
1997
        foreach ($badge_list as $badge) {
1998
            $html .= $badge;
1999
        }
2000
        $html .= '</div>';
2001
2002
        return $html;
2003
    }
2004
2005
    /**
2006
     * @param string $content
2007
     * @param string $type
2008
     *
2009
     * @return string
2010
     */
2011
    public static function label($content, $type = 'default')
2012
    {
2013
        switch ($type) {
2014
            case 'success':
2015
                $class = 'success';
2016
                break;
2017
            case 'warning':
2018
                $class = 'warning';
2019
                break;
2020
            case 'important':
2021
            case 'danger':
2022
                $class = 'danger';
2023
                break;
2024
            case 'info':
2025
                $class = 'info';
2026
                break;
2027
            case 'primary':
2028
                $class = 'primary';
2029
                break;
2030
            default:
2031
                $class = 'secondary';
2032
                break;
2033
        }
2034
2035
        $html = '';
2036
        if (!empty($content)) {
2037
            $html = '<span class="badge badge-'.$class.'">';
2038
            $html .= $content;
2039
            $html .= '</span>';
2040
        }
2041
2042
        return $html;
2043
    }
2044
2045
    /**
2046
     * @param array  $items
2047
     * @param string $class
2048
     *
2049
     * @return null|string
2050
     */
2051
    public static function actions($items, $class = 'new_actions')
2052
    {
2053
        $html = null;
2054
        if (!empty($items)) {
2055
            $html = '<div class="'.$class.'"><ul class="nav nav-pills">';
2056
            foreach ($items as $value) {
2057
                $class = null;
2058
                if (isset($value['active']) && $value['active']) {
2059
                    $class = 'class ="active"';
2060
                }
2061
2062
                if (basename($_SERVER['REQUEST_URI']) == basename($value['url'])) {
2063
                    $class = 'class ="active"';
2064
                }
2065
                $html .= "<li $class >";
2066
                $attributes = isset($value['url_attributes']) ? $value['url_attributes'] : [];
2067
                $html .= self::url($value['content'], $value['url'], $attributes);
2068
                $html .= '</li>';
2069
            }
2070
            $html .= '</ul></div>';
2071
            $html .= '<br />';
2072
        }
2073
2074
        return $html;
2075
    }
2076
2077
    /**
2078
     * Prints a tooltip.
2079
     *
2080
     * @param string $text
2081
     * @param string $tip
2082
     *
2083
     * @return string
2084
     */
2085
    public static function tip($text, $tip)
2086
    {
2087
        if (empty($tip)) {
2088
            return $text;
2089
        }
2090
2091
        return self::span(
2092
            $text,
2093
            ['class' => 'boot-tooltip', 'title' => strip_tags($tip)]
2094
        );
2095
    }
2096
2097
    /**
2098
     * @param array $buttons
2099
     *
2100
     * @return string
2101
     */
2102
    public static function groupButton($buttons)
2103
    {
2104
        $html = '<div class="btn-group" role="group">';
2105
        foreach ($buttons as $button) {
2106
            $html .= $button;
2107
        }
2108
        $html .= '</div>';
2109
2110
        return $html;
2111
    }
2112
2113
    /**
2114
     * @todo use twig
2115
     *
2116
     * @param string $title
2117
     * @param array  $elements
2118
     * @param bool   $alignToRight
2119
     *
2120
     * @return string
2121
     */
2122
    public static function groupButtonWithDropDown($title, $elements, $alignToRight = false)
2123
    {
2124
        $id = uniqid('dropdown', true);
2125
        $html = '<div class="btn-group" role="group">
2126
                <button id = "'.$id.'" class="btn btn-secondary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
2127
                '.$title.'
2128
                </button>
2129
                <div class="dropdown-menu aria-labelledby="'.$id.'" '.($alignToRight ? 'dropdown-menu-right' : '').'">';
2130
        foreach ($elements as $item) {
2131
            $html .= self::tag('li', self::url($item['title'], $item['href'], ['class' => 'dropdown-item']));
2132
        }
2133
        $html .= '</div>
2134
            </div>';
2135
2136
        return $html;
2137
    }
2138
2139
    /**
2140
     * @param string $file
2141
     * @param array  $params
2142
     *
2143
     * @return null|string
2144
     */
2145
    public static function getMediaPlayer($file, $params = [])
2146
    {
2147
        $fileInfo = pathinfo($file);
2148
2149
        switch ($fileInfo['extension']) {
2150
            case 'mp3':
2151
            case 'webm':
2152
                $autoplay = null;
2153
                if (isset($params['autoplay']) && $params['autoplay'] == 'true') {
2154
                    $autoplay = 'autoplay';
2155
                }
2156
                $width = isset($params['width']) ? 'width="'.$params['width'].'"' : null;
2157
                $id = isset($params['id']) ? $params['id'] : $fileInfo['basename'];
2158
                $class = isset($params['class']) ? ' class="'.$params['class'].'"' : null;
2159
2160
                $html = '<audio id="'.$id.'" '.$class.' controls '.$autoplay.' '.$width.' src="'.$params['url'].'" >';
2161
                $html .= '<object width="'.$width.'" height="50" type="application/x-shockwave-flash" data="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf">
2162
                            <param name="movie" value="'.api_get_path(WEB_LIBRARY_PATH).'javascript/mediaelement/flashmediaelement.swf" />
2163
                            <param name="flashvars" value="controls=true&file='.$params['url'].'" />
2164
                          </object>';
2165
                $html .= '</audio>';
2166
2167
                return $html;
2168
                break;
0 ignored issues
show
Unused Code introduced by
break is not strictly necessary here and could be removed.

The break statement is not necessary if it is preceded for example by a return statement:

switch ($x) {
    case 1:
        return 'foo';
        break; // This break is not necessary and can be left off.
}

If you would like to keep this construct to be consistent with other case statements, you can safely mark this issue as a false-positive.

Loading history...
2169
            case 'wav':
2170
            case 'ogg':
2171
                $html = '<audio width="300px" controls src="'.$params['url'].'" >';
2172
2173
                return $html;
2174
                break;
2175
        }
2176
2177
        return null;
2178
    }
2179
2180
    /**
2181
     * @param int    $nextValue
2182
     * @param array  $list
2183
     * @param int    $current
2184
     * @param int    $fixedValue
2185
     * @param array  $conditions
2186
     * @param string $link
2187
     * @param bool   $isMedia
2188
     * @param bool   $addHeaders
2189
     * @param array  $linkAttributes
2190
     *
2191
     * @return string
2192
     */
2193
    public static function progressPaginationBar(
2194
        $nextValue,
2195
        $list,
2196
        $current,
2197
        $fixedValue = null,
2198
        $conditions = [],
2199
        $link = null,
2200
        $isMedia = false,
2201
        $addHeaders = true,
2202
        $linkAttributes = []
2203
    ) {
2204
        if ($addHeaders) {
2205
            $pagination_size = 'pagination-mini';
2206
            $html = '<div class="exercise_pagination pagination '.$pagination_size.'"><ul>';
2207
        } else {
2208
            $html = null;
2209
        }
2210
        $affectAllItems = false;
2211
        if ($isMedia && isset($fixedValue) && ($nextValue + 1 == $current)) {
2212
            $affectAllItems = true;
2213
        }
2214
        $localCounter = 0;
2215
        foreach ($list as $itemId) {
2216
            $isCurrent = false;
2217
            if ($affectAllItems) {
2218
                $isCurrent = true;
2219
            } else {
2220
                if (!$isMedia) {
2221
                    $isCurrent = $current == ($localCounter + $nextValue + 1) ? true : false;
2222
                }
2223
            }
2224
            $html .= self::parsePaginationItem(
2225
                $itemId,
2226
                $isCurrent,
2227
                $conditions,
2228
                $link,
2229
                $nextValue,
2230
                $isMedia,
2231
                $localCounter,
2232
                $fixedValue,
2233
                $linkAttributes
2234
            );
2235
            $localCounter++;
2236
        }
2237
        if ($addHeaders) {
2238
            $html .= '</ul></div>';
2239
        }
2240
2241
        return $html;
2242
    }
2243
2244
    /**
2245
     * @param int    $itemId
2246
     * @param bool   $isCurrent
2247
     * @param array  $conditions
2248
     * @param string $link
2249
     * @param int    $nextValue
2250
     * @param bool   $isMedia
2251
     * @param int    $localCounter
2252
     * @param int    $fixedValue
2253
     * @param array  $linkAttributes
2254
     *
2255
     * @return string
2256
     */
2257
    public static function parsePaginationItem(
2258
        $itemId,
2259
        $isCurrent,
2260
        $conditions,
2261
        $link,
2262
        $nextValue = 0,
2263
        $isMedia = false,
2264
        $localCounter = null,
2265
        $fixedValue = null,
2266
        $linkAttributes = []
2267
    ) {
2268
        $defaultClass = 'before';
2269
        $class = $defaultClass;
2270
        foreach ($conditions as $condition) {
2271
            $array = isset($condition['items']) ? $condition['items'] : [];
2272
            $class_to_applied = $condition['class'];
2273
            $type = isset($condition['type']) ? $condition['type'] : 'positive';
2274
            $mode = isset($condition['mode']) ? $condition['mode'] : 'add';
2275
            switch ($type) {
2276
                case 'positive':
2277
                    if (in_array($itemId, $array)) {
2278
                        if ($mode == 'overwrite') {
2279
                            $class = " $defaultClass $class_to_applied";
2280
                        } else {
2281
                            $class .= " $class_to_applied";
2282
                        }
2283
                    }
2284
                    break;
2285
                case 'negative':
2286
                    if (!in_array($itemId, $array)) {
2287
                        if ($mode == 'overwrite') {
2288
                            $class = " $defaultClass $class_to_applied";
2289
                        } else {
2290
                            $class .= " $class_to_applied";
2291
                        }
2292
                    }
2293
                    break;
2294
            }
2295
        }
2296
        if ($isCurrent) {
2297
            $class = 'before current';
2298
        }
2299
        if ($isMedia && $isCurrent) {
2300
            $class = 'before current';
2301
        }
2302
        if (empty($link)) {
2303
            $link_to_show = '#';
2304
        } else {
2305
            $link_to_show = $link.($nextValue + $localCounter);
2306
        }
2307
        $label = $nextValue + $localCounter + 1;
2308
        if ($isMedia) {
2309
            $label = ($fixedValue + 1).' '.chr(97 + $localCounter);
2310
            $link_to_show = $link.$fixedValue.'#questionanchor'.$itemId;
2311
        }
2312
        $link = self::url($label.' ', $link_to_show, $linkAttributes);
2313
2314
        return  '<li class = "'.$class.'">'.$link.'</li>';
2315
    }
2316
2317
    /**
2318
     * @param int $current
2319
     * @param int $total
2320
     *
2321
     * @return string
2322
     */
2323
    public static function paginationIndicator($current, $total)
2324
    {
2325
        $html = null;
2326
        if (!empty($current) && !empty($total)) {
2327
            $label = sprintf(get_lang('PaginationXofY'), $current, $total);
2328
            $html = self::url($label, '#', ['class' => 'btn disabled']);
2329
        }
2330
2331
        return $html;
2332
    }
2333
2334
    /**
2335
     * Adds a message in the queue.
2336
     *
2337
     * @param string $message
2338
     */
2339
    public static function addFlash($message)
2340
    {
2341
        $messages = Session::read('flash_messages');
2342
        if (empty($messages)) {
2343
            $messages[] = $message;
2344
        } else {
2345
            array_push($messages, $message);
2346
        }
2347
        Session::write('flash_messages', $messages);
2348
    }
2349
2350
    /**
2351
     * @return string
2352
     */
2353
    public static function getFlashToString()
2354
    {
2355
        $messages = Session::read('flash_messages');
2356
        $messageToString = '';
2357
        if (!empty($messages)) {
2358
            foreach ($messages as $message) {
2359
                $messageToString .= $message;
2360
            }
2361
        }
2362
2363
        return $messageToString;
2364
    }
2365
2366
    /**
2367
     * Shows the message from the session.
2368
     */
2369
    public static function showFlash()
2370
    {
2371
        echo self::getFlashToString();
2372
    }
2373
2374
    /**
2375
     * Destroys the message session.
2376
     */
2377
    public static function cleanFlashMessages()
2378
    {
2379
        Session::erase('flash_messages');
2380
    }
2381
2382
    /**
2383
     * Get the profile edition link for a user.
2384
     *
2385
     * @param int  $userId  The user id
2386
     * @param bool $asAdmin Optional. Whether get the URL for the platform admin
2387
     *
2388
     * @return string The link
2389
     */
2390
    public static function getProfileEditionLink($userId, $asAdmin = false)
2391
    {
2392
        $editProfileUrl = api_get_path(WEB_CODE_PATH).'auth/profile.php';
2393
        if ($asAdmin) {
2394
            $editProfileUrl = api_get_path(WEB_CODE_PATH)."admin/user_edit.php?user_id=".intval($userId);
2395
        }
2396
2397
        if (api_get_setting('sso_authentication') === 'true') {
2398
            $subSSOClass = api_get_setting('sso_authentication_subclass');
2399
            $objSSO = null;
2400
2401
            if (!empty($subSSOClass)) {
2402
                $file = api_get_path(SYS_CODE_PATH)."auth/sso/sso.$subSSOClass.class.php";
2403
                if (file_exists($file)) {
2404
                    require_once $file;
2405
                    $subSSOClass = 'sso'.$subSSOClass;
2406
                    $objSSO = new $subSSOClass();
2407
                } else {
2408
                    throw new Exception("$subSSOClass file not set");
2409
                }
2410
            } else {
2411
                $objSSO = new sso();
2412
            }
2413
2414
            $editProfileUrl = $objSSO->generateProfileEditingURL(
2415
                $userId,
2416
                $asAdmin
2417
            );
2418
        }
2419
2420
        return $editProfileUrl;
2421
    }
2422
2423
    /**
2424
     * Get the vCard for a user.
2425
     *
2426
     * @param int $userId The user id
2427
     *
2428
     * @return string *.*vcf file
2429
     */
2430
    public static function getVCardUserLink($userId)
2431
    {
2432
        $vCardUrl = api_get_path(WEB_PATH).'main/social/vcard_export.php?userId='.intval($userId);
2433
2434
        return $vCardUrl;
2435
    }
2436
2437
    /**
2438
     * @param string $content
2439
     * @param string $title
2440
     * @param string $footer
2441
     * @param string $type        primary|success|info|warning|danger
2442
     * @param string $extra
2443
     * @param string $id
2444
     * @param string $customColor
2445
     * @param string $rightAction
2446
     *
2447
     * @return string
2448
     */
2449
    public static function panel(
2450
        $content,
2451
        $title = '',
2452
        $footer = '',
2453
        $type = 'default',
2454
        $extra = '',
2455
        $id = '',
2456
        $customColor = '',
2457
        $rightAction = ''
2458
    ) {
2459
        $headerStyle = '';
2460
        if (!empty($customColor)) {
2461
            $headerStyle = 'style = "color: white; background-color: '.$customColor.'" ';
2462
        }
2463
2464
        if (!empty($rightAction)) {
2465
            $rightAction = '<span class="float-right">'.$rightAction.'</span>';
2466
        }
2467
2468
        $title = !empty($title) ? '<h3 class="card-header">'.$title.' '.$rightAction.'</h3>'.$extra : '';
2469
        $footer = !empty($footer) ? '<div class="card-footer">'.$footer.'</div>' : '';
2470
        $typeList = ['primary', 'success', 'info', 'warning', 'danger'];
2471
        $style = !in_array($type, $typeList) ? 'default' : $type;
2472
2473
        if (!empty($id)) {
2474
            $id = " id='$id'";
2475
        }
2476
2477
        return '
2478
            <div '.$id.' class="card">
2479
                '.$title.'
2480
                '.self::contentPanel($content).'
2481
                '.$footer.'
2482
            </div>'
2483
        ;
2484
    }
2485
2486
    /**
2487
     * @param string $content
2488
     *
2489
     * @return string
2490
     */
2491
    public static function contentPanel($content): string
2492
    {
2493
        if (empty($content)) {
2494
            return '';
2495
        }
2496
2497
        return '<div class="card-text">'.$content.'</div>';
2498
    }
2499
2500
    /**
2501
     * Get the button HTML with an Awesome Font icon.
2502
     *
2503
     * @param string $text        The button content
2504
     * @param string $url         The url to button
2505
     * @param string $icon        The Awesome Font class for icon
2506
     * @param string $type        Optional. The button Bootstrap class. Default 'default' class
2507
     * @param array  $attributes  The additional attributes
2508
     * @param bool   $includeText
2509
     *
2510
     * @return string The button HTML
2511
     */
2512
    public static function toolbarButton(
2513
        $text,
2514
        $url,
2515
        $icon = 'check',
2516
        $type = 'default',
2517
        array $attributes = [],
2518
        $includeText = true
2519
    ) {
2520
        $buttonClass = "btn btn-$type";
2521
        $icon = self::tag('i', null, ['class' => "fa fa-$icon fa-fw", 'aria-hidden' => 'true']);
2522
        $attributes['class'] = isset($attributes['class']) ? "$buttonClass {$attributes['class']}" : $buttonClass;
2523
        $attributes['title'] = isset($attributes['title']) ? $attributes['title'] : $text;
2524
2525
        if (!$includeText) {
2526
            $text = '<span class="sr-only">'.$text.'</span>';
2527
        }
2528
2529
        return self::url("$icon $text", $url, $attributes);
2530
    }
2531
2532
    /**
2533
     * @param string $id
2534
     * @param array  $content
2535
     * @param array  $colsWidth Optional. Columns width
2536
     *
2537
     * @return string
2538
     */
2539
    public static function toolbarAction($id, $content, $colsWidth = [])
2540
    {
2541
        $col = count($content);
2542
2543
        if (!$colsWidth) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $colsWidth of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
2544
            $width = 12 / $col;
2545
            array_walk($content, function () use ($width, &$colsWidth) {
2546
                $colsWidth[] = $width;
2547
            });
2548
        }
2549
2550
        $html = '<div id="'.$id.'" >';
2551
        $html .= '<div class="row">';
2552
2553
        for ($i = 0; $i < $col; $i++) {
2554
            $class = 'col-sm-'.$colsWidth[$i];
2555
2556
            if ($col > 1) {
2557
                if ($i > 0 && $i < count($content) - 1) {
2558
                    $class .= ' text-center';
2559
                } elseif ($i === count($content) - 1) {
2560
                    $class .= ' text-right';
2561
                }
2562
            }
2563
2564
            $html .= '<div class="'.$class.'">'.$content[$i].'</div>';
2565
        }
2566
2567
        $html .= '</div>';
2568
        $html .= '</div>';
2569
2570
        return $html;
2571
    }
2572
2573
    /**
2574
     * Get a HTML code for a icon by Font Awesome.
2575
     *
2576
     * @param string     $name            The icon name
2577
     * @param int|string $size            Optional. The size for the icon. (Example: lg, 2, 3, 4, 5)
2578
     * @param bool       $fixWidth        Optional. Whether add the fw class
2579
     * @param string     $additionalClass Optional. Additional class
2580
     *
2581
     * @return string
2582
     */
2583
    public static function returnFontAwesomeIcon(
2584
        $name,
2585
        $size = '',
2586
        $fixWidth = false,
2587
        $additionalClass = ''
2588
    ) {
2589
        $className = "fa fa-$name";
2590
2591
        if ($fixWidth) {
2592
            $className .= ' fa-fw';
2593
        }
2594
2595
        switch ($size) {
2596
            case 'lg':
2597
                $className .= ' fa-lg';
2598
                break;
2599
            case 2:
2600
            case 3:
2601
            case 4:
2602
            case 5:
2603
                $className .= " fa-{$size}x";
2604
                break;
2605
        }
2606
2607
        if (!empty($additionalClass)) {
2608
            $className .= " $additionalClass";
2609
        }
2610
2611
        $icon = self::tag('em', null, ['class' => $className]);
2612
2613
        return "$icon ";
2614
    }
2615
2616
    /**
2617
     * @param string     $title
2618
     * @param string     $content
2619
     * @param null       $id
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $id is correct as it would always require null to be passed?
Loading history...
2620
     * @param array      $params
2621
     * @param null       $idAccordion
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $idAccordion is correct as it would always require null to be passed?
Loading history...
2622
     * @param null       $idCollapse
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $idCollapse is correct as it would always require null to be passed?
Loading history...
2623
     * @param bool|true  $open
2624
     * @param bool|false $fullClickable
2625
     *
2626
     * @return null|string
2627
     *
2628
     * @todo rework function to easy use
2629
     */
2630
    public static function panelCollapse(
2631
        $title,
2632
        $content,
2633
        $id = null,
2634
        $params = [],
2635
        $idAccordion = null,
2636
        $idCollapse = null,
0 ignored issues
show
Unused Code introduced by
The parameter $idCollapse is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

2636
        /** @scrutinizer ignore-unused */ $idCollapse = null,

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
2637
        $open = true,
2638
        $fullClickable = false
2639
    ) {
2640
        if (!empty($idAccordion)) {
2641
            $headerClass = '';
2642
            $headerClass .= $fullClickable ? 'center-block ' : '';
2643
            $headerClass .= $open ? '' : 'collapsed';
2644
            $contentClass = 'panel-collapse collapse ';
2645
            $contentClass .= $open ? 'in' : '';
2646
            $ariaExpanded = $open ? 'true' : 'false';
2647
            $html = <<<HTML
2648
            
2649
                <div class="card" id="$id">
2650
                    <div class="card-header">                        
2651
                        $title                        
2652
                    </div>                    
2653
                    <div class="card-body">$content</div>                    
2654
                </div>
2655
            
2656
HTML;
2657
        } else {
2658
            if (!empty($id)) {
2659
                $params['id'] = $id;
2660
            }
2661
            $params['class'] = 'card';
2662
            $html = null;
2663
            if (!empty($title)) {
2664
                $html .= '<div class="card-header">'.$title.'</div>'.PHP_EOL;
2665
            }
2666
            $html .= '<div class="card-body">'.$content.'</div>'.PHP_EOL;
2667
            $html = self::div($html, $params);
2668
        }
2669
2670
        return $html;
2671
    }
2672
2673
    /**
2674
     * Returns the string "1 day ago" with a link showing the exact date time.
2675
     *
2676
     * @param string $dateTime in UTC or a DateTime in UTC
2677
     *
2678
     * @return string
2679
     */
2680
    public static function dateToStringAgoAndLongDate($dateTime)
2681
    {
2682
        if (empty($dateTime) || $dateTime === '0000-00-00 00:00:00') {
2683
            return '';
2684
        }
2685
2686
        if ($dateTime instanceof \DateTime) {
0 ignored issues
show
introduced by
$dateTime is never a sub-type of DateTime.
Loading history...
2687
            $dateTime = $dateTime->format('Y-m-d H:i:s');
2688
        }
2689
2690
        return self::tip(
2691
            date_to_str_ago($dateTime),
2692
            api_convert_and_format_date($dateTime, DATE_TIME_FORMAT_LONG)
2693
            //api_get_local_time($dateTime)
2694
        );
2695
    }
2696
2697
    /**
2698
     * @param array  $userInfo
2699
     * @param string $status
2700
     * @param string $toolbar
2701
     *
2702
     * @return string
2703
     */
2704
    public static function getUserCard($userInfo, $status = '', $toolbar = '')
2705
    {
2706
        if (empty($userInfo)) {
2707
            return '';
2708
        }
2709
2710
        if (!empty($status)) {
2711
            $status = '<div class="items-user-status">'.$status.'</div>';
2712
        }
2713
2714
        if (!empty($toolbar)) {
2715
            $toolbar = '<div class="btn-group float-right">'.$toolbar.'</div>';
2716
        }
2717
2718
        return '<div id="user_card_'.$userInfo['id'].'" class="card d-flex flex-row">                    
2719
                    <img src="'.$userInfo['avatar'].'" class="rounded">
2720
                    <h3 class="card-title">'.$userInfo['complete_name'].'</h3>                    
2721
                    <div class="card-body">                       
2722
                       <div class="card-title">
2723
                       '.$status.'
2724
                       '.$toolbar.'
2725
                       </div> 
2726
                    </div>
2727
                    <hr />
2728
              </div>';
2729
    }
2730
2731
    /**
2732
     * Displays the reduced page header (without banner).
2733
     */
2734
    private static function set_header()
2735
    {
2736
        global $show_learnpath, $tool_name;
2737
        self::$global_template = new Template(
2738
            $tool_name,
2739
            false,
2740
            false,
2741
            $show_learnpath
2742
        );
2743
    }
2744
}
2745