Completed
Pull Request — master (#197)
by
unknown
13:25
created

xos_opal_Theme   D

Complexity

Total Complexity 105

Size/Duplication

Total Lines 716
Duplicated Lines 10.34 %

Coupling/Cohesion

Components 1
Dependencies 5

Importance

Changes 2
Bugs 0 Features 2
Metric Value
c 2
b 0
f 2
dl 74
loc 716
rs 4
wmc 105
lcom 1
cbo 5

16 Methods

Rating   Name   Duplication   Size   Complexity  
D xoInit() 0 86 17
B generateCacheId() 0 28 6
C checkCache() 0 23 8
F render() 0 88 19
A loadLocalization() 6 18 4
A addLanguage() 0 12 4
B addScript() 20 20 6
B addStylesheet() 20 20 6
A addLink() 0 14 4
A addHttpMeta() 0 8 2
A addMeta() 0 13 3
A headContent() 0 6 2
C renderMetas() 28 54 15
A genElementId() 0 9 2
A renderAttributes() 0 11 3
A resourcePath() 0 16 4

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like xos_opal_Theme 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. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

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 xos_opal_Theme, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 31 and the first side effect is on line 21.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * xos_opal_Theme component class file
4
 *
5
 * You may not change or alter any portion of this comment or credits
6
 * of supporting developers from this source code or any supporting source code
7
 * which is considered copyrighted (c) material of the original comment or credit authors.
8
 * This program is distributed in the hope that it will be useful,
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
 *
12
 * @copyright       (c) 2000-2016 XOOPS Project (www.xoops.org)
13
 * @license             GNU GPL 2 (http://www.gnu.org/licenses/gpl-2.0.html)
14
 * @author              Skalpa Keo <[email protected]>
15
 * @author              Taiwen Jiang <[email protected]>
16
 * @since               2.3.0
17
 * @package             kernel
18
 * @subpackage          xos_opal_Theme
19
 */
20
21
defined('XOOPS_ROOT_PATH') || exit('Restricted access');
22
23
/**
24
 * xos_opal_ThemeFactory
25
 *
26
 * @author     Skalpa Keo
27
 * @package    xos_opal
28
 * @subpackage xos_opal_Theme
29
 * @since      2.3.0
30
 */
31
class xos_opal_ThemeFactory
32
{
33
    public $xoBundleIdentifier = 'xos_opal_ThemeFactory';
34
    /**
35
     * Currently enabled themes (if empty, all the themes in themes/ are allowed)
36
     *
37
     * @var array
38
     */
39
    public $allowedThemes = array();
40
    /**
41
     * Default theme to instanciate if none specified
42
     *
43
     * @var string
44
     */
45
    public $defaultTheme = 'default';
46
    /**
47
     * If users are allowed to choose a custom theme
48
     *
49
     * @var bool
50
     */
51
    public $allowUserSelection = true;
52
53
    /**
54
     * Instanciate the specified theme
55
     * @param  array $options
56
     * @param  array $initArgs
57
     * @return null|xos_opal_Theme
58
     */
59
    public function &createInstance($options = array(), $initArgs = array())
60
    {
61
        // Grab the theme folder from request vars if present
62
        if (empty($options['folderName'])) {
63
            if (($req = @$_REQUEST['xoops_theme_select']) && $this->isThemeAllowed($req)) {
64
                $options['folderName'] = $req;
65
                if (isset($_SESSION) && $this->allowUserSelection) {
66
                    $_SESSION[$this->xoBundleIdentifier]['defaultTheme'] = $req;
67
                }
68
            } elseif (isset($_SESSION[$this->xoBundleIdentifier]['defaultTheme'])) {
69
                $options['folderName'] = $_SESSION[$this->xoBundleIdentifier]['defaultTheme'];
70
            } elseif (empty($options['folderName']) || !$this->isThemeAllowed($options['folderName'])) {
71
                $options['folderName'] = $this->defaultTheme;
72
            }
73
            $GLOBALS['xoopsConfig']['theme_set'] = $options['folderName'];
74
        }
75
        $options['path'] = XOOPS_THEME_PATH . '/' . $options['folderName'];
76
        $inst            = null;
0 ignored issues
show
Unused Code introduced by
$inst is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
77
        $inst            = new xos_opal_Theme();
78
        foreach ($options as $k => $v) {
79
            $inst->$k = $v;
80
        }
81
        $inst->xoInit();
82
83
        return $inst;
84
    }
85
86
    /**
87
     * Checks if the specified theme is enabled or not
88
     *
89
     * @param  string $name
90
     * @return bool
91
     */
92
    public function isThemeAllowed($name)
93
    {
94
        return (empty($this->allowedThemes) || in_array($name, $this->allowedThemes));
95
    }
96
}
97
98
/**
99
 * xos_opal_AdminThemeFactory
100
 *
101
 * @author     Andricq Nicolas (AKA MusS)
102
 * @author     trabis
103
 * @package    xos_opal
104
 * @subpackage xos_opal_Theme
105
 * @since      2.4.0
106
 */
107
class xos_opal_AdminThemeFactory extends xos_opal_ThemeFactory
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
108
{
109
    /**
110
     * @param array $options
111
     * @param array $initArgs
112
     *
113
     * @return null|xos_opal_Theme
114
     */
115
    public function &createInstance($options = array(), $initArgs = array())
116
    {
117
        $options['plugins']      = array();
118
        $options['renderBanner'] = false;
119
        $inst                    =& parent::createInstance($options, $initArgs);
120
        $inst->path              = XOOPS_ADMINTHEME_PATH . '/' . $inst->folderName;
121
        $inst->url               = XOOPS_ADMINTHEME_URL . '/' . $inst->folderName;
122
        $inst->template->assign(array(
123
                                    'theme_path'  => $inst->path,
124
                                    'theme_tpl'   => $inst->path . '/xotpl',
125
                                    'theme_url'   => $inst->url,
126
                                    'theme_img'   => $inst->url . '/img',
127
                                    'theme_icons' => $inst->url . '/icons',
128
                                    'theme_css'   => $inst->url . '/css',
129
                                    'theme_js'    => $inst->url . '/js',
130
                                    'theme_lang'  => $inst->url . '/language'));
131
132
        return $inst;
133
    }
134
}
135
136
/**
137
 * Class xos_opal_Theme
138
 */
139
class xos_opal_Theme
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class should be in its own file to aid autoloaders.

Having each class in a dedicated file usually plays nice with PSR autoloaders and is therefore a well established practice. If you use other autoloaders, you might not want to follow this rule.

Loading history...
140
{
141
    /**
142
     * Should we render banner? Not for redirect pages or admin side
143
     *
144
     * @var bool
145
     */
146
    public $renderBanner = true;
147
    /**
148
     * The name of this theme
149
     *
150
     * @var string
151
     */
152
    public $folderName = '';
153
    /**
154
     * Physical path of this theme folder
155
     *
156
     * @var string
157
     */
158
    public $path = '';
159
    public $url  = '';
160
161
    /**
162
     * Whether or not the theme engine should include the output generated by php
163
     *
164
     * @var string
165
     */
166
    public $bufferOutput = true;
167
    /**
168
     * Canvas-level template to use
169
     *
170
     * @var string
171
     */
172
    public $canvasTemplate = 'theme.html';
173
174
    /**
175
     * Theme folder path
176
     *
177
     * @var string
178
     */
179
    public $themesPath = 'themes';
180
181
    /**
182
     * Content-level template to use
183
     *
184
     * @var string
185
     */
186
    public $contentTemplate = '';
187
188
    public $contentCacheLifetime = 0;
189
    public $contentCacheId;
190
191
    /**
192
     * Text content to display right after the contentTemplate output
193
     *
194
     * @var string
195
     */
196
    public $content = '';
197
    /**
198
     * Page construction plug-ins to use
199
     *
200
     * @var array
201
     * @access public
202
     */
203
    public $plugins     = array(
204
        'xos_logos_PageBuilder');
205
    public $renderCount = 0;
206
    /**
207
     * Pointer to the theme template engine
208
     *
209
     * @var XoopsTpl
210
     */
211
    public $template = false;
212
213
    /**
214
     * Array containing the document meta-information
215
     *
216
     * @var array
217
     */
218
    public $metas = array(
219
        //'http' => array(
220
        //    'Content-Script-Type' => 'text/javascript' ,
221
        //    'Content-Style-Type' => 'text/css') ,
222
        'meta'   => array(),
223
        'link'   => array(),
224
        'script' => array());
225
226
    /**
227
     * Array of strings to be inserted in the head tag of HTML documents
228
     *
229
     * @var array
230
     */
231
    public $htmlHeadStrings = array();
232
    /**
233
     * Custom variables that will always be assigned to the template
234
     *
235
     * @var array
236
     */
237
    public $templateVars = array();
238
239
    /**
240
     * User extra information for cache id, like language, user groups
241
     *
242
     * @var boolean
243
     */
244
    public $use_extra_cache_id = true;
245
246
    /**
247
     * *#@-
248
     */
249
250
    /**
251
     * *#@+
252
     *
253
     * @tasktype 10 Initialization
254
     */
255
    /**
256
     * Initializes this theme
257
     *
258
     * Upon initialization, the theme creates its template engine and instanciates the
259
     * plug-ins from the specified {@link $plugins} list. If the theme is a 2.0 theme, that does not
260
     * display redirection messages, the HTTP redirections system is disabled to ensure users will
261
     * see the redirection screen.
262
     *
263
     * @param  array $options
264
     * @return bool
265
     */
266
    public function xoInit($options = array())
0 ignored issues
show
Unused Code introduced by
The parameter $options is not used and could be removed.

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

Loading history...
267
    {
268
        $this->path                   = XOOPS_THEME_PATH . '/' . $this->folderName;
269
        $this->url                    = XOOPS_THEME_URL . '/' . $this->folderName;
270
        $this->template               = null;
271
        $this->template               = new XoopsTpl();
272
        $this->template->currentTheme =& $this;
0 ignored issues
show
Bug introduced by
The property currentTheme does not seem to exist in XoopsTpl.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
273
        $this->template->assign_by_ref('xoTheme', $this);
274
		$xoops_page = str_replace(XOOPS_ROOT_PATH . '/', '', $_SERVER['SCRIPT_FILENAME']);
275
		if (strpos($xoops_page, 'modules') !== false){
276
            $xoops_page = str_replace('modules/', '', $xoops_page);
277
        }
278
		$xoops_page = str_replace('.php', '', $xoops_page);
279
		if (isset($GLOBALS['xoopsConfig']['startpage'])){
280
			$xoops_startpage = $GLOBALS['xoopsConfig']['startpage'];
281
			if ($xoops_startpage == '--') {
282
				$xoops_startpage = 'system';
283
			}
284
		} else {
285
			$xoops_startpage = 'system';
286
		}
287
        $this->template->assign(array(
288
                                    'xoops_theme'      => $GLOBALS['xoopsConfig']['theme_set'],
289
                                    'xoops_imageurl'   => XOOPS_THEME_URL . '/' . $GLOBALS['xoopsConfig']['theme_set'] . '/',
290
                                    'xoops_themecss'   => xoops_getcss($GLOBALS['xoopsConfig']['theme_set']),
291
                                    'xoops_requesturi' => htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES),
292
                                    'xoops_sitename'   => htmlspecialchars($GLOBALS['xoopsConfig']['sitename'], ENT_QUOTES),
293
                                    'xoops_slogan'     => htmlspecialchars($GLOBALS['xoopsConfig']['slogan'], ENT_QUOTES),
294
                                    'xoops_dirname'    => isset($GLOBALS['xoopsModule']) && is_object($GLOBALS['xoopsModule']) ? $GLOBALS['xoopsModule']->getVar('dirname') : 'system',
295
									'xoops_page'       => $xoops_page,
296
									'xoops_startpage'  => $xoops_startpage,
297
                                    'xoops_banner'     => ($GLOBALS['xoopsConfig']['banners'] && $this->renderBanner) ? xoops_getbanner() : '&nbsp;',
298
                                    'xoops_pagetitle'  => isset($GLOBALS['xoopsModule']) && is_object($GLOBALS['xoopsModule']) ? $GLOBALS['xoopsModule']->getVar('name') : htmlspecialchars($GLOBALS['xoopsConfig']['slogan'], ENT_QUOTES)));
299
        if (isset($GLOBALS['xoopsUser']) && is_object($GLOBALS['xoopsUser'])) {
300
            $this->template->assign(array(
301
                                        'xoops_isuser'     => true,
302
                                        'xoops_avatar'     => XOOPS_UPLOAD_URL . '/' . $GLOBALS['xoopsUser']->getVar('user_avatar'),
303
                                        'xoops_userid'     => $GLOBALS['xoopsUser']->getVar('uid'),
304
                                        'xoops_uname'      => $GLOBALS['xoopsUser']->getVar('uname'),
305
                                        'xoops_name'       => $GLOBALS['xoopsUser']->getVar('name'),
306
                                        'xoops_isadmin'    => $GLOBALS['xoopsUserIsAdmin'],
307
                                        'xoops_usergroups' => $GLOBALS['xoopsUser']->getGroups()));
308
        } else {
309
            $this->template->assign(array(
310
                                        'xoops_isuser'     => false,
311
                                        'xoops_isadmin'    => false,
312
                                        'xoops_usergroups' => array(XOOPS_GROUP_ANONYMOUS)));
313
        }
314
315
        // Meta tags
316
        $config_handler = xoops_getHandler('config');
317
        $criteria       = new CriteriaCompo(new Criteria('conf_modid', 0));
318
        $criteria->add(new Criteria('conf_catid', XOOPS_CONF_METAFOOTER));
319
        $config = $config_handler->getConfigs($criteria, true);
320
        foreach (array_keys($config) as $i) {
321
            $name  = $config[$i]->getVar('conf_name', 'n');
322
            $value = $config[$i]->getVar('conf_value', 'n');
323
            if (substr($name, 0, 5) === 'meta_') {
324
                $this->addMeta('meta', substr($name, 5), $value);
325
            } else {
326
                // prefix each tag with 'xoops_'
327
                $this->template->assign("xoops_$name", $value);
328
            }
329
        }
330
        // Load global javascript
331
        $this->addScript('include/xoops.js');
332
        $this->loadLocalization();
333
334
        if ($this->bufferOutput) {
335
            ob_start();
336
        }
337
        $GLOBALS['xoTheme']  =& $this;
338
        $GLOBALS['xoopsTpl'] =& $this->template;
339
        // Instanciate and initialize all the theme plugins
340
        foreach ($this->plugins as $k => $bundleId) {
341
            if (!is_object($bundleId)) {
342
                $this->plugins[$bundleId]        = null;
343
                $this->plugins[$bundleId]        = new $bundleId();
344
                $this->plugins[$bundleId]->theme =& $this;
345
                $this->plugins[$bundleId]->xoInit();
346
                unset($this->plugins[$k]);
347
            }
348
        }
349
350
        return true;
351
    }
352
353
    /**
354
     * Generate cache id based on extra information of language and user groups
355
     *
356
     * User groups other than anonymous should be detected to avoid disclosing group sensitive contents
357
     *
358
     * @param  string $cache_id    raw cache id
359
     * @param  string $extraString extra string
360
     * @return string complete cache id
361
     */
362
    public function generateCacheId($cache_id, $extraString = '')
363
    {
364
        static $extra_string;
365
        if (!$this->use_extra_cache_id) {
366
            return $cache_id;
367
        }
368
369
        if (empty($extraString)) {
370
            if (empty($extra_string)) {
371
                // Generate language section
372
                $extra_string = $GLOBALS['xoopsConfig']['language'];
373
                // Generate group section
374
                if (!isset($GLOBALS['xoopsUser']) || !is_object($GLOBALS['xoopsUser'])) {
375
                    $extra_string .= '-' . XOOPS_GROUP_ANONYMOUS;
376
                } else {
377
                    $groups = $GLOBALS['xoopsUser']->getGroups();
378
                    sort($groups);
379
                    // Generate group string for non-anonymous groups,
380
                    // XOOPS_DB_PASS and XOOPS_DB_NAME (before we find better variables) are used to protect group sensitive contents
381
                    $extra_string .= '-' . substr(md5(implode('-', $groups)), 0, 8) . '-' . substr(md5(XOOPS_DB_PASS . XOOPS_DB_NAME . XOOPS_DB_USER), 0, 8);
382
                }
383
            }
384
            $extraString = $extra_string;
385
        }
386
        $cache_id .= '-' . $extraString;
387
388
        return $cache_id;
389
    }
390
391
    /**
392
     * xos_opal_Theme::checkCache()
393
     *
394
     * @return bool
395
     */
396
    public function checkCache()
397
    {
398
        if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $this->contentCacheLifetime) {
399
            $template                       = $this->contentTemplate ?: 'db:system_dummy.tpl';
400
            $this->template->caching        = 2;
401
            $this->template->cache_lifetime = $this->contentCacheLifetime;
402
            $uri                            = str_replace(XOOPS_URL, '', $_SERVER['REQUEST_URI']);
403
            // Clean uri by removing session id
404
            if (defined('SID') && SID && strpos($uri, SID)) {
405
                $uri = preg_replace("/([\?&])(" . SID . "$|" . SID . '&)/', "\\1", $uri);
406
            }
407
            $this->contentCacheId = $this->generateCacheId('page_' . substr(md5($uri), 0, 8));
408
            if ($this->template->is_cached($template, $this->contentCacheId)) {
409
                $xoopsLogger = XoopsLogger::getInstance();
410
                $xoopsLogger->addExtra($template, sprintf('Cached (regenerates every %d seconds)', $this->contentCacheLifetime));
411
                $this->render(null, null, $template);
412
413
                return true;
414
            }
415
        }
416
417
        return false;
418
    }
419
420
    /**
421
     * Render the page
422
     *
423
     * The theme engine builds pages from 2 templates: canvas and content.
424
     *
425
     * A module can call this method directly and specify what templates the theme engine must use.
426
     * If render() hasn't been called before, the theme defaults will be used for the canvas and
427
     * page template (and xoopsOption['template_main'] for the content).
428
     *
429
     * @param string $canvasTpl  The canvas template, if different from the theme default
430
     * @param string $pageTpl    The page template, if different from the theme default (unsupported, 2.3+ only)
431
     * @param string $contentTpl The content template
432
     * @param array  $vars       Template variables to send to the template engine
433
     *
434
     * @return bool
435
     */
436
    public function render($canvasTpl = null, $pageTpl = null, $contentTpl = null, $vars = array())
0 ignored issues
show
Unused Code introduced by
The parameter $pageTpl is not used and could be removed.

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

Loading history...
437
    {
438
        if ($this->renderCount) {
439
            return false;
440
        }
441
        $xoopsLogger = XoopsLogger::getInstance();
442
        $xoopsLogger->startTime('Page rendering');
443
444
        xoops_load('xoopscache');
445
        $cache = XoopsCache::getInstance();
446
447
        //Get meta information for cached pages
448
        if ($this->contentCacheLifetime && $this->contentCacheId && $content = $cache->read($this->contentCacheId)) {
449
            //we need to merge metas set by blocks ) with the module cached meta
450
            $this->htmlHeadStrings = array_merge($this->htmlHeadStrings, $content['htmlHeadStrings']);
451
            foreach ($content['metas'] as $type => $value) {
452
                $this->metas[$type] = array_merge($this->metas[$type], $content['metas'][$type]);
453
            }
454
            $GLOBALS['xoopsOption']['xoops_pagetitle']     = $content['xoops_pagetitle'];
455
            $GLOBALS['xoopsOption']['xoops_module_header'] = $content['header'];
456
        }
457
458
        if (!empty($GLOBALS['xoopsOption']['xoops_pagetitle'])) {
459
            $this->template->assign('xoops_pagetitle', $GLOBALS['xoopsOption']['xoops_pagetitle']);
460
        }
461
        $header = empty($GLOBALS['xoopsOption']['xoops_module_header']) ? $this->template->get_template_vars('xoops_module_header') : $GLOBALS['xoopsOption']['xoops_module_header'];
462
463
        //save meta information of cached pages
464
        if ($this->contentCacheLifetime && $this->contentCacheId && !$contentTpl) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contentTpl of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
465
            $content['htmlHeadStrings'] = $this->htmlHeadStrings;
0 ignored issues
show
Bug introduced by
The variable $content does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
466
            $content['metas']           = $this->metas;
467
            $content['xoops_pagetitle'] =& $this->template->get_template_vars('xoops_pagetitle');
468
            $content['header']          = $header;
469
            $cache->write($this->contentCacheId, $content);
470
        }
471
472
        //  @internal : Lame fix to ensure the metas specified in the xoops config page don't appear twice
473
        $old = array(
474
            'robots',
475
            'keywords',
476
            'description',
477
            'rating',
478
            'author',
479
            'copyright');
480
        foreach ($this->metas['meta'] as $name => $value) {
481
            if (in_array($name, $old)) {
482
                $this->template->assign("xoops_meta_$name", htmlspecialchars($value, ENT_QUOTES));
483
                unset($this->metas['meta'][$name]);
484
            }
485
        }
486
487
        // We assume no overlap between $GLOBALS['xoopsOption']['xoops_module_header'] and $this->template->get_template_vars( 'xoops_module_header' ) ?
488
        $this->template->assign('xoops_module_header', $this->renderMetas(null, true) . "\n" . $header);
489
490
        if ($canvasTpl) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $canvasTpl of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
491
            $this->canvasTemplate = $canvasTpl;
492
        }
493
        if ($contentTpl) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $contentTpl of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
494
            $this->contentTemplate = $contentTpl;
495
        }
496
        if (!empty($vars)) {
497
            $this->template->assign($vars);
498
        }
499
        if ($this->contentTemplate) {
500
            $this->content = $this->template->fetch($this->contentTemplate, $this->contentCacheId);
501
        }
502
        if ($this->bufferOutput) {
503
            $this->content .= ob_get_contents();
504
            ob_end_clean();
505
        }
506
507
        $this->template->assign_by_ref('xoops_contents', $this->content);
508
509
        // Do not cache the main (theme.html) template output
510
        $this->template->caching = 0;
511
        //mb -------------------------
512
//        $this->template->display($this->path . '/' . $this->canvasTemplate);
513
        if (file_exists($this->path . '/' . $this->canvasTemplate)) {
514
            $this->template->display($this->path . '/' . $this->canvasTemplate);
515
        } else {
516
            $this->template->display($this->path . '/theme.tpl');
517
        }
518
        //mb -------------------------
519
        $this->renderCount++;
520
        $xoopsLogger->stopTime('Page rendering');
521
522
        return true;
523
    }
524
525
    /**
526
     * Load localization information
527
     *
528
     * Folder structure for localization:
529
     * <ul>themes/themefolder/english
530
     *     <li>main.php - language definitions</li>
531
     *     <li>style.css - localization stylesheet</li>
532
     *     <li>script.js - localization script</li>
533
     * </ul>
534
     * @param  string $type
535
     * @return bool
536
     */
537
    public function loadLocalization($type = 'main')
538
    {
539
        $language = $GLOBALS['xoopsConfig']['language'];
540
        // Load global localization stylesheet if available
541
        if (file_exists($GLOBALS['xoops']->path('language/' . $language . '/style.css'))) {
542
            $this->addStylesheet($GLOBALS['xoops']->url('language/' . $language . '/style.css'));
543
        }
544
        $this->addLanguage($type, $language);
545
        // Load theme localization stylesheet and scripts if available
546 View Code Duplication
        if (file_exists($this->path . '/language/' . $language . '/script.js')) {
547
            $this->addScript($this->url . '/language/' . $language . '/script.js');
548
        }
549 View Code Duplication
        if (file_exists($this->path . '/language/' . $language . '/style.css')) {
550
            $this->addStylesheet($this->url . '/language/' . $language . '/style.css');
551
        }
552
553
        return true;
554
    }
555
556
    /**
557
     * Load theme specific language constants
558
     *
559
     * @param string $type     language type, like 'main', 'admin'; Needs to be declared in theme xo-info.php
560
     * @param string $language specific language
561
     *
562
     * @return bool|mixed
563
     */
564
    public function addLanguage($type = 'main', $language = null)
565
    {
566
        $language = (null === $language) ? $GLOBALS['xoopsConfig']['language'] : $language;
567
        if (!file_exists($fileinc = $this->path . "/language/{$language}/{$type}.php")) {
568
            if (!file_exists($fileinc = $this->path . "/language/english/{$type}.php")) {
569
                return false;
570
            }
571
        }
572
        $ret = include_once $fileinc;
573
574
        return $ret;
575
    }
576
577
    /**
578
     * *#@+
579
     *
580
     * @tasktype 20 Manipulating page meta-information
581
     */
582
    /**
583
     * Adds script code to the document head
584
     *
585
     * This methods allows the insertion of an external script file (if $src is provided), or
586
     * of a script snippet. The file URI is parsed to take benefit of the theme resource
587
     * overloading system.
588
     *
589
     * The $attributes parameter allows you to specify the attributes that will be added to the
590
     * inserted <script> tag. If unspecified, the <var>type</var> attribute value will default to
591
     * 'text/javascript'.
592
     *
593
     * <code>
594
     * // Add an external script using a physical path
595
     * $theme->addScript( 'www/script.js', null, '' );
596
     * $theme->addScript( 'modules/newbb/script.js', null, '' );
597
     * // Specify attributes for the <script> tag
598
     * $theme->addScript( 'mod_xoops_SiteManager#common.js', array( 'type' => 'application/x-javascript' ), '', 'mod_xoops_Sitemanager' );
599
     * // Insert a code snippet
600
     * $theme->addScript( null, array( 'type' => 'application/x-javascript' ), 'window.open("Hello world");', 'hello' );
601
     * </code>
602
     *
603
     * @param  string $src        path to an external script file
604
     * @param  array  $attributes hash of attributes to add to the <script> tag
605
     * @param  string $content    Code snippet to output within the <script> tag
606
     * @param  string $name       Element Name in array scripts are stored in.
607
     * @return void
608
     */
609 View Code Duplication
    public function addScript($src = '', $attributes = array(), $content = '', $name = '')
610
    {
611
        if (empty($attributes)) {
612
            $attributes = array();
613
        }
614
        if (!empty($src)) {
615
            $src               = $GLOBALS['xoops']->url($this->resourcePath($src));
616
            $attributes['src'] = $src;
617
        }
618
        if (!empty($content)) {
619
            $attributes['_'] = $content;
620
        }
621
        if (!isset($attributes['type'])) {
622
            $attributes['type'] = 'text/javascript';
623
        }
624
        if (empty($name)) {
625
            $name = md5(serialize($attributes));
626
        }
627
        $this->addMeta('script', $name, $attributes);
628
    }
629
630
    /**
631
     * Add StyleSheet or CSS code to the document head
632
     *
633
     * @param  string $src        path to .css file
634
     * @param  array  $attributes name => value paired array of attributes such as title
635
     * @param  string $content    CSS code to output between the <style> tags (in case $src is empty)
636
     * @param  string $name       Element Name in array stylesheets are stored in.
637
     * @return void
638
     */
639 View Code Duplication
    public function addStylesheet($src = '', $attributes = array(), $content = '', $name = '')
640
    {
641
        if (empty($attributes)) {
642
            $attributes = array();
643
        }
644
        if (!empty($src)) {
645
            $src                = $GLOBALS['xoops']->url($this->resourcePath($src));
646
            $attributes['href'] = $src;
647
        }
648
        if (!isset($attributes['type'])) {
649
            $attributes['type'] = 'text/css';
650
        }
651
        if (!empty($content)) {
652
            $attributes['_'] = $content;
653
        }
654
        if (empty($name)) {
655
            $name = md5(serialize($attributes));
656
        }
657
        $this->addMeta('stylesheet', $name, $attributes);
658
    }
659
660
    /**
661
     * Add a <link> to the header
662
     *
663
     * @param string $rel        Relationship from the current doc to the anchored one
664
     * @param string $href       URI of the anchored document
665
     * @param array  $attributes Additional attributes to add to the <link> element
666
     * @param string $name       Element Name in array links are stored in.
667
     */
668
    public function addLink($rel, $href = '', $attributes = array(), $name = '')
669
    {
670
        if (empty($attributes)) {
671
            $attributes = array();
672
        }
673
        if (!empty($href)) {
674
            $attributes['href'] = $href;
675
        }
676
        $attributes['rel'] = $rel;
677
        if (empty($name)) {
678
            $name = md5(serialize($attributes));
679
        }
680
        $this->addMeta('link', $name, $attributes);
681
    }
682
683
    /**
684
     * Set a meta http-equiv value
685
     * @param         $name
686
     * @param  null   $value
687
     * @return string
0 ignored issues
show
Documentation introduced by
Should the return type not be string|null?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
688
     */
689
    public function addHttpMeta($name, $value = null)
690
    {
691
        if (isset($value)) {
692
            return $this->addMeta('http', $name, $value);
693
        }
694
        unset($this->metas['http'][$name]);
695
        return null;
696
    }
697
698
    /**
699
     * Change output page meta-information
700
     * @param  string $type
701
     * @param  string $name
702
     * @param  string $value
703
     * @return string
704
     */
705
    public function addMeta($type = 'meta', $name = '', $value = '')
706
    {
707
        if (!isset($this->metas[$type])) {
708
            $this->metas[$type] = array();
709
        }
710
        if (!empty($name)) {
711
            $this->metas[$type][$name] = $value;
712
        } else {
713
            $this->metas[$type][md5(serialize(array($value)))] = $value;
714
        }
715
716
        return $value;
717
    }
718
719
    /**
720
     * xos_opal_Theme::headContent()
721
     *
722
     * @param mixed $params
723
     * @param mixed $content
724
     * @param mixed $smarty
725
     * @param mixed $repeat
726
     *
727
     * @return void
728
     */
729
    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.

This check looks from 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.

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

Loading history...
730
    {
731
        if (!$repeat) {
732
            $this->htmlHeadStrings[] = $content;
733
        }
734
    }
735
736
    /**
737
     * xos_opal_Theme::renderMetas()
738
     *
739
     * @param  mixed $type
740
     * @param  mixed $return
741
     * @return bool|string
742
     */
743
    public function renderMetas($type = null, $return = false)
744
    {
745
        $str = '';
746
        if (!isset($type)) {
747
            foreach (array_keys($this->metas) as $type) {
748
                $str .= $this->renderMetas($type, true);
749
            }
750
            $str .= implode("\n", $this->htmlHeadStrings);
751
        } else {
752
            switch ($type) {
753 View Code Duplication
                case 'script':
754
                    foreach ($this->metas[$type] as $attrs) {
755
                        $str .= '<script' . $this->renderAttributes($attrs) . '>';
756
                        if (@$attrs['_']) {
757
                            $str .= "\n//<![CDATA[\n" . $attrs['_'] . "\n//]]>";
758
                        }
759
                        $str .= "</script>\n";
760
                    }
761
                    break;
762
                case 'link':
763
                    foreach ($this->metas[$type] as $attrs) {
764
                        $rel = $attrs['rel'];
765
                        unset($attrs['rel']);
766
                        $str .= '<link rel="' . $rel . '"' . $this->renderAttributes($attrs) . " />\n";
767
                    }
768
                    break;
769 View Code Duplication
                case 'stylesheet':
770
                    foreach ($this->metas[$type] as $attrs) {
771
                        if (@$attrs['_']) {
772
                            $str .= '<style' . $this->renderAttributes($attrs) . ">\n/* <![CDATA[ */\n" . $attrs['_'] . "\n/* //]]> */\n</style>";
773
                        } else {
774
                            $str .= '<link rel="stylesheet"' . $this->renderAttributes($attrs) . " />\n";
775
                        }
776
                    }
777
                    break;
778 View Code Duplication
                case 'http':
779
                    foreach ($this->metas[$type] as $name => $content) {
780
                        $str .= '<meta http-equiv="' . htmlspecialchars($name, ENT_QUOTES) . '" content="' . htmlspecialchars($content, ENT_QUOTES) . "\" />\n";
781
                    }
782
                    break;
783 View Code Duplication
                default:
784
                    foreach ($this->metas[$type] as $name => $content) {
785
                        $str .= '<meta name="' . htmlspecialchars($name, ENT_QUOTES) . '" content="' . htmlspecialchars($content, ENT_QUOTES) . "\" />\n";
786
                    }
787
                    break;
788
            }
789
        }
790
        if ($return) {
791
            return $str;
792
        }
793
        echo $str;
794
795
        return true;
796
    }
797
798
    /**
799
     * Generates a unique element ID
800
     *
801
     * @param  string $tagName
802
     * @return string
803
     */
804
    public function genElementId($tagName = 'xos')
805
    {
806
        static $cache = array();
807
        if (!isset($cache[$tagName])) {
808
            $cache[$tagName] = 1;
809
        }
810
811
        return $tagName . '-' . $cache[$tagName]++;
812
    }
813
814
    /**
815
     * Transform an attributes collection to an XML string
816
     *
817
     * @param  array $coll
818
     * @return string
819
     */
820
    public function renderAttributes($coll)
821
    {
822
        $str = '';
823
        foreach ($coll as $name => $val) {
824
            if ($name !== '_') {
825
                $str .= ' ' . $name . '="' . htmlspecialchars($val, ENT_QUOTES) . '"';
826
            }
827
        }
828
829
        return $str;
830
    }
831
832
    /**
833
     * Return a themable file resource path
834
     *
835
     * @param  string $path
836
     * @return string
837
     */
838
    public function resourcePath($path)
839
    {
840
        if (substr($path, 0, 1) === '/') {
841
            $path = substr($path, 1);
842
        }
843
844
        if (file_exists(XOOPS_ROOT_PATH . "/{$this->themesPath}/{$this->folderName}/{$path}")) {
845
            return "{$this->themesPath}/{$this->folderName}/{$path}";
846
        }
847
848
        if (file_exists(XOOPS_ROOT_PATH . "/themes/{$this->folderName}/{$path}")) {
849
            return "themes/{$this->folderName}/{$path}";
850
        }
851
852
        return $path;
853
    }
854
}
855