XoopsTheme   F
last analyzed

Complexity

Total Complexity 110

Size/Duplication

Total Lines 948
Duplicated Lines 0 %

Test Coverage

Coverage 39.24%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
eloc 316
c 1
b 0
f 1
dl 0
loc 948
ccs 124
cts 316
cp 0.3924
rs 2
wmc 110

25 Methods

Rating   Name   Duplication   Size   Complexity  
F xoInit() 0 112 13
A addBaseStylesheetAssets() 0 3 1
A getLocalizationAssets() 0 23 4
A addScript() 0 17 5
A addStylesheetAssets() 0 4 1
A resourcePath() 0 18 4
F render() 0 77 19
A addHttpMeta() 0 7 2
B checkCache() 0 19 8
A addStylesheet() 0 17 5
C renderMetasByType() 0 49 13
A addBaseScriptAssets() 0 3 1
A genElementId() 0 7 2
A setNamedAsset() 0 3 1
A generateCacheId() 0 31 5
A headContent() 0 4 2
A addScriptAssets() 0 4 1
A addLink() 0 10 3
A addBaseAssets() 0 6 3
A renderAttributes() 0 9 3
A addMeta() 0 11 3
A renderBaseAssets() 0 18 5
A renderMetas() 0 14 3
A setRenderer() 0 3 1
A renderer() 0 7 2

How to fix   Complexity   

Complex Class

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

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

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

1
<?php
2
/*
3
 You may not change or alter any portion of this comment or credits
4
 of supporting developers from this source code or any supporting source code
5
 which is considered copyrighted (c) material of the original comment or credit authors.
6
7
 This program is distributed in the hope that it will be useful,
8
 but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10
*/
11
12
namespace Xoops\Core\Theme;
13
14
use Xoops\Core\FixedGroups;
15
use Xoops\Core\XoopsTpl;
16
17
/**
18
 * XoopsTheme component class file
19
 *
20
 * @category  Xoops\Core
21
 * @package   Theme
22
 * @author    Skalpa Keo <[email protected]>
23
 * @author    Taiwen Jiang <[email protected]>
24
 * @copyright 2008-2017 XOOPS Project (http://xoops.org)
25
 * @license   GNU GPL 2 or later (http://www.gnu.org/licenses/gpl-2.0.html)
26
 * @link      http://xoops.org
27
 */
28
class XoopsTheme
29
{
30
    /**
31
     * Should we render banner? Not for redirect pages or admin side
32
     *
33
     * @var bool
34
     */
35
    public $renderBanner = true;
36
37
    /**
38
     * The name of this theme
39
     *
40
     * @var string
41
     */
42
    public $folderName = '';
43
44
    /**
45
     * Physical path of this theme folder
46
     *
47
     * @var string
48
     */
49
    public $path = '';
50
51
    /**
52
     * @var string
53
     */
54
    public $url = '';
55
56
    /**
57
     * Whether or not the theme engine should include the output generated by php
58
     *
59
     * @var string
60
     */
61
    public $bufferOutput = true;
62
63
    /**
64
     * Canvas-level template to use
65
     *
66
     * @var string
67
     */
68
    public $canvasTemplate = 'theme.tpl';
69
70
    /**
71
     * Theme folder path
72
     *
73
     * @var string
74
     */
75
    public $themesPath = 'themes';
76
77
    /**
78
     * Content-level template to use
79
     *
80
     * @var string
81
     */
82
    public $contentTemplate = '';
83
84
    /**
85
     * @var int
86
     */
87
    public $contentCacheLifetime = 0;
88
89
    /**
90
     * @var string
91
     */
92
    public $contentCacheId = null;
93
94
    /**
95
     * Text content to display right after the contentTemplate output
96
     *
97
     * @var string
98
     */
99
    public $content = '';
100
101
    /**
102
     * Page construction plug-ins to use
103
     *
104
     * @var array
105
     * @access public
106
     */
107
    public $plugins = array('\Xoops\Core\Theme\Plugins\Blocks');
108
109
    /**
110
     * @var int
111
     */
112
    public $renderCount = 0;
113
114
    /**
115
     * Pointer to the theme template engine
116
     *
117
     * @var XoopsTpl
118
     */
119
    public $template = false;
120
121
    /**
122
     * Array containing the document meta-information
123
     *
124
     * @var array
125
     */
126
    public $metas = array(
127
        'meta' => array(), 'link' => array(), 'script' => array()
128
    );
129
130
    /**
131
     * Asset manager instance
132
     *
133
     * @var object
134
     */
135
    public $assets = null;
136
137
    /**
138
     * Array containing base assets for the document
139
     *
140
     * @var array
141
     */
142
    public $baseAssets = array(
143
        'js' => array(),
144
        'css' => array(),
145
    );
146
147
    /**
148
     * Array of strings to be inserted in the head tag of HTML documents
149
     *
150
     * @var array
151
     */
152
    public $htmlHeadStrings = array();
153
154
    /**
155
     * Custom variables that will always be assigned to the template
156
     *
157
     * @var array
158
     */
159
    public $templateVars = array();
160
161
    /**
162
     * User extra information for cache id, like language, user groups
163
     *
164
     * @var boolean
165
     */
166
    public $use_extra_cache_id = true;
167
168
    /**
169
     * Engine used for caching headers information
170
     * Default is 'file', you can choose 'model' for database storage
171
     * or any other cache engine available in the class/cache folder
172
     *
173
     * @var boolean
174
     */
175
    public $headersCacheEngine = 'default';
176
	
177
	/**
178
     * 
179
     *$renderer instance of renderer
180
     * 
181
     */	
182
	protected $renderer;
183
184
    /**
185
     * *#@-
186
     */
187
188
    /**
189
     * *#@+
190
     * @tasktype 10 Initialization
191
     */
192
    /**
193
     * Initializes this theme
194
     * Upon initialization, the theme creates its template engine and instantiates the
195
     * plug-ins from the specified {@link $plugins} list. If the theme is a 2.0 theme, that does not
196
     * display redirection messages, the HTTP redirection system is disabled to ensure users will
197
     * see the redirection screen.
198
     *
199
     * @return bool
200
     */
201 4
    public function xoInit()
202
    {
203 4
        $xoops = \Xoops::getInstance();
204 4
        $this->assets = $xoops->assets();
205 4
        $this->path = \XoopsBaseConfig::get('themes-path') . '/' . $this->folderName;
206 4
        $this->url = \XoopsBaseConfig::get('themes-url') . '/' . $this->folderName;
207 4
        $this->template = null;
208 4
        $this->template = new XoopsTpl();
209
        //$this->template->currentTheme = $this;
210 4
        $this->template->assignByRef('xoTheme', $this);
0 ignored issues
show
Bug introduced by
The method assignByRef() does not exist on Xoops\Core\XoopsTpl. Did you maybe mean assign()? ( Ignorable by Annotation )

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

210
        $this->template->/** @scrutinizer ignore-call */ 
211
                         assignByRef('xoTheme', $this);

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...
211 4
        $this->template->assign(array(
212 4
            'xoops_theme'      => $xoops->getConfig('theme_set'),
213 4
            'xoops_imageurl'   => \XoopsBaseConfig::get('themes-url') . '/' . $xoops->getConfig('theme_set') . '/',
214 4
            'xoops_themecss'   => $xoops->getCss($xoops->getConfig('theme_set')),
215 4
            'xoops_requesturi' => htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES),
216 4
            'xoops_sitename'   => htmlspecialchars($xoops->getConfig('sitename'), ENT_QUOTES),
217 4
            'xoops_slogan'     => htmlspecialchars($xoops->getConfig('slogan'), ENT_QUOTES),
218 4
            'xoops_dirname'    => $xoops->moduleDirname,
219 4
            'xoops_banner'     => $this->renderBanner ? $xoops->getBanner() : '&nbsp;',
220 4
            'xoops_pagetitle'  => $xoops->isModule()
221
                ? $xoops->module->getVar('name')
0 ignored issues
show
Bug introduced by
The method getVar() 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

221
                ? $xoops->module->/** @scrutinizer ignore-call */ getVar('name')

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...
222 4
                : htmlspecialchars($xoops->getConfig('slogan'), ENT_QUOTES)
223
        ));
224 4
        $this->template->assign(array(
225 4
            'theme_path' => $this->path, 'theme_tpl' => $this->path . '/xotpl', 'theme_url' => $this->url,
226 4
            'theme_img'  => $this->url . '/img', 'theme_icons' => $this->url . '/icons',
227 4
            'theme_css'  => $this->url . '/css', 'theme_js' => $this->url . '/js',
228 4
            'theme_lang' => $this->url . '/language',
229
        ));
230
231 4
        if ($xoops->isUser()) {
232
            $response = $xoops->service("Avatar")->getAvatarUrl($xoops->user);
233
            $avatar = $response->getValue();
234
            $avatar = empty($avatar) ? '' : $avatar;
235
236
            $this->template->assign(array(
237
                'xoops_isuser'     => true,
238
                'xoops_avatar'     => $avatar,
239
                'xoops_userid'     => $xoops->user->getVar('uid'), 'xoops_uname' => $xoops->user->getVar('uname'),
240
                'xoops_name'       => $xoops->user->getVar('name'), 'xoops_isadmin' => $xoops->isAdmin(),
241
                'xoops_usergroups' => $xoops->user->getGroups()
242
            ));
243
        } else {
244 4
            $this->template->assign(array(
245 4
                'xoops_isuser' => false,
246
                'xoops_isadmin' => false,
247
                'xoops_usergroups' => array(FixedGroups::ANONYMOUS)
248
            ));
249
        }
250
251
        // Meta tags
252
        $metas = array(
253 4
            'description', 'keywords', 'robots', 'rating', 'author', 'copyright'
254
        );
255 4
        foreach ($metas as $name) {
256 4
            $this->addMeta('meta', $name, $xoops->getConfig('meta_' . $name));
257
        }
258
259
        // Other assigns
260
        $assigns = array(
261 4
            'title', 'slogan', 'locale', 'footer', 'jquery_theme', 'startpage'
262
        );
263 4
        foreach ($assigns as $name) {
264
            // prefix each tag with 'xoops_'
265 4
            $this->template->assign("xoops_$name", $xoops->getConfig($name));
266
        }
267
268
        // Load global javascript
269
        //$this->addScript('include/xoops.js');
270
        //$this->loadLocalization();
271 4
        list($cssAssets, $jsAssets) = $this->getLocalizationAssets();
272 4
        if (!empty($cssAssets)) {
273
            $this->addBaseStylesheetAssets($cssAssets);
274
        }
275 4
        $this->addBaseScriptAssets('include/xoops.js');
0 ignored issues
show
Bug introduced by
'include/xoops.js' of type string is incompatible with the type array expected by parameter $assets of Xoops\Core\Theme\XoopsTheme::addBaseScriptAssets(). ( Ignorable by Annotation )

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

275
        $this->addBaseScriptAssets(/** @scrutinizer ignore-type */ 'include/xoops.js');
Loading history...
276 4
        $this->addBaseScriptAssets('@jquery');
277 4
        $this->addBaseStylesheetAssets('@fontawesome');
0 ignored issues
show
Bug introduced by
'@fontawesome' of type string is incompatible with the type array expected by parameter $assets of Xoops\Core\Theme\XoopsTh...dBaseStylesheetAssets(). ( Ignorable by Annotation )

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

277
        $this->addBaseStylesheetAssets(/** @scrutinizer ignore-type */ '@fontawesome');
Loading history...
278 4
        if (!empty($jsAssets)) {
279
            $this->addBaseScriptAssets($jsAssets);
280
        }
281
282 4
        if ($this->bufferOutput) {
283 4
            ob_start();
284
        }
285 4
        $xoops->setTheme($this);
286 4
        $xoops->setTpl($this->template);
287
288
        //For legacy only, never use this Globals
289 4
        $GLOBALS['xoTheme'] = $xoops->theme();
290 4
        $GLOBALS['xoopsTpl'] = $xoops->tpl();
291
292
        //to control order of loading JS and CSS
293
        // TODO - this should be done in such a way it can join the base asset
294
        //        load above.
295 4
        if (\XoopsLoad::fileExists($this->path . "/theme_onload.php")) {
296 4
            include_once($this->path . "/theme_onload.php");
297
        }
298
299
        // Instantiate and initialize all the theme plugins
300 4
        foreach ($this->plugins as $k => $bundleId) {
301 2
            if (!is_object($bundleId)) {
302
                /* @var $plugin PluginAbstract */
303 2
                $plugin = new $bundleId();
304 2
                $plugin->theme = $this;
305 2
                $plugin->xoInit();
306
307 2
                $this->plugins[$bundleId] = null;
308 2
                $this->plugins[$bundleId] = $plugin;
309 2
                unset($this->plugins[$k]);
310
            }
311
        }
312 4
        return true;
313
    }
314
	
315
    /**
316
     * set the renderer
317
     *
318
     * @$renderer instance of renderer
319
     *
320
     * @return void
321
     */
322 1
    public function setRenderer($renderer)
323
    {
324 1
		$this->renderer = $renderer;
325 1
    }
326
	
327
	/**
328
     * get the renderer
329
     *
330
     * @return Renderer
0 ignored issues
show
Bug introduced by
The type Xoops\Core\Theme\Renderer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
331
     */
332 63
    public function renderer($element)
333
    {
334
        // return a default if not set
335 63
        if (null === $this->renderer) {
336 63
			return $element->defaultRender();
337
		} else {
338
			return $this->renderer->render($element);
339
		}
340
    }
341
342
    /**
343
     * Generate cache id based on extra information of language and user groups
344
     * User groups other than anonymous should be detected to avoid disclosing group sensitive contents
345
     *
346
     * @param string $cache_id    raw cache id
347
     * @param string $extraString extra string
348
     *
349
     * @return string complete cache id
350
     */
351 2
    public function generateCacheId($cache_id, $extraString = '')
352
    {
353 2
        $xoops = \Xoops::getInstance();
354 2
        static $extra_string;
355 2
        if (!$this->use_extra_cache_id) {
356
            return $cache_id;
357
        }
358
359 2
        if (empty($extraString)) {
360 2
            if (empty($extra_string)) {
361
                // Generate language section
362 1
                $extra_string = $xoops->getConfig('locale');
363
                // Generate group section
364 1
                if (!$xoops->isUser()) {
365 1
                    $extra_string .= '-' . FixedGroups::ANONYMOUS;
366
                } else {
367
                    $groups = $xoops->user->getGroups();
368
                    sort($groups);
369
                    // Generate group string for non-anonymous groups,
370
                    // db-pass and db-name (before we find better variables) are used
371
                    // to protect group sensitive contents
372
                    $extra_string .= '-' . substr(md5(implode('-', $groups)), 0, 8) . '-' . substr(md5(
373
                        \XoopsBaseConfig::get('db-pass') . \XoopsBaseConfig::get('db-name')
374
                        . \XoopsBaseConfig::get('db-user')
375
                    ), 0, 8);
376
                }
377
            }
378 2
            $extraString = $extra_string;
379
        }
380 2
        $cache_id .= '-' . $extraString;
381 2
        return $cache_id;
382
    }
383
384
    /**
385
     * XoopsTheme::checkCache()
386
     *
387
     * @return bool
388
     */
389
    public function checkCache()
390
    {
391
        if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $this->contentCacheLifetime) {
392
            $template = $this->contentTemplate ? $this->contentTemplate : 'module:system/system_dummy.tpl';
393
            $this->template->caching = 2;
394
            $this->template->cache_lifetime = $this->contentCacheLifetime;
395
            $uri = str_replace(\XoopsBaseConfig::get('url'), '', $_SERVER['REQUEST_URI']);
396
            // Clean uri by removing session id
397
            if (defined('SID') && SID && strpos($uri, SID)) {
398
                $uri = preg_replace("/([\?&])(" . SID . "$|" . SID . "&)/", "\\1", $uri);
399
            }
400
            $this->contentCacheId = $this->generateCacheId('page_' . substr(md5($uri), 0, 8));
401
            if ($this->template->isCached($template, $this->contentCacheId)) {
0 ignored issues
show
Bug introduced by
The method isCached() does not exist on Xoops\Core\XoopsTpl. ( Ignorable by Annotation )

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

401
            if ($this->template->/** @scrutinizer ignore-call */ isCached($template, $this->contentCacheId)) {

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...
402
                \Xoops::getInstance()->events()->triggerEvent('core.theme.checkcache.success', array($template, $this));
403
                $this->render(null, null, $template);
404
                return true;
405
            }
406
        }
407
        return false;
408
    }
409
410
    /**
411
     * Render the page
412
     * The theme engine builds pages from 2 templates: canvas and content.
413
     * A module can call this method directly and specify what templates the theme engine must use.
414
     * If render() hasn't been called before, the theme defaults will be used for the canvas and
415
     * page template (and xoopsOption['template_main'] for the content).
416
     *
417
     * @param string $canvasTpl  The canvas template, if different from the theme default
418
     * @param string $pageTpl    The page template, if different from the theme default (unsupported, 2.3+ only)
419
     * @param string $contentTpl The content template
420
     * @param array  $vars       Template variables to send to the template engine
421
     *
422
     * @return bool
423
     */
424
    public function render($canvasTpl = null, $pageTpl = null, $contentTpl = null, $vars = array())
425
    {
426
        if ($this->renderCount) {
427
            return false;
428
        }
429
        $xoops = \Xoops::getInstance();
430
        $xoops->events()->triggerEvent('core.theme.render.start', array($this));
431
        $cache = $xoops->cache($this->headersCacheEngine);
432
433
        //Get meta information for cached pages
434
        if ($this->contentCacheLifetime && $this->contentCacheId && $content = $cache->read($this->contentCacheId)) {
435
            //we need to merge metas set by blocks with the module cached meta
436
            $this->htmlHeadStrings = array_merge($this->htmlHeadStrings, $content['htmlHeadStrings']);
437
            foreach ($content['metas'] as $type => $value) {
438
                $this->metas[$type] = array_merge($this->metas[$type], $content['metas'][$type]);
439
            }
440
            $xoops->setOption('xoops_pagetitle', $content['xoops_pagetitle']);
441
            $xoops->setOption('xoops_module_header', $content['header']);
442
        }
443
444
        if ($xoops->getOption('xoops_pagetitle')) {
445
            $this->template->assign('xoops_pagetitle', $xoops->getOption('xoops_pagetitle'));
446
        }
447
        $header = !$xoops->getOption('xoops_module_header')
448
            ? $this->template->getTemplateVars('xoops_module_header')
0 ignored issues
show
Bug introduced by
The method getTemplateVars() does not exist on Xoops\Core\XoopsTpl. ( Ignorable by Annotation )

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

448
            ? $this->template->/** @scrutinizer ignore-call */ getTemplateVars('xoops_module_header')

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...
449
            : $xoops->getOption('xoops_module_header');
450
451
        //save meta information of cached pages
452
        if ($this->contentCacheLifetime && $this->contentCacheId && !$contentTpl) {
453
            $content['htmlHeadStrings'] = (array)$this->htmlHeadStrings;
454
            $content['metas'] = (array)$this->metas;
455
            $content['xoops_pagetitle'] = $this->template->getTemplateVars('xoops_pagetitle');
456
            $content['header'] = $header;
457
            $cache->write($this->contentCacheId, $content);
458
        }
459
460
        //  @internal : Lame fix to ensure the metas specified in the xoops config page don't appear twice
461
        $old = array('robots', 'keywords', 'description', 'rating', 'author', 'copyright');
462
        foreach ($this->metas['meta'] as $name => $value) {
463
            if (in_array($name, $old)) {
464
                $this->template->assign("xoops_meta_$name", htmlspecialchars($value, ENT_QUOTES));
465
                unset($this->metas['meta'][$name]);
466
            }
467
        }
468
469
        // We assume no overlap between $GLOBALS['xoopsOption']['xoops_module_header'] and
470
        // $this->template->getTemplateVars( 'xoops_module_header' ) ?
471
        $this->template->assign('xoops_module_header', $this->renderMetas(true) . "\n" . $header);
472
473
        if ($canvasTpl) {
474
            $this->canvasTemplate = $canvasTpl;
475
        }
476
        if ($contentTpl) {
477
            $this->contentTemplate = $contentTpl;
478
        }
479
        if (!empty($vars)) {
480
            $this->template->assign($vars);
481
        }
482
        if ($this->contentTemplate) {
483
            $this->content = $this->template->fetch($this->contentTemplate, $this->contentCacheId);
484
        }
485
        if ($this->bufferOutput) {
486
            $this->content .= ob_get_contents();
487
            ob_end_clean();
488
        }
489
490
        $this->template->assignByRef('xoops_contents', $this->content);
491
492
        // Do not cache the main (theme.tpl) template output
493
        $this->template->caching = 0;
494
        if (false === (bool)($xoops->getConfig('disable_theme_shortcodes'))) {
495
            $this->template->loadFilter('output', 'shortcodes');
0 ignored issues
show
Bug introduced by
The method loadFilter() does not exist on Xoops\Core\XoopsTpl. Did you maybe mean load_filter()? ( Ignorable by Annotation )

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

495
            $this->template->/** @scrutinizer ignore-call */ 
496
                             loadFilter('output', 'shortcodes');

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...
496
        }
497
        $this->template->display($this->path . '/' . $this->canvasTemplate);
498
        $this->renderCount++;
499
        $xoops->events()->triggerEvent('core.theme.render.end', array($this));
500
        return true;
501
    }
502
503
    /**
504
     * Load localization information
505
     * Folder structure for localization:
506
     * themes/themefolder/english
507
     *    - main.php - language definitions
508
     *    - style.css - localization stylesheet
509
     *    - script.js - localization script
510
     *
511
     * @param string $type language domain (unused?)
512
     *
513
     * @return array list of 2 arrays, one
514
     */
515 4
    public function getLocalizationAssets($type = "main")
0 ignored issues
show
Unused Code introduced by
The parameter $type is not used and could be removed. ( Ignorable by Annotation )

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

515
    public function getLocalizationAssets(/** @scrutinizer ignore-unused */ $type = "main")

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

Loading history...
516
    {
517 4
        $cssAssets = array();
518 4
        $jsAssets = array();
519
520 4
        $xoops = \Xoops::getInstance();
521
522 4
        \Xoops\Locale::loadThemeLocale($this);
523
524 4
        $language = \XoopsLocale::getLocale();
525
        // Load global localization stylesheet if available
526 4
        if (\XoopsLoad::fileExists($xoops->path('locale/' . $language . '/style.css'))) {
527
            $cssAssets[] = $xoops->path('locale/' . $language . '/style.css');
528
        }
529
        //$this->addLanguage($type);
530
        // Load theme localization stylesheet and scripts if available
531 4
        if (\XoopsLoad::fileExists($this->path . '/locale/' . $language . '/script.js')) {
532
            $jsAssets[] = $this->url . '/locale/' . $language . '/script.js';
533
        }
534 4
        if (\XoopsLoad::fileExists($this->path . '/locale/' . $language . '/style.css')) {
535
            $cssAssets[] = $this->path . '/locale/' . $language . '/style.css';
536
        }
537 4
        return array($cssAssets, $jsAssets);
538
    }
539
540
    /**
541
     * Load theme specific language constants
542
     *
543
     * @param string $type     language type, like 'main', 'admin'; Needs to be declared in theme xo-info.php
544
     * @param string $language specific language
545
     *
546
     * @return bool|mixed
547
     */
548
    /*
549
    public function addLanguage($type = "main", $language = null)
550
    {
551
        $xoops = \Xoops::getInstance();
552
        $language = is_null($language) ? $xoops->getConfig('locale') : $language;
553
        if (!XoopsLoad::fileExists($file = $xoops->path($this->resourcePath("/locale/{$language}/{$type}.php")))) {
554
            if (!XoopsLoad::fileExists($file = $xoops->path($this->resourcePath("/locale/en_US/{$type}.php")))) {
555
                return false;
556
            }
557
        }
558
        $ret = include_once $file;
559
        return $ret;
560
    }*/
561
562
    /**
563
     * *#@+
564
     * @tasktype 20 Manipulating page meta-information
565
     */
566
    /**
567
     * Adds script code to the document head
568
     * This methods allows the insertion of an external script file (if $src is provided), or
569
     * of a script snippet. The file URI is parsed to take benefit of the theme resource
570
     * overloading system.
571
     * The $attributes parameter allows you to specify the attributes that will be added to the
572
     * inserted <script> tag. If unspecified, the <var>type</var> attribute value will default to
573
     * 'text/javascript'.
574
     * <code>
575
     * // Add an external script using a physical path
576
     * $theme->addScript( 'www/script.js', null, '' );
577
     * $theme->addScript( 'modules/newbb/script.js', null, '' );
578
     * // Specify attributes for the <script> tag
579
     * $theme->addScript( 'mod_xoops_SiteManager#common.js', array( 'type' => 'application/x-javascript' ), '' );
580
     * // Insert a code snippet
581
     * $theme->addScript( null, array( 'type' => 'application/x-javascript' ), 'window.open("Hello world");' );
582
     * </code>
583
     *
584
     * @param string $src        path to an external script file
585
     * @param array  $attributes hash of attributes to add to the <script> tag
586
     * @param string $content    Code snippet to output within the <script> tag
587
     *
588
     * @return void
589
     */
590 7
    public function addScript($src = '', $attributes = array(), $content = '')
591
    {
592 7
        $xoops = \Xoops::getInstance();
593 7
        if (empty($attributes)) {
594 6
            $attributes = array();
595
        }
596 7
        if (!empty($src)) {
597 3
            $src = $xoops->url($this->resourcePath($src));
598 3
            $attributes['src'] = $src;
599
        }
600 7
        if (!empty($content)) {
601 4
            $attributes['_'] = $content;
602
        }
603 7
        if (!isset($attributes['type'])) {
604 6
            $attributes['type'] = 'text/javascript';
605
        }
606 7
        $this->addMeta('script', $src, $attributes);
0 ignored issues
show
Bug introduced by
$attributes of type array is incompatible with the type string expected by parameter $value of Xoops\Core\Theme\XoopsTheme::addMeta(). ( Ignorable by Annotation )

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

606
        $this->addMeta('script', $src, /** @scrutinizer ignore-type */ $attributes);
Loading history...
607 7
    }
608
609
    /**
610
     * Add StyleSheet or CSS code to the document head
611
     *
612
     * @param string|null $src        path to .css file
613
     * @param array|null  $attributes name => value paired array of attributes such as title
614
     * @param string      $content    CSS code to output between the <style> tags (in case $src is empty)
615
     *
616
     * @return void
617
     */
618
    public function addStylesheet($src = '', $attributes = array(), $content = '')
619
    {
620
        $xoops = \Xoops::getInstance();
621
        if (empty($attributes)) {
622
            $attributes = array();
623
        }
624
        if (!empty($src)) {
625
            $src = $xoops->url($this->resourcePath($src));
626
            $attributes['href'] = $src;
627
        }
628
        if (!isset($attributes['type'])) {
629
            $attributes['type'] = 'text/css';
630
        }
631
        if (!empty($content)) {
632
            $attributes['_'] = $content;
633
        }
634
        $this->addMeta('stylesheet', $src, $attributes);
0 ignored issues
show
Bug introduced by
$attributes of type array is incompatible with the type string expected by parameter $value of Xoops\Core\Theme\XoopsTheme::addMeta(). ( Ignorable by Annotation )

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

634
        $this->addMeta('stylesheet', $src, /** @scrutinizer ignore-type */ $attributes);
Loading history...
635
    }
636
637
    /**
638
     * addScriptAssets - add a list of scripts to the page
639
     *
640
     * @param array  $assets  list of source files to process
641
     * @param string $filters comma separated list of filters
642
     * @param string $target  target path, will default to assets directory
643
     *
644
     * @return void
645
     */
646
    public function addScriptAssets($assets, $filters = 'default', $target = null)
647
    {
648
        $url = $this->assets->getUrlToAssets('js', $assets, $filters, $target);
649
        $this->addScript($url);
650
    }
651
652
    /**
653
     * addStylesheetAssets - add a list of stylesheets to the page
654
     *
655
     * @param string[] $assets  list of source files to process
656
     * @param string   $filters comma separated list of filters
657
     * @param string   $target  target path, will default to assets directory
658
     *
659
     * @return void
660
     */
661
    public function addStylesheetAssets($assets, $filters = 'default', $target = null)
662
    {
663
        $url = $this->assets->getUrlToAssets('css', $assets, $filters, $target);
664
        $this->addStylesheet($url);
665
    }
666
667
    /**
668
     * addBaseAssets - add a list of assets to the page, these will all
669
     * be combined into a single asset file at render time
670
     *
671
     * @param string $type   type of asset, i.e. 'css' or 'js'
672
     * @param array  $assets list of source files to process
673
     *
674
     * @return void
675
     */
676 4
    public function addBaseAssets($type, $assets)
677
    {
678 4
        if (is_scalar($assets)) {
0 ignored issues
show
introduced by
The condition is_scalar($assets) is always false.
Loading history...
679 4
            $this->baseAssets[$type][]=$assets;
680 1
        } elseif (is_array($assets)) {
0 ignored issues
show
introduced by
The condition is_array($assets) is always true.
Loading history...
681 1
            $this->baseAssets[$type] = array_merge($this->baseAssets[$type], $assets);
682
        }
683 4
    }
684
685
    /**
686
     * addBaseScriptAssets - add a list of scripts to the page
687
     *
688
     * @param array $assets list of source files to process
689
     *
690
     * @return void
691
     */
692 4
    public function addBaseScriptAssets($assets)
693
    {
694 4
        $this->addBaseAssets('js', $assets);
695 4
    }
696
697
    /**
698
     * addBaseStylesheetAssets - add a list of stylesheets to the page
699
     *
700
     * @param array $assets list of source files to process
701
     *
702
     * @return void
703
     */
704 4
    public function addBaseStylesheetAssets($assets)
705
    {
706 4
        $this->addBaseAssets('css', $assets);
707 4
    }
708
709
    /**
710
     * setNamedAsset - Add an asset reference to the asset manager.
711
     * The specified asset will be added to the asset manager with the specified
712
     * name. As an example:
713
     *
714
     *   $theme->setNamedAsset('aacss','module/aa/assets/css/*.css');
715
     *
716
     * This will create an asset reference which can be added using other asset
717
     * functions, such as:
718
     *
719
     *   $theme->addBaseStylesheetAssets('@aacss');
720
     *
721
     * Additional custom filters can be specified for the named asset if needed.
722
     *
723
     * @param string $name    the name of the reference to be added
724
     * @param mixed  $assets  a string asset path, or an array of asset paths, may include wildcard
725
     * @param string $filters comma separated list of filters
726
     *
727
     * @return boolean true if asset registers, false on error
728
     */
729 1
    public function setNamedAsset($name, $assets, $filters = null)
730
    {
731 1
        return $this->assets->registerAssetReference($name, $assets, $filters);
732
    }
733
734
    /**
735
     * Add a <link> to the header
736
     *
737
     * @param string $rel        Relationship from the current doc to the anchored one
738
     * @param string $href       URI of the anchored document
739
     * @param array  $attributes Additional attributes to add to the <link> element
740
     *
741
     * @return void
742
     */
743
    public function addLink($rel, $href = '', $attributes = array())
744
    {
745
        if (empty($attributes)) {
746
            $attributes = array();
747
        }
748
        if (!empty($href)) {
749
            $attributes['href'] = $href;
750
        }
751
        $attributes['rel'] = $rel;
752
        $this->addMeta('link', '', $attributes);
0 ignored issues
show
Bug introduced by
$attributes of type array is incompatible with the type string expected by parameter $value of Xoops\Core\Theme\XoopsTheme::addMeta(). ( Ignorable by Annotation )

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

752
        $this->addMeta('link', '', /** @scrutinizer ignore-type */ $attributes);
Loading history...
753
    }
754
755
    /**
756
     * Set a meta http-equiv value
757
     *
758
     * @param string $name  meta tag name
759
     * @param null   $value meta tag value
0 ignored issues
show
Documentation Bug introduced by
Are you sure the doc-type for parameter $value is correct as it would always require null to be passed?
Loading history...
760
     *
761
     * @return string|false
762
     */
763
    public function addHttpMeta($name, $value = null)
764
    {
765
        if (isset($value)) {
766
            return $this->addMeta('http', $name, $value);
767
        }
768
        unset($this->metas['http'][$name]);
769
        return false;
770
    }
771
772
    /**
773
     * Change output page meta-information
774
     *
775
     * @param string $type  type
776
     * @param string $name  name
777
     * @param string $value value
778
     *
779
     * @return string
780
     */
781 11
    public function addMeta($type = 'meta', $name = '', $value = '')
782
    {
783 11
        if (!isset($this->metas[$type])) {
784
            $this->metas[$type] = array();
785
        }
786 11
        if (!empty($name)) {
787 7
            $this->metas[$type][$name] = $value;
788
        } else {
789 4
            $this->metas[$type][md5(serialize(array($value)))] = $value;
790
        }
791 11
        return $value;
792
    }
793
794
    /**
795
     * XoopsTheme::headContent()
796
     *
797
     * @param mixed  $params  unused
798
     * @param string $content content
799
     * @param mixed  $smarty  unused
800
     * @param bool   $repeat  repeat
801
     *
802
     * @return void
803
     */
804
    public function headContent($params, $content, &$smarty, &$repeat)
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

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

804
    public function headContent(/** @scrutinizer ignore-unused */ $params, $content, &$smarty, &$repeat)

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

Loading history...
Unused Code introduced by
The parameter $smarty is not used and could be removed. ( Ignorable by Annotation )

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

804
    public function headContent($params, $content, /** @scrutinizer ignore-unused */ &$smarty, &$repeat)

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

Loading history...
805
    {
806
        if (!$repeat) {
807
            $this->htmlHeadStrings[] = $content;
808
        }
809
    }
810
811
    /**
812
     * XoopsTheme::renderMetas()
813
     *
814
     * @param bool $return true to return as string, false to echo
815
     *
816
     * @return bool|string
817
     */
818
    public function renderMetas($return = false)
819
    {
820
        $str = $this->renderBaseAssets();
821
822
        foreach (array_keys($this->metas) as $type) {
823
            $str .= $this->renderMetasByType($type);
824
        }
825
        $str .= implode("\n", $this->htmlHeadStrings);
826
827
        if ($return) {
828
            return $str;
829
        }
830
        echo $str;
831
        return true;
832
    }
833
834
    /**
835
     * render base assets
836
     *
837
     * @return string
838
     */
839
    public function renderBaseAssets()
840
    {
841
        $str = '';
842
843
        if (!empty($this->baseAssets['js'])) {
844
            $url = $this->assets->getUrlToAssets('js', $this->baseAssets['js']);
845
            if (!empty($url)) {
846
                $str .= '<script src="' . $url . '" type="text/javascript"></script>'."\n";
847
            }
848
        }
849
850
        if (!empty($this->baseAssets['css'])) {
851
            $url = $this->assets->getUrlToAssets('css', $this->baseAssets['css']);
852
            if (!empty($url)) {
853
                $str .= '<link rel="stylesheet" href="' . $url . '" type="text/css" />'."\n";
854
            }
855
        }
856
        return $str;
857
    }
858
859
    /**
860
     * XoopsTheme::renderMetasByType() render the specified metadata type
861
     *
862
     * @param string $type type to render
863
     *
864
     * @return string
865
     */
866
    public function renderMetasByType($type)
867
    {
868
        if (!isset($type)) {
869
            return '';
870
        }
871
872
        $str = '';
873
        switch ($type) {
874
            case 'script':
875
                foreach ($this->metas[$type] as $attrs) {
876
                    $str .= "<script" . $this->renderAttributes($attrs) . ">";
877
                    if (@$attrs['_']) {
878
                        $str .= "\n//<![CDATA[\n" . $attrs['_'] . "\n//]]>";
879
                    }
880
                    $str .= "</script>\n";
881
                }
882
                break;
883
            case 'link':
884
                foreach ($this->metas[$type] as $attrs) {
885
                    $rel = $attrs['rel'];
886
                    unset($attrs['rel']);
887
                    $str .= '<link rel="' . $rel . '"' . $this->renderAttributes($attrs) . " />\n";
888
                }
889
                break;
890
            case 'stylesheet':
891
                foreach ($this->metas[$type] as $attrs) {
892
                    if (@$attrs['_']) {
893
                        $str .= '<style' . $this->renderAttributes($attrs)
894
                            . ">\n/* <![CDATA[ */\n" . $attrs['_'] . "\n/* //]]> */\n</style>";
895
                    } else {
896
                        $str .= '<link rel="stylesheet"' . $this->renderAttributes($attrs) . " />\n";
897
                    }
898
                }
899
                break;
900
            case 'http':
901
                foreach ($this->metas[$type] as $name => $content) {
902
                    $str .= '<meta http-equiv="' . htmlspecialchars($name, ENT_QUOTES) . '" content="'
903
                        . htmlspecialchars($content, ENT_QUOTES) . "\" />\n";
904
                }
905
                break;
906
            default:
907
                foreach ($this->metas[$type] as $name => $content) {
908
                    $str .= '<meta name="' . htmlspecialchars($name, ENT_QUOTES) . '" content="'
909
                        . htmlspecialchars($content, ENT_QUOTES) . "\" />\n";
910
                }
911
                break;
912
        }
913
914
        return $str;
915
    }
916
917
    /**
918
     * Generates a unique element ID
919
     *
920
     * @param string $tagName tag
921
     *
922
     * @return string
923
     */
924
    public function genElementId($tagName = 'xos')
925
    {
926
        static $cache = array();
927
        if (!isset($cache[$tagName])) {
928
            $cache[$tagName] = 1;
929
        }
930
        return $tagName . '-' . $cache[$tagName]++;
931
    }
932
933
    /**
934
     * Transform an attributes collection to an XML string
935
     *
936
     * @param array $coll collection of attributes
937
     *
938
     * @return string
939
     */
940
    public function renderAttributes($coll)
941
    {
942
        $str = '';
943
        foreach ($coll as $name => $val) {
944
            if ($name !== '_') {
945
                $str .= ' ' . $name . '="' . htmlspecialchars($val, ENT_QUOTES) . '"';
946
            }
947
        }
948
        return $str;
949
    }
950
951
    /**
952
     * Return a themable file resource path
953
     *
954
     * @param string $path file path
955
     *
956
     * @return string
957
     */
958 7
    public function resourcePath($path)
959
    {
960 7
        if (substr($path, 0, 1) === '/') {
961
            $path = substr($path, 1);
962
        }
963 7
        $xoops_root_path = \XoopsBaseConfig::get('root-path');
964
//\Xoops::getInstance()->events()->triggerEvent('debug.log', $this);
965 7
        if (\XoopsLoad::fileExists($xoops_root_path . "/{$this->themesPath}/{$this->folderName}/{$path}")) {
966
//\Xoops::getInstance()->events()->triggerEvent('debug.log', "custom theme path {$this->themesPath}/{$this->folderName}/{$path}");
967 4
            return "{$this->themesPath}/{$this->folderName}/{$path}";
968
        }
969
970 7
        if (\XoopsLoad::fileExists($xoops_root_path . "/themes/{$this->folderName}/{$path}")) {
971
//\Xoops::getInstance()->events()->triggerEvent('debug.log', "main theme folder themes/{$this->folderName}/{$path}");
972
            return "themes/{$this->folderName}/{$path}";
973
        }
974
//\Xoops::getInstance()->events()->triggerEvent('debug.log', "drop thru {$path}");
975 7
        return $path;
976
    }
977
}
978