Completed
Push — master ( 29f185...9200bf )
by Michael
18s
created

XoopsTheme::renderMetas()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 15
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 15
ccs 0
cts 9
cp 0
rs 9.4285
cc 3
eloc 9
nc 4
nop 1
crap 12
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-2015 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
     */
180
181
    /**
182
     * *#@+
183
     * @tasktype 10 Initialization
184
     */
185
    /**
186
     * Initializes this theme
187
     * Upon initialization, the theme creates its template engine and instantiates the
188
     * plug-ins from the specified {@link $plugins} list. If the theme is a 2.0 theme, that does not
189
     * display redirection messages, the HTTP redirection system is disabled to ensure users will
190
     * see the redirection screen.
191
     *
192
     * @return bool
193
     */
194 4
    public function xoInit()
0 ignored issues
show
Coding Style introduced by
xoInit uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
Coding Style introduced by
xoInit uses the super-global variable $GLOBALS which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
195
    {
196 4
        $xoops = \Xoops::getInstance();
197 4
        $this->assets = $xoops->assets();
198 4
        $this->path = \XoopsBaseConfig::get('themes-path') . '/' . $this->folderName;
199 4
        $this->url = \XoopsBaseConfig::get('themes-url') . '/' . $this->folderName;
200 4
        $this->template = null;
201 4
        $this->template = new XoopsTpl();
202
        //$this->template->currentTheme = $this;
203 4
        $this->template->assignByRef('xoTheme', $this);
204 4
        $this->template->assign(array(
205 4
            'xoops_theme'      => $xoops->getConfig('theme_set'),
206 4
            'xoops_imageurl'   => \XoopsBaseConfig::get('themes-url') . '/' . $xoops->getConfig('theme_set') . '/',
207 4
            'xoops_themecss'   => $xoops->getCss($xoops->getConfig('theme_set')),
208 4
            'xoops_requesturi' => htmlspecialchars($_SERVER['REQUEST_URI'], ENT_QUOTES),
209 4
            'xoops_sitename'   => htmlspecialchars($xoops->getConfig('sitename'), ENT_QUOTES),
210 4
            'xoops_slogan'     => htmlspecialchars($xoops->getConfig('slogan'), ENT_QUOTES),
211 4
            'xoops_dirname'    => $xoops->moduleDirname,
212 4
            'xoops_banner'     => $this->renderBanner ? $xoops->getBanner() : '&nbsp;',
213 4
            'xoops_pagetitle'  => $xoops->isModule()
214
                ? $xoops->module->getVar('name')
215 4
                : htmlspecialchars($xoops->getConfig('slogan'), ENT_QUOTES)
216
        ));
217 4
        $this->template->assign(array(
218 4
            'theme_path' => $this->path, 'theme_tpl' => $this->path . '/xotpl', 'theme_url' => $this->url,
219 4
            'theme_img'  => $this->url . '/img', 'theme_icons' => $this->url . '/icons',
220 4
            'theme_css'  => $this->url . '/css', 'theme_js' => $this->url . '/js',
221 4
            'theme_lang' => $this->url . '/language',
222
        ));
223
224 4
        if ($xoops->isUser()) {
225
            $response = $xoops->service("Avatar")->getAvatarUrl($xoops->user);
226
            $avatar = $response->getValue();
227
            $avatar = empty($avatar) ? '' : $avatar;
228
229
            $this->template->assign(array(
230
                'xoops_isuser'     => true,
231
                'xoops_avatar'     => $avatar,
232
                'xoops_userid'     => $xoops->user->getVar('uid'), 'xoops_uname' => $xoops->user->getVar('uname'),
233
                'xoops_name'       => $xoops->user->getVar('name'), 'xoops_isadmin' => $xoops->isAdmin(),
234
                'xoops_usergroups' => $xoops->user->getGroups()
235
            ));
236
        } else {
237 4
            $this->template->assign(array(
238 4
                'xoops_isuser' => false,
239
                'xoops_isadmin' => false,
240 4
                'xoops_usergroups' => array(FixedGroups::ANONYMOUS)
241
            ));
242
        }
243
244
        // Meta tags
245
        $metas = array(
246 4
            'description', 'keywords', 'robots', 'rating', 'author', 'copyright'
247
        );
248 4
        foreach ($metas as $name) {
249 4
            $this->addMeta('meta', $name, $xoops->getConfig('meta_' . $name));
250
        }
251
252
        // Other assigns
253
        $assigns = array(
254 4
            'title', 'slogan', 'locale', 'footer', 'jquery_theme', 'startpage'
255
        );
256 4
        foreach ($assigns as $name) {
257
            // prefix each tag with 'xoops_'
258 4
            $this->template->assign("xoops_$name", $xoops->getConfig($name));
259
        }
260
261
        // Load global javascript
262
        //$this->addScript('include/xoops.js');
263
        //$this->loadLocalization();
264 4
        list($cssAssets, $jsAssets) = $this->getLocalizationAssets();
265 4
        if (!empty($cssAssets)) {
266
            $this->addBaseStylesheetAssets($cssAssets);
267
        }
268 4
        $this->addBaseScriptAssets('include/xoops.js');
269 4
        $this->addBaseScriptAssets('@jquery');
270
        //$this->addBaseScriptAssets('media/bootstrap/js/bootstrap.min.js');
271 4
        if (!empty($jsAssets)) {
272
            $this->addBaseScriptAssets($jsAssets);
273
        }
274
275 4
        if ($this->bufferOutput) {
276 4
            ob_start();
277
        }
278 4
        $xoops->setTheme($this);
279 4
        $xoops->setTpl($this->template);
280
281
        //For legacy only, never use this Globals
282 4
        $GLOBALS['xoTheme'] = $xoops->theme();
283 4
        $GLOBALS['xoopsTpl'] = $xoops->tpl();
284
285
        //to control order of loading JS and CSS
286
        // TODO - this should be done in such a way it can join the base asset
287
        //        load above.
288 4
        if (\XoopsLoad::fileExists($this->path . "/theme_onload.php")) {
289 4
            include_once($this->path . "/theme_onload.php");
290
        }
291
292
        // Instantiate and initialize all the theme plugins
293 4
        foreach ($this->plugins as $k => $bundleId) {
294 2
            if (!is_object($bundleId)) {
295
                /* @var $plugin PluginAbstract */
296 2
                $plugin = new $bundleId();
297 2
                $plugin->theme = $this;
298 2
                $plugin->xoInit();
299
300 2
                $this->plugins[$bundleId] = null;
301 2
                $this->plugins[$bundleId] = $plugin;
302 2
                unset($this->plugins[$k]);
303
            }
304
        }
305 4
        return true;
306
    }
307
308
    /**
309
     * Generate cache id based on extra information of language and user groups
310
     * User groups other than anonymous should be detected to avoid disclosing group sensitive contents
311
     *
312
     * @param string $cache_id    raw cache id
313
     * @param string $extraString extra string
314
     *
315
     * @return string complete cache id
316
     */
317 2
    public function generateCacheId($cache_id, $extraString = '')
318
    {
319 2
        $xoops = \Xoops::getInstance();
320 2
        static $extra_string;
321 2
        if (!$this->use_extra_cache_id) {
322
            return $cache_id;
323
        }
324
325 2
        if (empty($extraString)) {
326 2
            if (empty($extra_string)) {
327
                // Generate language section
328 1
                $extra_string = $xoops->getConfig('locale');
329
                // Generate group section
330 1
                if (!$xoops->isUser()) {
331 1
                    $extra_string .= '-' . FixedGroups::ANONYMOUS;
332
                } else {
333
                    $groups = $xoops->user->getGroups();
334
                    sort($groups);
335
                    // Generate group string for non-anonymous groups,
336
                    // db-pass and db-name (before we find better variables) are used
337
                    // to protect group sensitive contents
338
                    $extra_string .= '-' . substr(md5(implode('-', $groups)), 0, 8) . '-' . substr(md5(
339
                        \XoopsBaseConfig::get('db-pass') . \XoopsBaseConfig::get('db-name')
340
                        . \XoopsBaseConfig::get('db-user')
341
                    ), 0, 8);
342
                }
343
            }
344 2
            $extraString = $extra_string;
345
        }
346 2
        $cache_id .= '-' . $extraString;
347 2
        return $cache_id;
348
    }
349
350
    /**
351
     * XoopsTheme::checkCache()
352
     *
353
     * @return bool
354
     */
355
    public function checkCache()
0 ignored issues
show
Coding Style introduced by
checkCache uses the super-global variable $_SERVER which is generally not recommended.

Instead of super-globals, we recommend to explicitly inject the dependencies of your class. This makes your code less dependent on global state and it becomes generally more testable:

// Bad
class Router
{
    public function generate($path)
    {
        return $_SERVER['HOST'].$path;
    }
}

// Better
class Router
{
    private $host;

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

    public function generate($path)
    {
        return $this->host.$path;
    }
}

class Controller
{
    public function myAction(Request $request)
    {
        // Instead of
        $page = isset($_GET['page']) ? intval($_GET['page']) : 1;

        // Better (assuming you use the Symfony2 request)
        $page = $request->query->get('page', 1);
    }
}
Loading history...
356
    {
357
        if ($_SERVER['REQUEST_METHOD'] !== 'POST' && $this->contentCacheLifetime) {
358
            $template = $this->contentTemplate ? $this->contentTemplate : 'module:system/system_dummy.tpl';
359
            $this->template->caching = 2;
360
            $this->template->cache_lifetime = $this->contentCacheLifetime;
361
            $uri = str_replace(\XoopsBaseConfig::get('url'), '', $_SERVER['REQUEST_URI']);
362
            // Clean uri by removing session id
363
            if (defined('SID') && SID && strpos($uri, SID)) {
364
                $uri = preg_replace("/([\?&])(" . SID . "$|" . SID . "&)/", "\\1", $uri);
365
            }
366
            $this->contentCacheId = $this->generateCacheId('page_' . substr(md5($uri), 0, 8));
367
            if ($this->template->isCached($template, $this->contentCacheId)) {
368
                \Xoops::getInstance()->events()->triggerEvent('core.theme.checkcache.success', array($template, $this));
369
                $this->render(null, null, $template);
370
                return true;
371
            }
372
        }
373
        return false;
374
    }
375
376
    /**
377
     * Render the page
378
     * The theme engine builds pages from 2 templates: canvas and content.
379
     * A module can call this method directly and specify what templates the theme engine must use.
380
     * If render() hasn't been called before, the theme defaults will be used for the canvas and
381
     * page template (and xoopsOption['template_main'] for the content).
382
     *
383
     * @param string $canvasTpl  The canvas template, if different from the theme default
384
     * @param string $pageTpl    The page template, if different from the theme default (unsupported, 2.3+ only)
385
     * @param string $contentTpl The content template
386
     * @param array  $vars       Template variables to send to the template engine
387
     *
388
     * @return bool
389
     */
390
    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...
391
    {
392
        if ($this->renderCount) {
393
            return false;
394
        }
395
        $xoops = \Xoops::getInstance();
396
        $xoops->events()->triggerEvent('core.theme.render.start', array($this));
397
        $cache = $xoops->cache($this->headersCacheEngine);
398
399
        //Get meta information for cached pages
400
        if ($this->contentCacheLifetime && $this->contentCacheId && $content = $cache->read($this->contentCacheId)) {
401
            //we need to merge metas set by blocks with the module cached meta
402
            $this->htmlHeadStrings = array_merge($this->htmlHeadStrings, $content['htmlHeadStrings']);
403
            foreach ($content['metas'] as $type => $value) {
404
                $this->metas[$type] = array_merge($this->metas[$type], $content['metas'][$type]);
405
            }
406
            $xoops->setOption('xoops_pagetitle', $content['xoops_pagetitle']);
407
            $xoops->setOption('xoops_module_header', $content['header']);
408
        }
409
410
        if ($xoops->getOption('xoops_pagetitle')) {
411
            $this->template->assign('xoops_pagetitle', $xoops->getOption('xoops_pagetitle'));
412
        }
413
        $header = !$xoops->getOption('xoops_module_header')
414
            ? $this->template->getTemplateVars('xoops_module_header')
415
            : $xoops->getOption('xoops_module_header');
416
417
        //save meta information of cached pages
418
        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...
419
            $content['htmlHeadStrings'] = (array)$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...
420
            $content['metas'] = (array)$this->metas;
421
            $content['xoops_pagetitle'] = $this->template->getTemplateVars('xoops_pagetitle');
422
            $content['header'] = $header;
423
            $cache->write($this->contentCacheId, $content);
424
        }
425
426
        //  @internal : Lame fix to ensure the metas specified in the xoops config page don't appear twice
427
        $old = array('robots', 'keywords', 'description', 'rating', 'author', 'copyright');
428
        foreach ($this->metas['meta'] as $name => $value) {
429
            if (in_array($name, $old)) {
430
                $this->template->assign("xoops_meta_$name", htmlspecialchars($value, ENT_QUOTES));
431
                unset($this->metas['meta'][$name]);
432
            }
433
        }
434
435
        // We assume no overlap between $GLOBALS['xoopsOption']['xoops_module_header'] and
436
        // $this->template->getTemplateVars( 'xoops_module_header' ) ?
437
        $this->template->assign('xoops_module_header', $this->renderMetas(true) . "\n" . $header);
438
439
        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...
440
            $this->canvasTemplate = $canvasTpl;
441
        }
442
        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...
443
            $this->contentTemplate = $contentTpl;
444
        }
445
        if (!empty($vars)) {
446
            $this->template->assign($vars);
447
        }
448
        if ($this->contentTemplate) {
449
            $this->content = $this->template->fetch($this->contentTemplate, $this->contentCacheId);
450
        }
451
        if ($this->bufferOutput) {
452
            $this->content .= ob_get_contents();
453
            ob_end_clean();
454
        }
455
456
        $this->template->assignByRef('xoops_contents', $this->content);
457
458
        // Do not cache the main (theme.tpl) template output
459
        $this->template->caching = 0;
460
        if (false === (bool)($xoops->getConfig('disable_theme_shortcodes'))) {
461
            $this->template->loadFilter('output', 'shortcodes');
462
        }
463
        $this->template->display($this->path . '/' . $this->canvasTemplate);
464
        $this->renderCount++;
465
        $xoops->events()->triggerEvent('core.theme.render.end', array($this));
466
        return true;
467
    }
468
469
    /**
470
     * Load localization information
471
     * Folder structure for localization:
472
     * themes/themefolder/english
473
     *    - main.php - language definitions
474
     *    - style.css - localization stylesheet
475
     *    - script.js - localization script
476
     *
477
     * @param string $type language domain (unused?)
478
     *
479
     * @return array list of 2 arrays, one
480
     */
481 4
    public function getLocalizationAssets($type = "main")
0 ignored issues
show
Unused Code introduced by
The parameter $type 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...
482
    {
483 4
        $cssAssets = array();
484 4
        $jsAssets = array();
485
486 4
        $xoops = \Xoops::getInstance();
487
488 4
        \Xoops\Locale::loadThemeLocale($this);
489
490 4
        $language = \XoopsLocale::getLocale();
491
        // Load global localization stylesheet if available
492 4
        if (\XoopsLoad::fileExists($xoops->path('locale/' . $language . '/style.css'))) {
493
            $cssAssets[] = $xoops->path('locale/' . $language . '/style.css');
494
        }
495
        //$this->addLanguage($type);
496
        // Load theme localization stylesheet and scripts if available
497 4 View Code Duplication
        if (\XoopsLoad::fileExists($this->path . '/locale/' . $language . '/script.js')) {
498
            $jsAssets[] = $this->url . '/locale/' . $language . '/script.js';
499
        }
500 4 View Code Duplication
        if (\XoopsLoad::fileExists($this->path . '/locale/' . $language . '/style.css')) {
501
            $cssAssets[] = $this->path . '/locale/' . $language . '/style.css';
502
        }
503 4
        return array($cssAssets, $jsAssets);
504
    }
505
506
    /**
507
     * Load theme specific language constants
508
     *
509
     * @param string $type     language type, like 'main', 'admin'; Needs to be declared in theme xo-info.php
510
     * @param string $language specific language
511
     *
512
     * @return bool|mixed
513
     */
514
    /*
515
    public function addLanguage($type = "main", $language = null)
516
    {
517
        $xoops = \Xoops::getInstance();
518
        $language = is_null($language) ? $xoops->getConfig('locale') : $language;
519
        if (!XoopsLoad::fileExists($file = $xoops->path($this->resourcePath("/locale/{$language}/{$type}.php")))) {
520
            if (!XoopsLoad::fileExists($file = $xoops->path($this->resourcePath("/locale/en_US/{$type}.php")))) {
521
                return false;
522
            }
523
        }
524
        $ret = include_once $file;
525
        return $ret;
526
    }*/
527
528
    /**
529
     * *#@+
530
     * @tasktype 20 Manipulating page meta-information
531
     */
532
    /**
533
     * Adds script code to the document head
534
     * This methods allows the insertion of an external script file (if $src is provided), or
535
     * of a script snippet. The file URI is parsed to take benefit of the theme resource
536
     * overloading system.
537
     * The $attributes parameter allows you to specify the attributes that will be added to the
538
     * inserted <script> tag. If unspecified, the <var>type</var> attribute value will default to
539
     * 'text/javascript'.
540
     * <code>
541
     * // Add an external script using a physical path
542
     * $theme->addScript( 'www/script.js', null, '' );
543
     * $theme->addScript( 'modules/newbb/script.js', null, '' );
544
     * // Specify attributes for the <script> tag
545
     * $theme->addScript( 'mod_xoops_SiteManager#common.js', array( 'type' => 'application/x-javascript' ), '' );
546
     * // Insert a code snippet
547
     * $theme->addScript( null, array( 'type' => 'application/x-javascript' ), 'window.open("Hello world");' );
548
     * </code>
549
     *
550
     * @param string $src        path to an external script file
551
     * @param array  $attributes hash of attributes to add to the <script> tag
552
     * @param string $content    Code snippet to output within the <script> tag
553
     *
554
     * @return void
555
     */
556 View Code Duplication
    public function addScript($src = '', $attributes = array(), $content = '')
557
    {
558
        $xoops = \Xoops::getInstance();
559
        if (empty($attributes)) {
560
            $attributes = array();
561
        }
562
        if (!empty($src)) {
563
            $src = $xoops->url($this->resourcePath($src));
564
            $attributes['src'] = $src;
565
        }
566
        if (!empty($content)) {
567
            $attributes['_'] = $content;
568
        }
569
        if (!isset($attributes['type'])) {
570
            $attributes['type'] = 'text/javascript';
571
        }
572
        $this->addMeta('script', $src, $attributes);
573
    }
574
575
    /**
576
     * Add StyleSheet or CSS code to the document head
577
     *
578
     * @param string|null $src        path to .css file
579
     * @param array|null  $attributes name => value paired array of attributes such as title
580
     * @param string      $content    CSS code to output between the <style> tags (in case $src is empty)
581
     *
582
     * @return void
583
     */
584 1 View Code Duplication
    public function addStylesheet($src = '', $attributes = array(), $content = '')
585
    {
586 1
        $xoops = \Xoops::getInstance();
587 1
        if (empty($attributes)) {
588 1
            $attributes = array();
589
        }
590 1
        if (!empty($src)) {
591 1
            $src = $xoops->url($this->resourcePath($src));
592 1
            $attributes['href'] = $src;
593
        }
594 1
        if (!isset($attributes['type'])) {
595 1
            $attributes['type'] = 'text/css';
596
        }
597 1
        if (!empty($content)) {
598
            $attributes['_'] = $content;
599
        }
600 1
        $this->addMeta('stylesheet', $src, $attributes);
601 1
    }
602
603
    /**
604
     * addScriptAssets - add a list of scripts to the page
605
     *
606
     * @param array  $assets  list of source files to process
607
     * @param string $filters comma separated list of filters
608
     * @param string $target  target path, will default to assets directory
609
     *
610
     * @return void
611
     */
612
    public function addScriptAssets($assets, $filters = 'default', $target = null)
613
    {
614
        $url = $this->assets->getUrlToAssets('js', $assets, $filters, $target);
615
        $this->addScript($url);
616
    }
617
618
    /**
619
     * addStylesheetAssets - add a list of stylesheets to the page
620
     *
621
     * @param string[] $assets  list of source files to process
622
     * @param string   $filters comma separated list of filters
623
     * @param string   $target  target path, will default to assets directory
624
     *
625
     * @return void
626
     */
627
    public function addStylesheetAssets($assets, $filters = 'default', $target = null)
628
    {
629
        $url = $this->assets->getUrlToAssets('css', $assets, $filters, $target);
630
        $this->addStylesheet($url);
631
    }
632
633
    /**
634
     * addBaseAssets - add a list of assets to the page, these will all
635
     * be combined into a single asset file at render time
636
     *
637
     * @param string $type   type of asset, i.e. 'css' or 'js'
638
     * @param array  $assets list of source files to process
639
     *
640
     * @return void
641
     */
642 4
    public function addBaseAssets($type, $assets)
643
    {
644 4
        if (is_scalar($assets)) {
645 4
            $this->baseAssets[$type][]=$assets;
646 1
        } elseif (is_array($assets)) {
647 1
            $this->baseAssets[$type] = array_merge($this->baseAssets[$type], $assets);
648
        }
649 4
    }
650
651
    /**
652
     * addBaseScriptAssets - add a list of scripts to the page
653
     *
654
     * @param array $assets list of source files to process
655
     *
656
     * @return void
657
     */
658 4
    public function addBaseScriptAssets($assets)
659
    {
660 4
        $this->addBaseAssets('js', $assets);
661 4
    }
662
663
    /**
664
     * addBaseStylesheetAssets - add a list of stylesheets to the page
665
     *
666
     * @param array $assets list of source files to process
667
     *
668
     * @return void
669
     */
670 1
    public function addBaseStylesheetAssets($assets)
671
    {
672 1
        $this->addBaseAssets('css', $assets);
673 1
    }
674
675
    /**
676
     * setNamedAsset - Add an asset reference to the asset manager.
677
     * The specified asset will be added to the asset manager with the specified
678
     * name. As an example:
679
     *
680
     *   $theme->setNamedAsset('aacss','module/aa/assets/css/*.css');
681
     *
682
     * This will create an asset reference which can be added using other asset
683
     * functions, such as:
684
     *
685
     *   $theme->addBaseStylesheetAssets('@aacss');
686
     *
687
     * Additional custom filters can be specified for the named asset if needed.
688
     *
689
     * @param string $name    the name of the reference to be added
690
     * @param mixed  $assets  a string asset path, or an array of asset paths, may include wildcard
691
     * @param string $filters comma separated list of filters
692
     *
693
     * @return boolean true if asset registers, false on error
694
     */
695 1
    public function setNamedAsset($name, $assets, $filters = null)
696
    {
697 1
        return $this->assets->registerAssetReference($name, $assets, $filters);
698
    }
699
700
    /**
701
     * Add a <link> to the header
702
     *
703
     * @param string $rel        Relationship from the current doc to the anchored one
704
     * @param string $href       URI of the anchored document
705
     * @param array  $attributes Additional attributes to add to the <link> element
706
     *
707
     * @return void
708
     */
709
    public function addLink($rel, $href = '', $attributes = array())
710
    {
711
        if (empty($attributes)) {
712
            $attributes = array();
713
        }
714
        if (!empty($href)) {
715
            $attributes['href'] = $href;
716
        }
717
        $attributes['rel'] = $rel;
718
        $this->addMeta('link', '', $attributes);
719
    }
720
721
    /**
722
     * Set a meta http-equiv value
723
     *
724
     * @param string $name  meta tag name
725
     * @param null   $value meta tag value
726
     *
727
     * @return string|false
728
     */
729
    public function addHttpMeta($name, $value = null)
730
    {
731
        if (isset($value)) {
732
            return $this->addMeta('http', $name, $value);
733
        }
734
        unset($this->metas['http'][$name]);
735
        return false;
736
    }
737
738
    /**
739
     * Change output page meta-information
740
     *
741
     * @param string $type  type
742
     * @param string $name  name
743
     * @param string $value value
744
     *
745
     * @return string
746
     */
747 5
    public function addMeta($type = 'meta', $name = '', $value = '')
748
    {
749 5
        if (!isset($this->metas[$type])) {
750
            $this->metas[$type] = array();
751
        }
752 5
        if (!empty($name)) {
753 5
            $this->metas[$type][$name] = $value;
754
        } else {
755
            $this->metas[$type][md5(serialize(array($value)))] = $value;
756
        }
757 5
        return $value;
758
    }
759
760
    /**
761
     * XoopsTheme::headContent()
762
     *
763
     * @param mixed  $params  unused
764
     * @param string $content content
765
     * @param mixed  $smarty  unused
766
     * @param bool   $repeat  repeat
767
     *
768
     * @return void
769
     */
770
    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...
771
    {
772
        if (!$repeat) {
773
            $this->htmlHeadStrings[] = $content;
774
        }
775
    }
776
777
    /**
778
     * XoopsTheme::renderMetas()
779
     *
780
     * @param bool $return true to return as string, false to echo
781
     *
782
     * @return bool|string
783
     */
784
    public function renderMetas($return = false)
785
    {
786
        $str = $this->renderBaseAssets();
787
788
        foreach (array_keys($this->metas) as $type) {
789
            $str .= $this->renderMetasByType($type);
790
        }
791
        $str .= implode("\n", $this->htmlHeadStrings);
792
793
        if ($return) {
794
            return $str;
795
        }
796
        echo $str;
797
        return true;
798
    }
799
800
    /**
801
     * render base assets
802
     *
803
     * @return string
804
     */
805 1
    public function renderBaseAssets()
806
    {
807 1
        $str = '';
808
809 1 View Code Duplication
        if (!empty($this->baseAssets['js'])) {
810 1
            $url = $this->assets->getUrlToAssets('js', $this->baseAssets['js']);
811 1
            if (!empty($url)) {
812 1
                $str .= '<script src="' . $url . '" type="text/javascript"></script>'."\n";
813
            }
814
        }
815
816 1 View Code Duplication
        if (!empty($this->baseAssets['css'])) {
817
            $url = $this->assets->getUrlToAssets('css', $this->baseAssets['css']);
818
            if (!empty($url)) {
819
                $str .= '<link rel="stylesheet" href="' . $url . '" type="text/css" />'."\n";
820
            }
821
        }
822 1
        return $str;
823
    }
824
825
    /**
826
     * XoopsTheme::renderMetasByType() render the specified metadata type
827
     *
828
     * @param string $type type to render
829
     *
830
     * @return string
831
     */
832
    public function renderMetasByType($type)
833
    {
834
        if (!isset($type)) {
835
            return '';
836
        }
837
838
        $str = '';
839
        switch ($type) {
840 View Code Duplication
            case 'script':
841
                foreach ($this->metas[$type] as $attrs) {
842
                    $str .= "<script" . $this->renderAttributes($attrs) . ">";
843
                    if (@$attrs['_']) {
844
                        $str .= "\n//<![CDATA[\n" . $attrs['_'] . "\n//]]>";
845
                    }
846
                    $str .= "</script>\n";
847
                }
848
                break;
849
            case 'link':
850
                foreach ($this->metas[$type] as $attrs) {
851
                    $rel = $attrs['rel'];
852
                    unset($attrs['rel']);
853
                    $str .= '<link rel="' . $rel . '"' . $this->renderAttributes($attrs) . " />\n";
854
                }
855
                break;
856 View Code Duplication
            case 'stylesheet':
857
                foreach ($this->metas[$type] as $attrs) {
858
                    if (@$attrs['_']) {
859
                        $str .= '<style' . $this->renderAttributes($attrs)
860
                            . ">\n/* <![CDATA[ */\n" . $attrs['_'] . "\n/* //]]> */\n</style>";
861
                    } else {
862
                        $str .= '<link rel="stylesheet"' . $this->renderAttributes($attrs) . " />\n";
863
                    }
864
                }
865
                break;
866 View Code Duplication
            case 'http':
867
                foreach ($this->metas[$type] as $name => $content) {
868
                    $str .= '<meta http-equiv="' . htmlspecialchars($name, ENT_QUOTES) . '" content="'
869
                        . htmlspecialchars($content, ENT_QUOTES) . "\" />\n";
870
                }
871
                break;
872 View Code Duplication
            default:
873
                foreach ($this->metas[$type] as $name => $content) {
874
                    $str .= '<meta name="' . htmlspecialchars($name, ENT_QUOTES) . '" content="'
875
                        . htmlspecialchars($content, ENT_QUOTES) . "\" />\n";
876
                }
877
                break;
878
        }
879
880
        return $str;
881
    }
882
883
    /**
884
     * Generates a unique element ID
885
     *
886
     * @param string $tagName tag
887
     *
888
     * @return string
889
     */
890
    public function genElementId($tagName = 'xos')
891
    {
892
        static $cache = array();
893
        if (!isset($cache[$tagName])) {
894
            $cache[$tagName] = 1;
895
        }
896
        return $tagName . '-' . $cache[$tagName]++;
897
    }
898
899
    /**
900
     * Transform an attributes collection to an XML string
901
     *
902
     * @param array $coll collection of attributes
903
     *
904
     * @return string
905
     */
906
    public function renderAttributes($coll)
907
    {
908
        $str = '';
909
        foreach ($coll as $name => $val) {
910
            if ($name !== '_') {
911
                $str .= ' ' . $name . '="' . htmlspecialchars($val, ENT_QUOTES) . '"';
912
            }
913
        }
914
        return $str;
915
    }
916
917
    /**
918
     * Return a themable file resource path
919
     *
920
     * @param string $path file path
921
     *
922
     * @return string
923
     */
924 5
    public function resourcePath($path)
925
    {
926 5
        if (substr($path, 0, 1) === '/') {
927
            $path = substr($path, 1);
928
        }
929 5
        $xoops_root_path = \XoopsBaseConfig::get('root-path');
930
//\Xoops::getInstance()->events()->triggerEvent('debug.log', $this);
931 5
        if (\XoopsLoad::fileExists($xoops_root_path . "/{$this->themesPath}/{$this->folderName}/{$path}")) {
932
//\Xoops::getInstance()->events()->triggerEvent('debug.log', "custom theme path {$this->themesPath}/{$this->folderName}/{$path}");
933 4
            return "{$this->themesPath}/{$this->folderName}/{$path}";
934
        }
935
936 5
        if (\XoopsLoad::fileExists($xoops_root_path . "/themes/{$this->folderName}/{$path}")) {
937
//\Xoops::getInstance()->events()->triggerEvent('debug.log', "main theme folder themes/{$this->folderName}/{$path}");
938
            return "themes/{$this->folderName}/{$path}";
939
        }
940
//\Xoops::getInstance()->events()->triggerEvent('debug.log', "drop thru {$path}");
941 5
        return $path;
942
    }
943
}
944