Passed
Pull Request — master (#5614)
by Angel Fernando Quiroz
16:10 queued 07:37
created

Template::getPortalIcon()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 14
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 1
dl 0
loc 14
rs 10
c 0
b 0
f 0

1 Method

Rating   Name   Duplication   Size   Complexity  
A Template::fetch() 0 3 1
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_setting('display.default_template');
140
        if (!empty($defaultStyle)) {
141
            $this->templateFolder = $defaultStyle;
0 ignored issues
show
Documentation Bug introduced by
It seems like $defaultStyle can also be of type array. However, the property $templateFolder is declared as type string. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
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,
0 ignored issues
show
Bug introduced by
Are you sure $help 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

188
                    api_get_path(WEB_CODE_PATH).'help/help.php?open='./** @scrutinizer ignore-type */ $help,
Loading history...
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_configuration_value('default_template');
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
        $params['from_vue'] = isset($_REQUEST['from_vue']) ? 1 : 0;
722
    }
723
724
    /**
725
     * @param array  $params
726
     * @param string $template
727
     *
728
     * @throws \Twig\Error\Error
729
     */
730
    public function returnResponse($params, $template)
731
    {
732
        $response = new Response();
733
        $content = Container::getTwig()->render($template, $params);
734
        $response->setContent($content);
735
        $response->send();
736
    }
737
738
    /**
739
     * Special function to declare last-minute JS libraries which depend on
740
     * other things to be declared first. In particular, it might be useful
741
     * under IE9 with compatibility mode, which for some reason is getting
742
     * upset when a variable is used in a function (even if not used yet)
743
     * when this variable hasn't been defined yet.
744
     */
745
    public function set_js_files_post()
746
    {
747
        global $disable_js_and_css_files;
748
        $js_files = [];
749
        if (api_is_global_chat_enabled()) {
750
            //Do not include the global chat in LP
751
            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...
752
                $js_files[] = 'chat/js/chat.js';
753
            }
754
        }
755
        $js_file_to_string = '';
756
        foreach ($js_files as $js_file) {
757
            $js_file_to_string .= api_get_js($js_file);
758
        }
759
        if (!$disable_js_and_css_files) {
760
            $this->assign('js_file_to_string_post', $js_file_to_string);
761
        }
762
    }
763
764
    /**
765
     * Show footer js template.
766
     */
767
    public function show_footer_js_template()
768
    {
769
        $tpl = $this->get_template('layout/footer.js.tpl');
770
        $this->display($tpl);
771
    }
772
773
    /**
774
     * @param string $template
775
     *
776
     * @return string
777
     */
778
    public function fetch($template = null)
779
    {
780
        return $this->twig->render($template, $this->params);
781
    }
782
783
    /**
784
     * @param string $variable
785
     * @param mixed  $value
786
     */
787
    public function assign($variable, $value = '')
788
    {
789
        $this->params[$variable] = $value;
790
    }
791
792
    /**
793
     * Adds a body class for login pages.
794
     */
795
    public function setLoginBodyClass()
796
    {
797
        $this->assign('login_class', 'section-login');
798
    }
799
800
    /**
801
     * The theme that will be used if the database is not working.
802
     *
803
     * @return string
804
     */
805
    public static function getThemeFallback(): string
806
    {
807
        return 'chamilo';
808
    }
809
810
    /**
811
     * @return string
812
     */
813
    public function displayLoginForm()
814
    {
815
        $form = new FormValidator(
816
            'form-login',
817
            'POST',
818
            api_get_path(WEB_PUBLIC_PATH).'login_check',
819
            null,
820
            null,
821
            FormValidator::LAYOUT_BOX_NO_LABEL
822
        );
823
        $params = [
824
            'id' => '_username',
825
            'autofocus' => 'autofocus',
826
            'icon' => 'user fa-fw',
827
            'placeholder' => get_lang('Username'),
828
        ];
829
830
        // Avoid showing the autocapitalize option if the browser doesn't
831
        // support it: this attribute is against the HTML5 standard
832
        /*$browserAutoCapitalize = false;
833
        if (api_browser_support('autocapitalize')) {
834
            $browserAutoCapitalize = false;
835
            $params['autocapitalize'] = 'none';
836
        }*/
837
        $form->addText(
838
            '_username',
839
            get_lang('Username'),
840
            true,
841
            $params
842
        );
843
        $params = [
844
            'id' => '_password',
845
            'icon' => 'lock fa-fw',
846
            'placeholder' => get_lang('Pass'),
847
        ];
848
        /*if ($browserAutoCapitalize) {
849
            $params['autocapitalize'] = 'none';
850
        }*/
851
        $form->addElement(
852
            'password',
853
            '_password',
854
            get_lang('Pass'),
855
            $params
856
        );
857
858
        $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

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

998
            $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...
999
1000
            if ($allow) {
1001
                $rightFloatMenu .= '<div class="help">
1002
                    <a href="'.$url.'" target="_blank">
1003
                        '.$iconTicket.'
1004
                    </a>
1005
                </div>';
1006
            }
1007
        }
1008
1009
        $this->assign('bug_notification', $rightFloatMenu);
1010
1011
        return true;
1012
    }
1013
1014
    /**
1015
     * Load legacy params.
1016
     */
1017
    private function loadLegacyParams()
1018
    {
1019
        // Set legacy breadcrumb
1020
        global $interbreadcrumb;
1021
1022
        $courseInfo = api_get_course_info();
1023
        if (!empty($courseInfo)) {
1024
            $url = $courseInfo['course_public_url'];
1025
            $sessionId = api_get_session_id();
1026
            if (!empty($sessionId)) {
1027
                $url .= '?sid='.$sessionId;
1028
            }
1029
            if (empty($interbreadcrumb)) {
1030
                $interbreadcrumb = ['name' => $courseInfo['title'], 'url' => $url];
1031
            } else {
1032
                array_unshift(
1033
                    $interbreadcrumb,
1034
                    ['name' => $courseInfo['title'], 'url' => $url]
1035
                );
1036
            }
1037
        }
1038
1039
        $this->params['legacy_breadcrumb'] = json_encode($interbreadcrumb ? array_values($interbreadcrumb) : []);
1040
        global $htmlHeadXtra;
1041
        $this->params['legacy_javascript'] = $htmlHeadXtra;
1042
    }
1043
1044
    /**
1045
     * Prepare the _c array for template files. The _c array contains
1046
     * information about the current course.
1047
     */
1048
    private function set_course_parameters()
1049
    {
1050
        //Setting course id
1051
        $course = api_get_course_info();
1052
        if (empty($course)) {
1053
            $this->assign('course_is_set', false);
1054
1055
            return;
1056
        }
1057
        $this->assign('course_is_set', true);
1058
        $this->course_id = $course['id'];
1059
        $_c = [
1060
            'id' => $course['real_id'],
1061
            'code' => $course['code'],
1062
            'title' => $course['name'],
1063
            'visibility' => $course['visibility'],
1064
            'language' => $course['language'],
1065
            'directory' => $course['directory'],
1066
            'session_id' => api_get_session_id(),
1067
            'user_is_teacher' => api_is_course_admin(),
1068
            'student_view' => (!empty($_GET['isStudentView']) && 'true' == $_GET['isStudentView']),
1069
        ];
1070
        $this->assign('course_code', $course['code']);
1071
        $this->assign('_c', $_c);
1072
    }
1073
1074
    /**
1075
     * Manage specific HTTP headers security.
1076
     */
1077
    private function addHTTPSecurityHeaders()
1078
    {
1079
        // Implementation of HTTP headers security, as suggested and checked
1080
        // by https://securityheaders.io/
1081
        // Enable these settings in configuration.php to use them on your site
1082
        // Strict-Transport-Security
1083
        $setting = api_get_setting('security.security_strict_transport');
1084
        if (!empty($setting)) {
1085
            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

1085
            header('Strict-Transport-Security: './** @scrutinizer ignore-type */ $setting);
Loading history...
1086
        }
1087
        // Content-Security-Policy
1088
        $setting = api_get_setting('security.security_content_policy');
1089
        if (!empty($setting)) {
1090
            header('Content-Security-Policy: '.$setting);
1091
        }
1092
        $setting = api_get_setting('security.security_content_policy_report_only');
1093
        if (!empty($setting)) {
1094
            header('Content-Security-Policy-Report-Only: '.$setting);
1095
        }
1096
        // Public-Key-Pins
1097
        $setting = api_get_setting('security.security_public_key_pins');
1098
        if (!empty($setting)) {
1099
            header('Public-Key-Pins: '.$setting);
1100
        }
1101
        $setting = api_get_setting('security.security_public_key_pins_report_only');
1102
        if (!empty($setting)) {
1103
            header('Public-Key-Pins-Report-Only: '.$setting);
1104
        }
1105
        // X-Frame-Options
1106
        $setting = api_get_setting('security.security_x_frame_options');
1107
        if (!empty($setting)) {
1108
            header('X-Frame-Options: '.$setting);
1109
        }
1110
        // X-XSS-Protection
1111
        $setting = api_get_setting('security.security_xss_protection');
1112
        if (!empty($setting)) {
1113
            header('X-XSS-Protection: '.$setting);
1114
        }
1115
        // X-Content-Type-Options
1116
        $setting = api_get_setting('security.security_x_content_type_options');
1117
        if (!empty($setting)) {
1118
            header('X-Content-Type-Options: '.$setting);
1119
        }
1120
        // Referrer-Policy
1121
        $setting = api_get_setting('security.security_referrer_policy');
1122
        if (!empty($setting)) {
1123
            header('Referrer-Policy: '.$setting);
1124
        }
1125
        // end of HTTP headers security block
1126
    }
1127
1128
    /**
1129
     * Assign favicon to the 'favico' template variable.
1130
     *
1131
     * @return bool Always return true because there is always at least one correct favicon.ico
1132
     */
1133
    private function assignFavIcon()
1134
    {
1135
        // Default root chamilo favicon
1136
        $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_PATH).'favicon.ico" type="image/x-icon" />';
1137
1138
        //Added to verify if in the current Chamilo Theme exist a favicon
1139
        $favicoThemeUrl = api_get_path(SYS_CSS_PATH).$this->themeDir.'images/';
1140
1141
        //If exist pick the current chamilo theme favicon
1142
        if (is_file($favicoThemeUrl.'favicon.ico')) {
1143
            $favico = '<link rel="shortcut icon" href="'.api_get_path(WEB_CSS_PATH).$this->themeDir.'images/favicon.ico" type="image/x-icon" />';
1144
        }
1145
1146
        if (api_is_multiple_url_enabled()) {
1147
            /*$access_url_id = api_get_current_access_url_id();
1148
            if ($access_url_id != -1) {
1149
                $url_info = api_get_access_url($access_url_id);
1150
                $url = api_remove_trailing_slash(
1151
                    preg_replace('/https?:\/\//i', '', $url_info['url'])
1152
                );
1153
                $clean_url = api_replace_dangerous_char($url);
1154
                $clean_url = str_replace('/', '-', $clean_url);
1155
                $clean_url .= '/';
1156
                $homep = api_get_path(REL_PATH).'home/'.$clean_url; //homep for Home Path
1157
                $icon_real_homep = api_get_path(SYS_APP_PATH).'home/'.$clean_url;
1158
                //we create the new dir for the new sites
1159
                if (is_file($icon_real_homep.'favicon.ico')) {
1160
                    $favico = '<link rel="shortcut icon" href="'.$homep.'favicon.ico" type="image/x-icon" />';
1161
                }
1162
            }*/
1163
        }
1164
1165
        $this->assign('favico', $favico);
1166
1167
        return true;
1168
    }
1169
1170
    /**
1171
     * Assign HTML code to the 'accessibility' template variable (usually shown above top menu).
1172
     *
1173
     * @return bool Always return true (even if empty string)
1174
     */
1175
    private function assignAccessibilityBlock()
1176
    {
1177
        $resize = '';
1178
        if ('true' == api_get_setting('accessibility_font_resize')) {
1179
            $resize .= '<div class="resize_font">';
1180
            $resize .= '<div class="btn-group">';
1181
            $resize .= '<a title="'.get_lang('Decrease the font size').'" href="#" class="decrease_font btn btn--plain"><em class="fa fa-font"></em></a>';
1182
            $resize .= '<a title="'.get_lang('Reset the font size').'" href="#" class="reset_font btn btn--plain"><em class="fa fa-font"></em></a>';
1183
            $resize .= '<a title="'.get_lang('Increase the font size').'" href="#" class="increase_font btn btn--plain"><em class="fa fa-font"></em></a>';
1184
            $resize .= '</div>';
1185
            $resize .= '</div>';
1186
        }
1187
        $this->assign('accessibility', $resize);
1188
1189
        return true;
1190
    }
1191
1192
    /**
1193
     * Assign HTML code to the 'social_meta' template variable (usually shown above top menu).
1194
     *
1195
     * @return bool Always return true (even if empty string)
1196
     */
1197
    private function assignSocialMeta()
1198
    {
1199
        $socialMeta = '';
1200
        $metaTitle = api_get_setting('meta_title');
1201
        if (!empty($metaTitle)) {
1202
            $socialMeta .= '<meta name="twitter:card" content="summary" />'."\n";
1203
            $metaSite = api_get_setting('meta_twitter_site');
1204
            if (!empty($metaSite)) {
1205
                $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

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

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

1229
                    $socialMeta .= '<meta property="og:title" content="'.$course->getTitle().' - './** @scrutinizer ignore-type */ $metaTitle.'" />'."\n";
Loading history...
1230
                    $socialMeta .= '<meta property="twitter:title" content="'.$course->getTitle().' - '.$metaTitle.'" />'."\n";
1231
                    $socialMeta .= '<meta property="og:url" content="'.api_get_course_url($course->getId()).'" />'."\n";
1232
1233
                    $metaDescription = api_get_setting('meta_description');
1234
                    if (!empty($course->getDescription())) {
1235
                        $socialMeta .= '<meta property="og:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1236
                        $socialMeta .= '<meta property="twitter:description" content="'.strip_tags($course->getDescription()).'" />'."\n";
1237
                    } elseif (!empty($metaDescription)) {
1238
                        $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

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

1304
        $metaImageSysPath = api_get_path(SYS_PATH)./** @scrutinizer ignore-type */ $metaImage;
Loading history...
1305
        $metaImageWebPath = api_get_path(WEB_PATH).$metaImage;
1306
        $portalImageMeta = '';
1307
        if (!empty($metaImage)) {
1308
            if (is_file($metaImageSysPath)) {
1309
                $portalImageMeta = '<meta property="og:image" content="'.$metaImageWebPath.'" />'."\n";
1310
                $portalImageMeta .= '<meta property="twitter:image" content="'.$metaImageWebPath.'" />'."\n";
1311
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1312
            }
1313
        } else {
1314
            $logo = ChamiloApi::getPlatformLogoPath($this->theme);
1315
            if (!empty($logo)) {
1316
                $portalImageMeta = '<meta property="og:image" content="'.$logo.'" />'."\n";
1317
                $portalImageMeta .= '<meta property="twitter:image" content="'.$logo.'" />'."\n";
1318
                $portalImageMeta .= '<meta property="twitter:image:alt" content="'.$imageAlt.'" />'."\n";
1319
            }
1320
        }
1321
1322
        return $portalImageMeta;
1323
    }
1324
}
1325