Template   F
last analyzed

Complexity

Total Complexity 159

Size/Duplication

Total Lines 1301
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 590
dl 0
loc 1301
rs 2
c 0
b 0
f 0
wmc 159

41 Methods

Rating   Name   Duplication   Size   Complexity  
B displayLoginForm() 0 107 4
B setCssFiles() 0 53 9
A getGlobals() 0 11 1
A get_template() 0 3 1
A display() 0 15 2
A displayBlankTemplateNoHeader() 0 5 1
B isToolBarDisplayedForUser() 0 25 8
A display_blank_template() 0 5 1
A display_one_col_template() 0 10 2
A findTemplateFilePath() 0 25 5
A displayTemplate() 0 4 1
A displayTwoColTemplate() 0 6 1
A setHelp() 0 25 4
A displaySkillLayout() 0 5 1
A set_actions() 0 9 3
A getThemeDir() 0 13 3
B setCssCustomFiles() 0 54 9
A set_header() 0 18 2
A display_no_layout_template() 0 5 1
F set_js_files() 0 123 23
A __construct() 0 73 5
A getWebPaths() 0 22 3
A fetch() 0 3 1
A loadLegacyParams() 0 25 5
A returnResponse() 0 6 1
A enableCookieUsageWarning() 0 33 2
A set_course_parameters() 0 24 3
A show_footer_js_template() 0 4 1
A getResponseCode() 0 3 1
B set_js_files_post() 0 16 7
A assignAccessibilityBlock() 0 15 2
A setLoginBodyClass() 0 3 1
A returnTutorsNames() 0 24 2
A setResponseCode() 0 3 1
A assign() 0 3 1
F assignSocialMeta() 0 94 17
D addHTTPSecurityHeaders() 0 47 10
A setVueParams() 0 3 1
A getThemeFallback() 0 3 1
A getMetaPortalImagePath() 0 28 5
B assignBugNotification() 0 40 7

How to fix   Complexity   

Complex Class

Complex classes like Template often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Template, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* For licensing terms, see /license.txt */
4
5
use Chamilo\CoreBundle\Entity\Session;
6
use Chamilo\CoreBundle\Entity\User;
7
use Chamilo\CoreBundle\Enums\ToolIcon;
8
use Chamilo\CoreBundle\Framework\Container;
9
use Symfony\Component\Filesystem\Exception\FileNotFoundException;
10
use Symfony\Component\HttpFoundation\Response;
11
12
/**
13
 * Class Template.
14
 *
15
 * @author Julio Montoya <[email protected]>
16
 *
17
 * @todo better organization of the class, methods and variables
18
 */
19
class Template
20
{
21
    /**
22
     * The Template folder name see main/template.
23
     *
24
     * @var string
25
     */
26
    public $templateFolder = 'default';
27
28
    /**
29
     * The theme that will be used: chamilo, public_admin, chamilo_red, etc
30
     * This variable is set from the database.
31
     *
32
     * @var string
33
     */
34
    public $theme = '';
35
36
    /**
37
     * @var string
38
     */
39
    public $preview_theme = '';
40
    public $title = null;
41
    public $show_header;
42
    public $show_footer;
43
    public $help;
44
    public $menu_navigation = []; //Used in the userportal.lib.php function: return_navigation_course_links()
45
    public $show_learnpath = false; // This is a learnpath section or not?
46
    public $plugin = null;
47
    public $course_id = null;
48
    public $user_is_logged_in = false;
49
    public $twig = null;
50
51
    /* Loads chamilo plugins */
52
    public $load_plugins = false;
53
    public $params = [];
54
    public $force_plugin_load = false;
55
    public $responseCode = 0;
56
    private $themeDir;
57
58
    /**
59
     * @param string $title
60
     * @param bool   $show_header
61
     * @param bool   $show_footer
62
     * @param bool   $show_learnpath
63
     * @param bool   $hide_global_chat
64
     * @param bool   $load_plugins
65
     * @param int    $responseCode
66
     * @param bool   $sendHeaders      send http headers or not
67
     */
68
    public function __construct(
69
        $title = '',
70
        $show_header = true,
71
        $show_footer = true,
72
        $show_learnpath = false,
73
        $hide_global_chat = false,
74
        $load_plugins = true,
75
        $sendHeaders = true,
76
        $responseCode = 0
77
    ) {
78
        // Page title
79
        $this->title = $title;
80
        global $interbreadcrumb;
81
82
        if (!empty($title)) {
83
            $interbreadcrumb[] = ['url' => '#', 'name' => $title];
84
        }
85
86
        $this->show_learnpath = $show_learnpath;
87
88
        if (empty($this->show_learnpath)) {
89
            $origin = api_get_origin();
90
            if ('learnpath' === $origin) {
91
                $this->show_learnpath = true;
92
                $show_footer = false;
93
                $show_header = false;
94
            }
95
        }
96
        $this->hide_global_chat = $hide_global_chat;
97
        $this->load_plugins = $load_plugins;
98
99
        /*$template_paths = [
100
            api_get_path(SYS_CODE_PATH).'template/overrides', // user defined templates
101
            api_get_path(SYS_CODE_PATH).'template', //template folder
102
            api_get_path(SYS_PLUGIN_PATH), // plugin folder
103
            api_get_path(SYS_PATH).'src/ThemeBundle/Resources/views',
104
        ];*/
105
106
        $this->twig = Container::getTwig();
107
108
        // Setting app paths/URLs
109
        $this->assign('_p', $this->getWebPaths());
110
111
        // Here we can add system parameters that can be use in any template
112
        $_s = [
113
            'software_name' => api_get_configuration_value('software_name'),
114
            'system_version' => api_get_configuration_value('system_version'),
115
            'site_name' => api_get_setting('siteName'),
116
            'institution' => api_get_setting('Institution'),
117
            'institution_url' => api_get_setting('InstitutionUrl'),
118
            'date' => api_format_date('now', DATE_FORMAT_LONG),
119
            'timezone' => api_get_timezone(),
120
            'gamification_mode' => api_get_setting('gamification_mode'),
121
        ];
122
        $this->assign('_s', $_s);
123
124
        // Setting user variables
125
        //$this->set_user_parameters();
126
127
        // Setting course variables
128
        //$this->set_course_parameters();
129
130
        // Setting administrator variables
131
        //$this->setAdministratorParams();
132
        //$this->setCSSEditor();
133
134
        // Header and footer are showed by default
135
        //$this->set_footer($show_footer);
136
        //$this->set_header($show_header);
137
138
        $defaultStyle = api_get_env_variable('DEFAULT_TEMPLATE', 'default');
139
        if (!empty($defaultStyle)) {
140
            $this->templateFolder = $defaultStyle;
141
        }
142
    }
143
144
    private function getWebPaths()
145
    {
146
        $queryString = empty($_SERVER['QUERY_STRING']) ? '' : $_SERVER['QUERY_STRING'];
147
        $requestURI = empty($_SERVER['REQUEST_URI']) ? '' : $_SERVER['REQUEST_URI'];
148
149
        return [
150
            'web' => api_get_path(WEB_PATH),
151
            'web_relative' => api_get_path(REL_PATH),
152
            'web_course' => api_get_path(WEB_COURSE_PATH),
153
            'web_main' => api_get_path(WEB_CODE_PATH),
154
            'web_css' => api_get_path(WEB_CSS_PATH),
155
            'web_css_theme' => api_get_path(WEB_CSS_PATH).$this->themeDir,
156
            'web_ajax' => api_get_path(WEB_AJAX_PATH),
157
            'web_img' => api_get_path(WEB_IMG_PATH),
158
            'web_plugin' => api_get_path(WEB_PLUGIN_PATH),
159
            'web_lib' => api_get_path(WEB_LIBRARY_PATH),
160
            'web_self' => api_get_self(),
161
            'self_basename' => basename(api_get_self()),
162
            'web_query_vars' => api_htmlentities($queryString),
163
            'web_self_query_vars' => api_htmlentities($requestURI),
164
            'web_cid_query' => api_get_cidreq(),
165
            'web_rel_code' => api_get_path(REL_CODE_PATH),
166
        ];
167
    }
168
169
    /**
170
     * @param string $helpInput
171
     */
172
    public function setHelp($helpInput = null)
173
    {
174
        if (!empty($helpInput)) {
175
            $help = $helpInput;
176
        } else {
177
            $help = $this->help;
178
        }
179
180
        $content = '';
181
        if ('true' == api_get_setting('enable_help_link')) {
182
            if (!empty($help)) {
183
                $help = Security::remove_XSS($help);
184
                $content = '<div class="help">';
185
                $content .= Display::url(
186
                    Display::getMdiIcon(ToolIcon::HELP, 'ch-tool-icon', null, ICON_SIZE_LARGE, get_lang('Help')),
187
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='.$help,
188
                    [
189
                        'class' => 'ajax',
190
                        'data-title' => get_lang('Help'),
191
                    ]
192
                );
193
                $content .= '</div>';
194
            }
195
        }
196
        $this->assign('help_content', $content);
197
    }
198
199
    /**
200
     * Use template system to parse the actions menu.
201
     *
202
     * @todo finish it!
203
     */
204
    public function set_actions($actions)
205
    {
206
        $action_string = '';
207
        if (!empty($actions)) {
208
            foreach ($actions as $action) {
209
                $action_string .= $action;
210
            }
211
        }
212
        $this->assign('actions', $actions);
213
    }
214
215
    /**
216
     * Render the template.
217
     *
218
     * @param string $template The template path
219
     */
220
    public function display($template)
221
    {
222
        $template = str_replace('tpl', 'html.twig', $template);
223
        $templateFile = api_get_path(SYS_CODE_PATH).'template/'.$template;
224
225
        $this->loadLegacyParams();
226
227
        if (!file_exists($templateFile)) {
228
            $e = new FileNotFoundException($templateFile);
229
            echo $e->getMessage();
230
            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...
231
        }
232
233
        $this->setVueParams($this->params);
234
        $this->returnResponse($this->params, $template);
235
    }
236
237
    /**
238
     * @param string $template
239
     *
240
     * @throws \Twig\Error\Error
241
     */
242
    public function displayTemplate($template)
243
    {
244
        $this->loadLegacyParams();
245
        $this->returnResponse($this->params, $template);
246
    }
247
248
    /**
249
     * Shortcut to display a 1 col layout (index.php).
250
     * */
251
    public function display_one_col_template()
252
    {
253
        $this->loadLegacyParams();
254
        $template = '@ChamiloCore/Layout/layout_one_col.html.twig';
255
        $origin = api_get_origin();
256
        if ('learnpath' === $origin) {
257
            $template = '@ChamiloCore/Layout/no_layout.html.twig';
258
        }
259
        $this->setVueParams($this->params);
260
        $this->returnResponse($this->params, $template);
261
    }
262
263
    public function displayTwoColTemplate()
264
    {
265
        $this->loadLegacyParams();
266
        $template = '@ChamiloCore/Layout/layout_two_col.html.twig';
267
        $this->setVueParams($this->params);
268
        $this->returnResponse($this->params, $template);
269
    }
270
271
    /**
272
     * Displays an empty template.
273
     */
274
    public function display_blank_template()
275
    {
276
        $this->loadLegacyParams();
277
        $template = '@ChamiloCore/Layout/blank.html.twig';
278
        $this->returnResponse($this->params, $template);
279
    }
280
281
    /**
282
     * Displays an empty template.
283
     */
284
    public function displayBlankTemplateNoHeader()
285
    {
286
        $this->loadLegacyParams();
287
        $template = '@ChamiloCore/Layout/blank_no_header.html.twig';
288
        $this->returnResponse($this->params, $template);
289
    }
290
291
    /**
292
     * Displays an empty template.
293
     */
294
    public function display_no_layout_template()
295
    {
296
        $this->loadLegacyParams();
297
        $template = '@ChamiloCore/Layout/no_layout.html.twig';
298
        $this->returnResponse($this->params, $template);
299
    }
300
301
    /**
302
     * Displays an empty template.
303
     */
304
    public function displaySkillLayout()
305
    {
306
        $this->loadLegacyParams();
307
        $template = '@ChamiloCore/Layout/skill_layout.html.twig';
308
        $this->returnResponse($this->params, $template);
309
    }
310
311
    /**
312
     * return true if toolbar has to be displayed for user.
313
     *
314
     * @return bool
315
     */
316
    public static function isToolBarDisplayedForUser()
317
    {
318
        //Toolbar
319
        $show_admin_toolbar = api_get_setting('show_admin_toolbar');
320
        $show_toolbar = false;
321
322
        switch ($show_admin_toolbar) {
323
            case 'do_not_show':
324
                break;
325
            case 'show_to_admin':
326
                if (api_is_platform_admin()) {
327
                    $show_toolbar = true;
328
                }
329
                break;
330
            case 'show_to_admin_and_teachers':
331
                if (api_is_platform_admin() || api_is_allowed_to_edit()) {
332
                    $show_toolbar = true;
333
                }
334
                break;
335
            case 'show_to_all':
336
                $show_toolbar = true;
337
                break;
338
        }
339
340
        return $show_toolbar;
341
    }
342
343
    /**
344
     * Sets the header visibility.
345
     *
346
     * @param bool true if we show the header
347
     */
348
    public function set_header($status)
349
    {
350
        $this->show_header = $status;
351
        $this->assign('show_header', $status);
352
353
        $show_toolbar = 0;
354
355
        if (self::isToolBarDisplayedForUser()) {
356
            $show_toolbar = 1;
357
        }
358
359
        $this->assign('show_toolbar', $show_toolbar);
360
361
        // Only if course is available
362
        $courseToolBar = '';
363
        $show_course_navigation_menu = '';
364
        $this->assign('show_course_shortcut', $courseToolBar);
365
        $this->assign('show_course_navigation_menu', $show_course_navigation_menu);
366
    }
367
368
    /**
369
     * Returns the sub-folder and filename for the given tpl file.
370
     *
371
     * If template not found in overrides/ or custom template folder, the default template will be used.
372
     *
373
     * @param string $name
374
     *
375
     * @return string
376
     */
377
    public static function findTemplateFilePath($name)
378
    {
379
        $sysTemplatePath = api_get_path(SYS_TEMPLATE_PATH);
380
381
        // Check if the tpl file is present in the main/template/overrides/ dir
382
        // Overrides is a special directory meant for temporary template
383
        // customization. It must be taken into account before anything else
384
        if (is_readable($sysTemplatePath."overrides/$name")) {
385
            return "overrides/$name";
386
        }
387
388
        $defaultFolder = api_get_env_variable('DEFAULT_TEMPLATE', 'default');
389
390
        // If a template folder has been manually defined, search for the right
391
        // file, and if not found, go for the same file in the default template
392
        if ($defaultFolder && 'default' != $defaultFolder) {
393
            // Avoid missing template error, use the default file.
394
            if (file_exists($sysTemplatePath."$defaultFolder/$name")) {
395
                return "$defaultFolder/$name";
396
            }
397
        }
398
399
        $name = str_replace('tpl', 'html.twig', $name);
400
401
        return "default/$name";
402
    }
403
404
    /**
405
     * Call non-static for Template::findTemplateFilePath.
406
     *
407
     * @see Template::findTemplateFilePath()
408
     *
409
     * @param string $name
410
     *
411
     * @return string
412
     */
413
    public function get_template($name)
414
    {
415
        return api_find_template($name);
416
    }
417
418
    /**
419
     * Get CSS themes sub-directory.
420
     *
421
     * @param string $theme
422
     *
423
     * @return string with a trailing slash, e.g. 'themes/chamilo_red/'
424
     */
425
    public static function getThemeDir($theme)
426
    {
427
        $themeDir = 'themes/'.$theme.'/';
428
        $virtualTheme = api_get_configuration_value('virtual_css_theme_folder');
429
        if (!empty($virtualTheme)) {
430
            $virtualThemeList = api_get_themes(true);
431
            $isVirtualTheme = in_array($theme, array_keys($virtualThemeList));
432
            if ($isVirtualTheme) {
433
                $themeDir = 'themes/'.$virtualTheme.'/'.$theme.'/';
434
            }
435
        }
436
437
        return $themeDir;
438
    }
439
440
    /**
441
     * Set legacy twig globals in order to be hook in the LegacyListener.php.
442
     *
443
     * @return array
444
     */
445
    public static function getGlobals()
446
    {
447
        return [
448
            '_s' => [
449
                'software_name' => api_get_configuration_value('software_name'),
450
                'system_version' => api_get_configuration_value('system_version'),
451
                'site_name' => api_get_setting('siteName'),
452
                'institution' => api_get_setting('Institution'),
453
                'gamification_mode' => api_get_setting('gamification_mode'),
454
            ],
455
            'template' => 'default', // @todo setup template folder in config.yml;
456
        ];
457
    }
458
459
    /**
460
     * Set theme, include mainstream CSS files.
461
     *
462
     * @deprecated
463
     * @see setCssCustomFiles() for additional CSS sheets
464
     */
465
    public function setCssFiles()
466
    {
467
        global $disable_js_and_css_files;
468
        $css = [];
469
470
        // Default CSS Bootstrap
471
        $bowerCSSFiles = [
472
            'fontawesome/css/font-awesome.min.css',
473
            'jquery-ui/themes/smoothness/theme.css',
474
            'jquery-ui/themes/smoothness/jquery-ui.min.css',
475
            'mediaelement/build/mediaelementplayer.min.css',
476
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.css',
477
            'bootstrap/dist/css/bootstrap.min.css',
478
            'jquery.scrollbar/jquery.scrollbar.css',
479
            //'bootstrap-daterangepicker/daterangepicker.css',
480
            'bootstrap-select/dist/css/bootstrap-select.min.css',
481
            'select2/dist/css/select2.min.css',
482
            'mediaelement/plugins/vrview/vrview.css',
483
        ];
484
485
        $features = api_get_setting('platform.video_features', true);
486
        $defaultFeatures = ['playpause', 'current', 'progress', 'duration', 'tracks', 'volume', 'fullscreen', 'vrview'];
487
488
        if (!empty($features) && isset($features['features'])) {
489
            foreach ($features['features'] as $feature) {
490
                if ('vrview' === $feature) {
491
                    continue;
492
                }
493
                $bowerCSSFiles[] = "mediaelement/plugins/$feature/$feature.css";
494
                $defaultFeatures[] = $feature;
495
            }
496
        }
497
498
        foreach ($bowerCSSFiles as $file) {
499
            //$css[] = api_get_path(WEB_PUBLIC_PATH).'assets/'.$file;
500
        }
501
502
        //$css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chosen/chosen.css';
503
504
        if (api_is_global_chat_enabled()) {
505
            $css[] = api_get_path(WEB_LIBRARY_PATH).'javascript/chat/css/chat.css';
506
        }
507
        $css_file_to_string = '';
508
        foreach ($css as $file) {
509
            $css_file_to_string .= api_get_css($file);
510
        }
511
512
        if (!$disable_js_and_css_files) {
513
            $this->assign('css_static_file_to_string', $css_file_to_string);
514
        }
515
516
        $defaultFeatures = implode("','", $defaultFeatures);
517
        $this->assign('video_features', $defaultFeatures);
518
    }
519
520
    /**
521
     * Prepare custom CSS to be added at the very end of the <head> section.
522
     *
523
     * @see setCssFiles() for the mainstream CSS files
524
     */
525
    public function setCssCustomFiles()
526
    {
527
        global $disable_js_and_css_files;
528
        $css = [];
529
        if ($this->show_learnpath) {
530
            if (is_file(api_get_path(SYS_CSS_PATH).$this->themeDir.'learnpath.css')) {
531
                $css[] = api_get_path(WEB_CSS_PATH).$this->themeDir.'learnpath.css';
532
            }
533
        }
534
535
        $css_file_to_string = '';
536
        foreach ($css as $file) {
537
            $css_file_to_string .= api_get_css($file);
538
        }
539
540
        // @todo move this somewhere else. Special fix when using tablets in order to see the text near icons
541
        if (SHOW_TEXT_NEAR_ICONS == true) {
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...
542
            //hack in order to fix the actions buttons
543
            $css_file_to_string .= '<style>
544
                .td_actions a {
545
                    float:left;
546
                    width:100%;
547
                }
548
                .forum_message_left a {
549
                    float:left;
550
                    width:100%;
551
                }
552
                </style>';
553
        }
554
555
        $navigator_info = api_get_navigator();
556
        if ('Internet Explorer' == $navigator_info['name'] && '6' == $navigator_info['version']) {
557
            $css_file_to_string .= 'img, div { behavior: url('.api_get_path(WEB_LIBRARY_PATH).'javascript/iepngfix/iepngfix.htc) } '."\n";
558
        }
559
560
        if (!$disable_js_and_css_files) {
561
            $this->assign('css_custom_file_to_string', $css_file_to_string);
562
563
            $style_print = '';
564
            if (is_readable(api_get_path(SYS_CSS_PATH).$this->theme.'/print.css')) {
565
                $style_print = api_get_css(
566
                    api_get_path(WEB_CSS_PATH).$this->theme.'/print.css',
567
                    'print'
568
                );
569
            }
570
            $this->assign('css_style_print', $style_print);
571
        }
572
573
        // Logo
574
        $logo = return_logo($this->theme);
575
        $logoPdf = return_logo($this->theme, false);
576
        $this->assign('logo', $logo);
577
        $this->assign('logo_pdf', $logoPdf);
578
        $this->assign('show_media_element', 1);
579
    }
580
581
    /**
582
     * Declare and define the template variable that will be used to load
583
     * javascript libraries in the header.
584
     */
585
    public function set_js_files()
586
    {
587
        global $disable_js_and_css_files, $htmlHeadXtra;
588
        $isoCode = api_get_language_isocode();
589
        $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_'.strtoupper($isoCode).'.min.js';
590
591
        if ('en' == $isoCode) {
592
            $selectLink = 'bootstrap-select/dist/js/i18n/defaults-'.$isoCode.'_US.min.js';
593
        }
594
        // JS files
595
        $js_files = [
596
            'chosen/chosen.jquery.min.js',
597
        ];
598
599
        $viewBySession = 'true' === api_get_setting('my_courses_view_by_session');
600
601
        if (api_is_global_chat_enabled() || $viewBySession) {
602
            // Do not include the global chat in LP
603
            if (false == $this->show_learnpath &&
604
                true == $this->show_footer &&
605
                false == $this->hide_global_chat
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...
606
            ) {
607
                $js_files[] = 'chat/js/chat.js';
608
            }
609
        }
610
611
        if ('true' === api_get_setting('accessibility_font_resize')) {
612
            $js_files[] = 'fontresize.js';
613
        }
614
615
        $js_file_to_string = '';
616
        $bowerJsFiles = [
617
            'modernizr/modernizr.js',
618
            'jquery/query.min.js',
619
            'bootstrap/dist/js/bootstrap.min.js',
620
            'jquery-ui/jquery-ui.min.js',
621
            'jqueryui-touch-punch/jquery.ui.touch-punch.min.js',
622
            'moment/min/moment-with-locales.js',
623
            //'bootstrap-daterangepicker/daterangepicker.js',
624
            'jquery-timeago/jquery.timeago.js',
625
            'mediaelement/mediaelement-and-player.min.js',
626
            'jqueryui-timepicker-addon/dist/jquery-ui-timepicker-addon.min.js',
627
            'image-map-resizer/js/imageMapResizer.min.js',
628
            'jquery.scrollbar/jquery.scrollbar.min.js',
629
            //'readmore-js/readmore.min.js',
630
            'bootstrap-select/dist/js/bootstrap-select.min.js',
631
            $selectLink,
632
            'select2/dist/js/select2.min.js',
633
            "select2/dist/js/i18n/$isoCode.js",
634
            'mediaelement/plugins/vrview/vrview.js',
635
        ];
636
637
        $features = api_get_setting('platform.video_features', true);
638
        if (!empty($features) && isset($features['features'])) {
639
            foreach ($features['features'] as $feature) {
640
                if ('vrview' === $feature) {
641
                    continue;
642
                }
643
                $bowerJsFiles[] = "mediaelement/plugins/$feature/$feature.js";
644
            }
645
        }
646
647
        if ('true' === api_get_setting('include_asciimathml_script')) {
648
            $bowerJsFiles[] = 'MathJax/MathJax.js?config=TeX-MML-AM_HTMLorMML';
649
        }
650
651
        if ('en' != $isoCode) {
652
            $bowerJsFiles[] = 'jqueryui-timepicker-addon/dist/i18n/jquery-ui-timepicker-'.$isoCode.'.js';
653
            $bowerJsFiles[] = 'jquery-ui/ui/minified/i18n/datepicker-'.$isoCode.'.min.js';
654
        }
655
656
        foreach ($bowerJsFiles as $file) {
657
            //$js_file_to_string .= '<script type="text/javascript" src="'.api_get_path(WEB_PUBLIC_PATH).'assets/'.$file.'"></script>'."\n";
658
        }
659
660
        foreach ($js_files as $file) {
661
            //$js_file_to_string .= api_get_js($file);
662
        }
663
664
        // Loading email_editor js
665
        if (!api_is_anonymous() && 'true' == api_get_setting('allow_email_editor')) {
666
            $template = $this->get_template('mail_editor/email_link.js.tpl');
667
            $js_file_to_string .= $this->fetch($template);
668
        }
669
670
        if (!$disable_js_and_css_files) {
671
            $this->assign('js_file_to_string', $js_file_to_string);
672
            $extraHeaders = '';
673
            //$extraHeaders = '<script>var _p = '.json_encode($this->getWebPaths(), JSON_PRETTY_PRINT).'</script>';
674
            //Adding jquery ui by default
675
            $extraHeaders .= api_get_jquery_ui_js();
676
            if (isset($htmlHeadXtra) && $htmlHeadXtra) {
677
                foreach ($htmlHeadXtra as &$this_html_head) {
678
                    $extraHeaders .= $this_html_head."\n";
679
                }
680
            }
681
682
            $ajax = api_get_path(WEB_AJAX_PATH);
683
            $courseId = api_get_course_id();
684
            if (empty($courseId)) {
685
                $courseLogoutCode = '
686
                <script>
687
                function courseLogout() {
688
                }
689
                </script>';
690
            } else {
691
                $courseLogoutCode = "
692
                <script>
693
                var logOutUrl = '".$ajax."course.ajax.php?a=course_logout&".api_get_cidreq()."';
694
                function courseLogout() {
695
                    $.ajax({
696
                        async : false,
697
                        url: logOutUrl,
698
                        success: function (data) {
699
                            return 1;
700
                        }
701
                    });
702
                }
703
                </script>";
704
            }
705
706
            $extraHeaders .= $courseLogoutCode;
707
            $this->assign('extra_headers', $extraHeaders);
708
        }
709
    }
710
711
    public static function setVueParams(&$params)
712
    {
713
        $params['is_authenticated'] = !api_is_anonymous();
714
        /*$user = api_get_user_entity(api_get_user_id());
715
        $encoded = '';
716
        if ($user) {
717
            $encoded = json_encode($user);
718
        }
719
        $params['user'] = $encoded;*/
720
    }
721
722
    /**
723
     * @param array  $params
724
     * @param string $template
725
     *
726
     * @throws \Twig\Error\Error
727
     */
728
    public function returnResponse($params, $template)
729
    {
730
        $response = new Response();
731
        $content = Container::getTwig()->render($template, $params);
732
        $response->setContent($content);
733
        $response->send();
734
    }
735
736
    /**
737
     * Special function to declare last-minute JS libraries which depend on
738
     * other things to be declared first. In particular, it might be useful
739
     * under IE9 with compatibility mode, which for some reason is getting
740
     * upset when a variable is used in a function (even if not used yet)
741
     * when this variable hasn't been defined yet.
742
     */
743
    public function set_js_files_post()
744
    {
745
        global $disable_js_and_css_files;
746
        $js_files = [];
747
        if (api_is_global_chat_enabled()) {
748
            //Do not include the global chat in LP
749
            if (false == $this->show_learnpath && true == $this->show_footer && false == $this->hide_global_chat) {
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...
750
                $js_files[] = 'chat/js/chat.js';
751
            }
752
        }
753
        $js_file_to_string = '';
754
        foreach ($js_files as $js_file) {
755
            $js_file_to_string .= api_get_js($js_file);
756
        }
757
        if (!$disable_js_and_css_files) {
758
            $this->assign('js_file_to_string_post', $js_file_to_string);
759
        }
760
    }
761
762
    /**
763
     * Show footer js template.
764
     */
765
    public function show_footer_js_template()
766
    {
767
        $tpl = $this->get_template('layout/footer.js.tpl');
768
        $this->display($tpl);
769
    }
770
771
    /**
772
     * @param string $template
773
     *
774
     * @return string
775
     */
776
    public function fetch($template = null)
777
    {
778
        return $this->twig->render($template, $this->params);
779
    }
780
781
    /**
782
     * @param string $variable
783
     * @param mixed  $value
784
     */
785
    public function assign($variable, $value = '')
786
    {
787
        $this->params[$variable] = $value;
788
    }
789
790
    /**
791
     * Adds a body class for login pages.
792
     */
793
    public function setLoginBodyClass()
794
    {
795
        $this->assign('login_class', 'section-login');
796
    }
797
798
    /**
799
     * The theme that will be used if the database is not working.
800
     *
801
     * @return string
802
     */
803
    public static function getThemeFallback(): string
804
    {
805
        return 'chamilo';
806
    }
807
808
    /**
809
     * @return string
810
     */
811
    public function displayLoginForm()
812
    {
813
        $form = new FormValidator(
814
            'form-login',
815
            'POST',
816
            api_get_path(WEB_PUBLIC_PATH).'login_check',
817
            null,
818
            null,
819
            FormValidator::LAYOUT_BOX_NO_LABEL
820
        );
821
        $params = [
822
            'id' => '_username',
823
            'autofocus' => 'autofocus',
824
            'icon' => 'user fa-fw',
825
            'placeholder' => get_lang('Username'),
826
        ];
827
828
        // Avoid showing the autocapitalize option if the browser doesn't
829
        // support it: this attribute is against the HTML5 standard
830
        /*$browserAutoCapitalize = false;
831
        if (api_browser_support('autocapitalize')) {
832
            $browserAutoCapitalize = false;
833
            $params['autocapitalize'] = 'none';
834
        }*/
835
        $form->addText(
836
            '_username',
837
            get_lang('Username'),
838
            true,
839
            $params
840
        );
841
        $params = [
842
            'id' => '_password',
843
            'icon' => 'lock fa-fw',
844
            'placeholder' => get_lang('Pass'),
845
        ];
846
        /*if ($browserAutoCapitalize) {
847
            $params['autocapitalize'] = 'none';
848
        }*/
849
        $form->addElement(
850
            'password',
851
            '_password',
852
            get_lang('Pass'),
853
            $params
854
        );
855
856
        $token = Chamilo\CoreBundle\Framework\Container::$container->get('security.csrf.token_manager')->getToken('authenticate');
0 ignored issues
show
Bug introduced by
The method get() does not exist on null. ( Ignorable by Annotation )

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

856
        $token = Chamilo\CoreBundle\Framework\Container::$container->/** @scrutinizer ignore-call */ get('security.csrf.token_manager')->getToken('authenticate');

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
857
        $form->addHidden('_csrf_token', $token->getValue());
858
859
        // Captcha
860
        $captcha = api_get_setting('allow_captcha');
861
        $allowCaptcha = 'true' === $captcha;
862
863
        if ($allowCaptcha) {
864
            $useCaptcha = isset($_SESSION['loginFailed']) ? $_SESSION['loginFailed'] : null;
865
            if ($useCaptcha) {
866
                $ajax = api_get_path(WEB_AJAX_PATH).'form.ajax.php?a=get_captcha';
867
                $options = [
868
                    'width' => 250,
869
                    'height' => 90,
870
                    'callback' => $ajax.'&var='.basename(__FILE__, '.php'),
871
                    'sessionVar' => basename(__FILE__, '.php'),
872
                    'imageOptions' => [
873
                        'font_size' => 20,
874
                        'font_path' => api_get_path(SYS_FONTS_PATH).'opensans/',
875
                        'font_file' => 'OpenSans-Regular.ttf',
876
                        //'output' => 'gif'
877
                    ],
878
                ];
879
880
                // Minimum options using all defaults (including defaults for Image_Text):
881
                //$options = array('callback' => 'qfcaptcha_image.php');
882
                $captcha_question = $form->addElement('CAPTCHA_Image', 'captcha_question', '', $options);
883
                $form->addHtml(get_lang('Click on the image to load a new one.'));
884
885
                $form->addElement(
886
                    'text',
887
                    'captcha',
888
                    get_lang('Enter the letters you see.')
889
                );
890
                $form->addRule(
891
                    'captcha',
892
                    get_lang('Enter the characters you see on the image'),
893
                    'required',
894
                    null,
895
                    'client'
896
                );
897
                $form->addRule(
898
                    'captcha',
899
                    get_lang('The text you entered doesn\'t match the picture.'),
900
                    'CAPTCHA',
901
                    $captcha_question
902
                );
903
            }
904
        }
905
906
        $form->addButton(
907
            'submitAuth',
908
            get_lang('Login'),
909
            null,
910
            'primary',
911
            null,
912
            'btn-block'
913
        );
914
915
        $html = $form->returnForm();
916
917
        return $html;
918
    }
919
920
    public function enableCookieUsageWarning()
921
    {
922
        $form = new FormValidator(
923
            'cookiewarning',
924
            'post',
925
            '',
926
            '',
927
            [
928
                //'onsubmit' => "$(this).toggle('show')",
929
            ],
930
            FormValidator::LAYOUT_BOX_NO_LABEL
931
        );
932
        $form->addHidden('acceptCookies', '1');
933
        $form->addHtml(
934
            '<div class="cookieUsageValidation">
935
                '.get_lang('By continuing to use this site, you declare you accept its use of cookies.').'
936
                <button class="btn btn-link" onclick="$(this).next().toggle(\'slow\'); $(this).toggle(\'slow\')" type="button">
937
                    ('.get_lang('More').')
938
                </button>
939
                <div style="display:none; margin:20px 0;">
940
                    '.get_lang("In order for this site to work and be able to measure the use of content, this platform uses cookies.<br /><br />\nIf needed, the Help section of your browser indicates how to configure cookies.<br /><br />\nFor more information on cookies, you can visit the <a href=\"http://www.aboutcookies.org/\">About Cookies</a> website.").'
941
                </div>
942
                <button class="btn btn-link" onclick="$(this).parents(\'form\').submit()" type="button">
943
                    ('.get_lang('Accept').')
944
                </button>
945
            </div>'
946
        );
947
        $form->protect();
948
949
        if ($form->validate()) {
950
            api_set_site_use_cookie_warning_cookie();
951
        } else {
952
            $this->assign('frmDisplayCookieUsageWarning', $form->returnForm());
953
        }
954
    }
955
956
    /**
957
     * Returns the tutors names for the current course in session
958
     * Function to use in Twig templates.
959
     *
960
     * @return string
961
     */
962
    public static function returnTutorsNames()
963
    {
964
        $em = Database::getManager();
965
        $tutors = $em
966
            ->createQuery('
967
                SELECT u FROM ChamiloCoreBundle:User u
968
                INNER JOIN ChamiloCoreBundle:SessionRelCourseRelUser scu WITH u.id = scu.user
969
                WHERE scu.status = :teacher_status AND scu.session = :session AND scu.course = :course
970
            ')
971
            ->setParameters([
972
                'teacher_status' => Session::COURSE_COACH,
973
                'session' => api_get_session_id(),
974
                'course' => api_get_course_int_id(),
975
            ])
976
            ->getResult();
977
978
        $names = [];
979
980
        /** @var User $tutor */
981
        foreach ($tutors as $tutor) {
982
            $names[] = UserManager::formatUserFullName($tutor);
983
        }
984
985
        return implode(CourseManager::USER_SEPARATOR, $names);
986
    }
987
988
    /**
989
     * @param int $code
990
     */
991
    public function setResponseCode($code)
992
    {
993
        $this->responseCode = $code;
994
    }
995
996
    public function getResponseCode()
997
    {
998
        return $this->responseCode;
999
    }
1000
1001
    /**
1002
     * Assign HTML code to the 'bug_notification' template variable for the side tabs to report issues.
1003
     *
1004
     * @return bool Always return true because there is always a string, even if empty
1005
     */
1006
    public function assignBugNotification()
1007
    {
1008
        //@todo move this in the template
1009
        $rightFloatMenu = '';
1010
        $iconBug = Display::getMdiIcon(ToolIcon::BUG_REPORT, 'ch-tool-icon', null, ICON_SIZE_LARGE, get_lang('Report a bug'));
1011
        if ('true' === api_get_setting('show_link_bug_notification') && $this->user_is_logged_in) {
1012
            $rightFloatMenu = '<div class="report">
1013
		        <a href="https://github.com/chamilo/chamilo-lms/wiki/How-to-report-issues" target="_blank">
1014
                    '.$iconBug.'
1015
                </a>
1016
		        </div>';
1017
        }
1018
1019
        if ('true' === api_get_setting('show_link_ticket_notification') &&
1020
            $this->user_is_logged_in
1021
        ) {
1022
            // by default is project_id = 1
1023
            $defaultProjectId = 1;
1024
            $iconTicket = Display::getMdiIcon(ToolIcon::HELP, 'ch-tool-icon', null, ICON_SIZE_LARGE, get_lang('Ticket'));
1025
            $courseInfo = api_get_course_info();
1026
            $courseParams = '';
1027
            if (!empty($courseInfo)) {
1028
                $courseParams = api_get_cidreq();
1029
            }
1030
            $url = api_get_path(WEB_CODE_PATH).'ticket/tickets.php?project_id='.$defaultProjectId.'&'.$courseParams;
1031
1032
            $allow = TicketManager::userIsAllowInProject($defaultProjectId);
0 ignored issues
show
Deprecated Code introduced by
The function TicketManager::userIsAllowInProject() has been deprecated: Use TicketProjectHelper::userIsAllowInProject instead ( Ignorable by Annotation )

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

1032
            $allow = /** @scrutinizer ignore-deprecated */ TicketManager::userIsAllowInProject($defaultProjectId);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
1033
1034
            if ($allow) {
1035
                $rightFloatMenu .= '<div class="help">
1036
                    <a href="'.$url.'" target="_blank">
1037
                        '.$iconTicket.'
1038
                    </a>
1039
                </div>';
1040
            }
1041
        }
1042
1043
        $this->assign('bug_notification', $rightFloatMenu);
1044
1045
        return true;
1046
    }
1047
1048
    /**
1049
     * Load legacy params.
1050
     */
1051
    private function loadLegacyParams()
1052
    {
1053
        // Set legacy breadcrumb
1054
        global $interbreadcrumb;
1055
1056
        $courseInfo = api_get_course_info();
1057
        if (!empty($courseInfo)) {
1058
            $url = $courseInfo['course_public_url'];
1059
            $sessionId = api_get_session_id();
1060
            if (!empty($sessionId)) {
1061
                $url .= '?sid='.$sessionId;
1062
            }
1063
            if (empty($interbreadcrumb)) {
1064
                $interbreadcrumb = ['name' => $courseInfo['title'], 'url' => $url];
1065
            } else {
1066
                array_unshift(
1067
                    $interbreadcrumb,
1068
                    ['name' => $courseInfo['title'], 'url' => $url]
1069
                );
1070
            }
1071
        }
1072
1073
        $this->params['legacy_breadcrumb'] = json_encode($interbreadcrumb ? array_values($interbreadcrumb) : []);
1074
        global $htmlHeadXtra;
1075
        $this->params['legacy_javascript'] = $htmlHeadXtra;
1076
    }
1077
1078
    /**
1079
     * Prepare the _c array for template files. The _c array contains
1080
     * information about the current course.
1081
     */
1082
    private function set_course_parameters()
1083
    {
1084
        //Setting course id
1085
        $course = api_get_course_info();
1086
        if (empty($course)) {
1087
            $this->assign('course_is_set', false);
1088
1089
            return;
1090
        }
1091
        $this->assign('course_is_set', true);
1092
        $this->course_id = $course['id'];
1093
        $_c = [
1094
            'id' => $course['real_id'],
1095
            'code' => $course['code'],
1096
            'title' => $course['name'],
1097
            'visibility' => $course['visibility'],
1098
            'language' => $course['language'],
1099
            'directory' => $course['directory'],
1100
            'session_id' => api_get_session_id(),
1101
            'user_is_teacher' => api_is_course_admin(),
1102
            'student_view' => (!empty($_GET['isStudentView']) && 'true' == $_GET['isStudentView']),
1103
        ];
1104
        $this->assign('course_code', $course['code']);
1105
        $this->assign('_c', $_c);
1106
    }
1107
1108
    /**
1109
     * Manage specific HTTP headers security.
1110
     */
1111
    private function addHTTPSecurityHeaders()
1112
    {
1113
        // Implementation of HTTP headers security, as suggested and checked
1114
        // by https://securityheaders.io/
1115
        // Enable these settings in configuration.php to use them on your site
1116
        // Strict-Transport-Security
1117
        $setting = api_get_setting('security.security_strict_transport');
1118
        if (!empty($setting)) {
1119
            header('Strict-Transport-Security: '.$setting);
0 ignored issues
show
Bug introduced by
Are you sure $setting of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1119
            header('Strict-Transport-Security: './** @scrutinizer ignore-type */ $setting);
Loading history...
1120
        }
1121
        // Content-Security-Policy
1122
        $setting = api_get_setting('security.security_content_policy');
1123
        if (!empty($setting)) {
1124
            header('Content-Security-Policy: '.$setting);
1125
        }
1126
        $setting = api_get_setting('security.security_content_policy_report_only');
1127
        if (!empty($setting)) {
1128
            header('Content-Security-Policy-Report-Only: '.$setting);
1129
        }
1130
        // Public-Key-Pins
1131
        $setting = api_get_setting('security.security_public_key_pins');
1132
        if (!empty($setting)) {
1133
            header('Public-Key-Pins: '.$setting);
1134
        }
1135
        $setting = api_get_setting('security.security_public_key_pins_report_only');
1136
        if (!empty($setting)) {
1137
            header('Public-Key-Pins-Report-Only: '.$setting);
1138
        }
1139
        // X-Frame-Options
1140
        $setting = api_get_setting('security.security_x_frame_options');
1141
        if (!empty($setting)) {
1142
            header('X-Frame-Options: '.$setting);
1143
        }
1144
        // X-XSS-Protection
1145
        $setting = api_get_setting('security.security_xss_protection');
1146
        if (!empty($setting)) {
1147
            header('X-XSS-Protection: '.$setting);
1148
        }
1149
        // X-Content-Type-Options
1150
        $setting = api_get_setting('security.security_x_content_type_options');
1151
        if (!empty($setting)) {
1152
            header('X-Content-Type-Options: '.$setting);
1153
        }
1154
        // Referrer-Policy
1155
        $setting = api_get_setting('security.security_referrer_policy');
1156
        if (!empty($setting)) {
1157
            header('Referrer-Policy: '.$setting);
1158
        }
1159
        // end of HTTP headers security block
1160
    }
1161
1162
    /**
1163
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1164
     *
1165
     * @return bool Always return true (even if empty string)
1166
     */
1167
    private function assignAccessibilityBlock()
1168
    {
1169
        $resize = '';
1170
        if ('true' == api_get_setting('accessibility_font_resize')) {
1171
            $resize .= '<div class="resize_font">';
1172
            $resize .= '<div class="btn-group">';
1173
            $resize .= '<a title="'.get_lang('Decrease the font size').'" href="#" class="decrease_font btn btn--plain"><em class="fa fa-font"></em></a>';
1174
            $resize .= '<a title="'.get_lang('Reset the font size').'" href="#" class="reset_font btn btn--plain"><em class="fa fa-font"></em></a>';
1175
            $resize .= '<a title="'.get_lang('Increase the font size').'" href="#" class="increase_font btn btn--plain"><em class="fa fa-font"></em></a>';
1176
            $resize .= '</div>';
1177
            $resize .= '</div>';
1178
        }
1179
        $this->assign('accessibility', $resize);
1180
1181
        return true;
1182
    }
1183
1184
    /**
1185
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1186
     *
1187
     * @return bool Always return true (even if empty string)
1188
     */
1189
    private function assignSocialMeta()
1190
    {
1191
        $socialMeta = '';
1192
        $metaTitle = api_get_setting('meta_title');
1193
        if (!empty($metaTitle)) {
1194
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1195
            $metaSite = api_get_setting('meta_twitter_site');
1196
            if (!empty($metaSite)) {
1197
                $socialMeta .= '<meta name="twitter:site" content="'.$metaSite.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaSite of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1197
                $socialMeta .= '<meta name="twitter:site" content="'./** @scrutinizer ignore-type */ $metaSite.'" />'."\n";
Loading history...
1198
                $metaCreator = api_get_setting('meta_twitter_creator');
1199
                if (!empty($metaCreator)) {
1200
                    $socialMeta .= '<meta name="twitter:creator" content="'.$metaCreator.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaCreator of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1200
                    $socialMeta .= '<meta name="twitter:creator" content="'./** @scrutinizer ignore-type */ $metaCreator.'" />'."\n";
Loading history...
1201
                }
1202
            }
1203
1204
            // The user badge page emits its own meta tags, so if this is
1205
            // enabled, ignore the global ones
1206
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1207
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1208
1209
            if (!$userId && !$skillId) {
1210
                // no combination of user and skill ID has been defined,
1211
                // so print the normal or course-specific OpenGraph meta tags
1212
                // Check for a course ID
1213
                $courseId = api_get_course_int_id();
1214
                // Check session ID from session/id/about (see .htaccess)
1215
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1216
1217
                if (false != $courseId) {
0 ignored issues
show
Bug Best Practice introduced by
It seems like you are loosely comparing $courseId of type integer to the boolean false. If you are specifically checking for non-zero, consider using something more explicit like > 0 or !== 0 instead.
Loading history...
1218
                    // If we are inside a course (even if within a session), publish info about the course
1219
                    $course = api_get_course_entity($courseId);
1220
                    // @TODO: support right-to-left in title
1221
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaTitle of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1221
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - './** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1222
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1223
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getId()).'" />'."\n";
1224
1225
                    $metaDescription = api_get_setting('meta_description');
1226
                    if (!empty($course->getDescription())) {
1227
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1228
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1229
                    } elseif (!empty($metaDescription)) {
1230
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
0 ignored issues
show
Bug introduced by
Are you sure $metaDescription of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1230
                        $socialMeta .= '<meta property="og:description" content="'./** @scrutinizer ignore-type */ $metaDescription.'" />'."\n";
Loading history...
1231
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1232
                    }
1233
1234
                    $picture = Container::getIllustrationRepository()->getIllustrationUrl($course);
1235
                    if (!empty($picture)) {
1236
                        $socialMeta .= '<meta property="og:image" content="'.$picture.'" />'."\n";
1237
                        $socialMeta .= '<meta property="twitter:image" content="'.$picture.'" />'."\n";
1238
                        $socialMeta .= '<meta property="twitter:image:alt" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1239
                    } else {
1240
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1241
                    }
1242
                } elseif (0 !== $sessionId) {
1243
                    // If we are on a session "about" screen, publish info about the session
1244
                    $session = api_get_session_entity($sessionId);
1245
1246
                    $socialMeta .= '<meta property="og:title" content="'.$session->getTitle().' - '.$metaTitle.'" />'."\n";
1247
                    $socialMeta .= '<meta property="twitter:title" content="'.$session->getTitle().' - '.$metaTitle.'" />'."\n";
1248
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH)."sessions/{$session->getId()}/about/".'" />'."\n";
1249
1250
                    $sessionValues = new ExtraFieldValue('session');
1251
                    $sessionImage = $sessionValues->get_values_by_handler_and_field_variable($session->getId(), 'image')['value'];
1252
                    //$sessionImageSysPath = api_get_path(SYS_UPLOAD_PATH).$sessionImage;
1253
                    if (!empty($sessionImage)) {
1254
                        $asset = Container::getAssetRepository()->find($sessionImage);
1255
                        $sessionImagePath = Container::getAssetRepository()->getAssetUrl($asset);
1256
                        if (!empty($sessionImagePath)) {
1257
                            $socialMeta .= '<meta property="og:image" content="'.$sessionImagePath.'" />'."\n";
1258
                            $socialMeta .= '<meta property="twitter:image" content="'.$sessionImagePath.'" />'."\n";
1259
                            $socialMeta .= '<meta property="twitter:image:alt" content="'.$session->getTitle().' - '.$metaTitle.'" />'."\n";
1260
                        }
1261
                    } else {
1262
                        $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1263
                    }
1264
                } else {
1265
                    // Otherwise (not a course nor a session, nor a user, nor a badge), publish portal info
1266
                    $socialMeta .= '<meta property="og:title" content="'.$metaTitle.'" />'."\n";
1267
                    $socialMeta .= '<meta property="twitter:title" content="'.$metaTitle.'" />'."\n";
1268
                    $socialMeta .= '<meta property="og:url" content="'.api_get_path(WEB_PATH).'" />'."\n";
1269
1270
                    $metaDescription = api_get_setting('meta_description');
1271
                    if (!empty($metaDescription)) {
1272
                        $socialMeta .= '<meta property="og:description" content="'.$metaDescription.'" />'."\n";
1273
                        $socialMeta .= '<meta property="twitter:description" content="'.$metaDescription.'" />'."\n";
1274
                    }
1275
                    $socialMeta .= $this->getMetaPortalImagePath($metaTitle);
1276
                }
1277
            }
1278
        }
1279
1280
        $this->assign('social_meta', $socialMeta);
1281
1282
        return true;
1283
    }
1284
1285
    /**
1286
     * Get platform meta image tag (check meta_image_path setting, then use the logo).
1287
     *
1288
     * @param string $imageAlt The alt attribute for the image
1289
     *
1290
     * @return string The meta image HTML tag, or empty
1291
     */
1292
    private function getMetaPortalImagePath($imageAlt = '')
1293
    {
1294
        // Load portal meta image if defined
1295
        $metaImage = api_get_setting('meta_image_path');
1296
        $metaImageSysPath = api_get_path(SYS_PATH).$metaImage;
0 ignored issues
show
Bug introduced by
Are you sure $metaImage of type array|string can be used in concatenation? ( Ignorable by Annotation )

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

1296
        $metaImageSysPath = api_get_path(SYS_PATH)./** @scrutinizer ignore-type */ $metaImage;
Loading history...
1297
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1298
        $portalImageMeta = '';
1299
        if (!empty($metaImage)) {
1300
            if (is_file($metaImageSysPath)) {
1301
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1302
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
1303
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1304
            }
1305
        } else {
1306
            $logo = Container::getThemeHelper()->getThemeAssetUrl('images/header-logo.svg');
1307
1308
            if (empty($logo)) {
1309
                $logo = Container::getThemeHelper()->getThemeAssetUrl('images/header-logo.png');
1310
            }
1311
1312
            if (!empty($logo)) {
1313
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1314
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
1315
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1316
            }
1317
        }
1318
1319
        return $portalImageMeta;
1320
    }
1321
}
1322