Completed
Push — psr2 ( c3cc6e...e9f4a0 )
by Andreas
08:59 queued 06:19
created

StyleUtils::__construct()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
nc 2
nop 3
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
1
<?php
2
3
namespace dokuwiki;
4
5
/**
6
 * Class StyleUtils
7
 *
8
 * Reads and applies the template's style.ini settings
9
 */
10
class StyleUtils
11
{
12
13
    /** @var string current template */
14
    protected $tpl;
15
    /** @var bool reinitialize styles config */
16
    protected $reinit;
17
    /** @var bool $preview preview mode */
18
    protected $preview;
19
    /** @var array default replacements to be merged with custom style configs */
20
    protected $defaultReplacements = array(
21
        '__text__' => "#000",
22
        '__background__' => "#fff",
23
        '__text_alt__' => "#999",
24
        '__background_alt__' => "#eee",
25
        '__text_neu__' => "#666",
26
        '__background_neu__' => "#ddd",
27
        '__border__' => "#ccc",
28
        '__highlight__' => "#ff9",
29
        '__link__' => "#00f",
30
    );
31
32
    /**
33
     * StyleUtils constructor.
34
     * @param string $tpl template name: if not passed as argument, the default value from $conf will be used
35
     * @param bool $preview
36
     * @param bool $reinit whether static style conf should be reinitialized
37
     */
38
    public function __construct($tpl = '', $preview = false, $reinit = false)
39
    {
40
        if (!$tpl) {
41
            global $conf;
42
            $tpl = $conf['conf'];
43
        }
44
        $this->tpl = $tpl;
45
        $this->reinit = $reinit;
46
        $this->preview = $preview;
47
    }
48
49
    /**
50
     * Load style ini contents
51
     *
52
     * Loads and merges style.ini files from template and config and prepares
53
     * the stylesheet modes
54
     *
55
     * @author Andreas Gohr <[email protected]>
56
     * @author Anna Dabrowska <[email protected]>
57
     *
58
     * @return array with keys 'stylesheets' and 'replacements'
59
     */
60
    public function cssStyleini()
61
    {
62
        static $combined = [];
63
        if (!empty($combined) && !$this->reinit) {
64
            return $combined;
65
        }
66
67
        global $conf;
68
        global $config_cascade;
69
        $stylesheets = array(); // mode, file => base
70
71
        // guaranteed placeholder => value
72
        $replacements = $this->defaultReplacements;
73
74
        // merge all styles from config cascade
75
        if (!is_array($config_cascade['styleini'])) {
76
            trigger_error('Missing config cascade for styleini', E_USER_WARNING);
77
        }
78
79
        // allow replacement overwrites in preview mode
80
        if ($this->preview) {
81
            $config_cascade['styleini']['local'][] = $conf['cachedir'] . '/preview.ini';
82
        }
83
84
        $combined['stylesheets'] = [];
85
        $combined['replacements'] = [];
86
87
        foreach (array('default', 'local', 'protected') as $config_group) {
88
            if (empty($config_cascade['styleini'][$config_group])) continue;
89
90
            // set proper server dirs
91
            $webbase = $this->getWebbase($config_group);
92
93
            foreach ($config_cascade['styleini'][$config_group] as $inifile) {
94
                // replace the placeholder with the name of the current template
95
                $inifile = str_replace('%TEMPLATE%', $this->tpl, $inifile);
96
97
                $incbase = dirname($inifile) . '/';
98
99
                if (file_exists($inifile)) {
100
                    $config = parse_ini_file($inifile, true);
101
102
                    if (is_array($config['stylesheets'])) {
103
                        foreach ($config['stylesheets'] as $inifile => $mode) {
104
                            // validate and include style files
105
                            $stylesheets = array_merge(
106
                                $stylesheets,
107
                                $this->getValidatedStyles($stylesheets, $inifile, $mode, $incbase, $webbase)
108
                            );
109
                            $combined['stylesheets'] = array_merge($combined['stylesheets'], $stylesheets);
110
                        }
111
                    }
112
113
                    if (is_array($config['replacements'])) {
114
                        $replacements = array_replace(
115
                            $replacements,
116
                            $this->cssFixreplacementurls($config['replacements'], $webbase)
117
                        );
118
                        $combined['replacements'] = array_merge($combined['replacements'], $replacements);
119
                    }
120
                }
121
            }
122
        }
123
124
        return $combined;
125
    }
126
127
    /**
128
     * Checks if configured style files exist and, if necessary, adjusts file extensions in config
129
     *
130
     * @param array $stylesheets
131
     * @param string $file
132
     * @param string $mode
133
     * @param string $incbase
134
     * @param string $webbase
135
     * @return mixed
136
     */
137
    protected function getValidatedStyles($stylesheets, $file, $mode, $incbase, $webbase)
138
    {
139
        global $conf;
140
        if (!file_exists($incbase . $file)) {
141
            list($extension, $basename) = array_map('strrev', explode('.', strrev($file), 2));
142
            $newExtension = $extension === 'css' ? 'less' : 'css';
143
            if (file_exists($incbase . $basename . '.' . $newExtension)) {
144
                $stylesheets[$mode][$incbase . $basename . '.' . $newExtension] = $webbase;
145
                if ($conf['allowdebug']) {
146
                    msg("Stylesheet $file not found, using $basename.$newExtension instead. " .
147
                        "Please contact developer of \"$this->tpl\" template.", 2);
148
                }
149
            } elseif ($conf['allowdebug']) {
150
                msg("Stylesheet $file not found, please contact the developer of \"$this->tpl\" template.", 2);
151
            }
152
        }
153
        $stylesheets[$mode][fullpath($incbase . $file)] = $webbase;
154
        return $stylesheets;
155
    }
156
157
    /**
158
     * Returns the web base path for the given level/group in config cascade.
159
     * Style resources are relative to the template directory for the main (default) styles
160
     * but relative to DOKU_BASE for everything else"
161
     *
162
     * @param string $config_group
163
     * @return string
164
     */
165
    protected function getWebbase($config_group)
166
    {
167
        if ($config_group === 'default') {
168
            return tpl_basedir($this->tpl);
169
        } else {
170
            return DOKU_BASE;
171
        }
172
    }
173
174
    /**
175
     * Amend paths used in replacement relative urls, refer FS#2879
176
     *
177
     * @author Chris Smith <[email protected]>
178
     *
179
     * @param array $replacements with key-value pairs
180
     * @param string $location
181
     * @return array
182
     */
183
    protected function cssFixreplacementurls($replacements, $location)
184
    {
185
        foreach ($replacements as $key => $value) {
186
            $replacements[$key] = preg_replace(
187
                '#(url\([ \'"]*)(?!/|data:|http://|https://| |\'|")#',
188
                '\\1' . $location,
189
                $value
190
            );
191
        }
192
        return $replacements;
193
    }
194
}
195