Passed
Pull Request — master (#6079)
by
unknown
07:52
created

Template::displayTwoColTemplate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

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

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

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

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

1198
                $socialMeta .= '<meta name="twitter:site" content="'./** @scrutinizer ignore-type */ $metaSite.'" />'."\n";
Loading history...
1199
                $metaCreator = api_get_setting('meta_twitter_creator');
1200
                if (!empty($metaCreator)) {
1201
                    $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

1201
                    $socialMeta .= '<meta name="twitter:creator" content="'./** @scrutinizer ignore-type */ $metaCreator.'" />'."\n";
Loading history...
1202
                }
1203
            }
1204
1205
            // The user badge page emits its own meta tags, so if this is
1206
            // enabled, ignore the global ones
1207
            $userId = isset($_GET['user']) ? intval($_GET['user']) : 0;
1208
            $skillId = isset($_GET['skill']) ? intval($_GET['skill']) : 0;
1209
1210
            if (!$userId && !$skillId) {
1211
                // no combination of user and skill ID has been defined,
1212
                // so print the normal or course-specific OpenGraph meta tags
1213
                // Check for a course ID
1214
                $courseId = api_get_course_int_id();
1215
                // Check session ID from session/id/about (see .htaccess)
1216
                $sessionId = isset($_GET['session_id']) ? intval($_GET['session_id']) : 0;
1217
1218
                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...
1219
                    // If we are inside a course (even if within a session), publish info about the course
1220
                    $course = api_get_course_entity($courseId);
1221
                    // @TODO: support right-to-left in title
1222
                    $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

1222
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - './** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1223
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1224
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getId()).'" />'."\n";
1225
1226
                    $metaDescription = api_get_setting('meta_description');
1227
                    if (!empty($course->getDescription())) {
1228
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1229
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1230
                    } elseif (!empty($metaDescription)) {
1231
                        $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

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

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