Passed
Push — master ( b764bc...695d2d )
by Stéphane
23:13
created

DauxHelper   C

Complexity

Total Complexity 57

Size/Duplication

Total Lines 366
Duplicated Lines 0 %

Test Coverage

Coverage 43.3%

Importance

Changes 11
Bugs 2 Features 0
Metric Value
eloc 142
c 11
b 2
f 0
dl 0
loc 366
ccs 42
cts 97
cp 0.433
rs 5.04
wmc 57

13 Methods

Rating   Name   Duplication   Size   Complexity  
A rebaseConfiguration() 0 11 3
A getFilenames() 0 8 1
B getTheme() 0 64 11
A getCleanPath() 0 17 4
C getFile() 0 65 13
B resolveInternalFile() 0 30 7
A slug() 0 21 1
A getAbsolutePath() 0 6 2
A isAbsolutePath() 0 28 4
A isExternalUrl() 0 3 1
A isValidUrl() 0 3 2
A is() 0 2 2
A getRelativePath() 0 32 6

How to fix   Complexity   

Complex Class

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

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

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

1
<?php namespace Todaymade\Daux;
2
3
use Todaymade\Daux\Exception\LinkNotFoundException;
4
use Todaymade\Daux\Tree\Builder;
5
use Todaymade\Daux\Tree\Directory;
6
use Todaymade\Daux\Tree\Entry;
7
8
class DauxHelper
9
{
10
    /**
11
     * Set a new base_url for the configuration
12
     *
13
     * @param Config $config
14
     * @param string $base_url
15
     */
16
    public static function rebaseConfiguration(Config $config, $base_url)
17
    {
18
        // Avoid changing the url if it is already correct
19
        if ($config->getBaseUrl() == $base_url && !empty($config->getTheme())) {
20
            return;
21
        }
22
23
        // Change base url for all links on the pages
24
        $config['base_url'] = $base_url;
25
        $config['theme'] = static::getTheme($config, $base_url);
26
        $config['image'] = str_replace('<base_url>', $base_url, $config->getImage());
27
    }
28
29
    /**
30
     * @param Config $config
31
     * @param string $current_url
32
     * @return array
33
     */
34
    protected static function getTheme(Config $config, $current_url)
35
    {
36
        $htmlTheme = $config->getHTML()->getTheme();
37
38
        $theme_folder = $config->getThemesPath() . DIRECTORY_SEPARATOR . $htmlTheme;
39
        $theme_url = $config->getBaseUrl() . 'themes/' . $htmlTheme . '/';
40
41
        $theme = [];
42
        if (is_file($theme_folder . DIRECTORY_SEPARATOR . 'config.json')) {
43
            $theme = json_decode(file_get_contents($theme_folder . DIRECTORY_SEPARATOR . 'config.json'), true);
44
            if (!$theme) {
45
                $theme = [];
46
            }
47
        }
48
49
        //Default parameters for theme
50
        $theme += [
51
            'name' => $htmlTheme,
52
            'css' => [],
53
            'js' => [],
54
            'fonts' => [],
55
            'favicon' => '<base_url>themes/daux/img/favicon.png',
56
            'templates' => $theme_folder . DIRECTORY_SEPARATOR . 'templates',
57
            'variants' => [],
58
        ];
59
60
        if ($config->getHTML()->hasThemeVariant()) {
61
            $variant = $config->getHTML()->getThemeVariant();
62
            if (!array_key_exists($variant, $theme['variants'])) {
63
                throw new Exception("Variant '$variant' not found for theme '$theme[name]'");
64
            }
65
66
            // These will be replaced
67
            foreach (['templates', 'favicon'] as $element) {
68
                if (array_key_exists($element, $theme['variants'][$variant])) {
69
                    $theme[$element] = $theme['variants'][$variant][$element];
70
                }
71
            }
72
73
            // These will be merged
74
            foreach (['css', 'js', 'fonts'] as $element) {
75
                if (array_key_exists($element, $theme['variants'][$variant])) {
76
                    $theme[$element] = array_merge($theme[$element], $theme['variants'][$variant][$element]);
77
                }
78
            }
79
        }
80
81
        $substitutions = [
82
            '<local_base>' => $config->getLocalBase(),
83
            '<base_url>' => $current_url,
84
            '<theme_url>' => $theme_url,
85
        ];
86
87
        // Substitute some placeholders
88
        $theme['templates'] = strtr($theme['templates'], $substitutions);
89
        $theme['favicon'] = utf8_encode(strtr($theme['favicon'], $substitutions));
90
91
        foreach (['css', 'js', 'fonts'] as $element) {
92
            foreach ($theme[$element] as $key => $value) {
93
                $theme[$element][$key] = utf8_encode(strtr($value, $substitutions));
94
            }
95
        }
96
97
        return $theme;
98
    }
99
100
    /**
101
     * Remove all '/./' and '/../' in a path, without actually checking the path
102
     *
103
     * @param string $path
104
     * @return string
105
     */
106
    public static function getCleanPath($path)
107
    {
108
        $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path);
109
        $parts = array_filter(explode(DIRECTORY_SEPARATOR, $path), 'strlen');
110
        $absolutes = [];
111
        foreach ($parts as $part) {
112
            if ('.' == $part) {
113
                continue;
114
            }
115
            if ('..' == $part) {
116
                array_pop($absolutes);
117
            } else {
118
                $absolutes[] = $part;
119
            }
120
        }
121
122
        return implode(DIRECTORY_SEPARATOR, $absolutes);
123
    }
124
125
    /**
126
     * Get the possible output file names for a source file.
127
     *
128
     * @param Config $config
129
     * @param string $part
130
     * @return string[]
131
     */
132 16
    public static function getFilenames(Config $config, $part)
133
    {
134 16
        $extensions = implode('|', array_map('preg_quote', $config->getValidContentExtensions())) . '|html';
135
136 16
        $raw = preg_replace('/(.*)?\\.(' . $extensions . ')$/', '$1', $part);
137 16
        $raw = Builder::removeSortingInformations($raw);
138
139 16
        return ["$raw.html", $raw];
140
    }
141
142
    /**
143
     * Locate a file in the tree. Returns the file if found or false
144
     *
145
     * @param Directory $tree
146
     * @param string $request
147
     * @return Tree\Content|Tree\Raw|false
148
     */
149 17
    public static function getFile($tree, $request)
150
    {
151 17
        $request = explode('/', $request);
152 17
        foreach ($request as $node) {
153
            // If the element we're in currently is not a
154
            // directory, we failed to find the requested file
155 17
            if (!$tree instanceof Directory) {
156 1
                return false;
157
            }
158
159
            // Some relative paths may start with ./
160 17
            if ($node == '.') {
161 3
                continue;
162
            }
163
164 17
            if ($node == '..') {
165 2
                $tree = $tree->getParent();
166 2
                continue;
167
            }
168
169
            // if the node exists in the current request tree,
170
            // change the $tree variable to reference the new
171
            // node and proceed to the next url part
172 17
            if (isset($tree->getEntries()[$node])) {
173 17
                $tree = $tree->getEntries()[$node];
174 17
                continue;
175
            }
176
177
            // We try a second time by decoding the url
178 12
            $node = DauxHelper::slug(urldecode($node));
179 12
            if (isset($tree->getEntries()[$node])) {
180
                $tree = $tree->getEntries()[$node];
181
                continue;
182
            }
183
184
            // if the node doesn't exist, we can try
185
            // two variants of the requested file:
186
            // with and w/o the .html extension
187 12
            foreach (static::getFilenames($tree->getConfig(), $node) as $filename) {
188 12
                if (isset($tree->getEntries()[$filename])) {
189 12
                    $tree = $tree->getEntries()[$filename];
190 12
                    continue 2;
191
                }
192
            }
193
194
            // At this stage, we're in a directory, but no
195
            // sub-item matches, so the current node must
196
            // be an index page or we failed
197 3
            if ($node !== 'index' && $node !== 'index.html') {
198 3
                return false;
199
            }
200
201
            return $tree->getIndexPage();
202
        }
203
204
        // If the entry we found is not a directory, we're done
205 17
        if (!$tree instanceof Directory) {
206 17
            return $tree;
207
        }
208
209
        if ($index = $tree->getIndexPage()) {
210
            return $index;
211
        }
212
213
        return false;
214
    }
215
216
    /**
217
     * Generate a URL friendly "slug" from a given string.
218
     *
219
     * Taken from Stringy
220
     *
221
     * @param  string $title
222
     * @return string
223
     */
224 28
    public static function slug($title)
225
    {
226
        // Convert to ASCII
227 28
        $title = transliterator_transliterate("Any-Latin; NFD; [:Nonspacing Mark:] Remove; NFC;", $title);
228 28
        $title = iconv("utf-8", "ASCII//TRANSLIT//IGNORE", $title);
229
230
        // Remove unsupported characters
231
        $title = preg_replace('/[^\x20-\x7E]/u', '', $title);
232 28
233
        $separator = '_';
234 28
        // Convert all dashes into underscores
235
        $title = preg_replace('![' . preg_quote('-') . ']+!u', $separator, $title);
236 28
237
        // Remove all characters that are not valid in a URL: 
238
        // $-_.+!*'(), separator, letters, numbers, or whitespace.
239
        $title = preg_replace('![^-' . preg_quote($separator) . '\!\'\(\),\.\+\*\$\pL\pN\s]+!u', '', $title);
240 28
241
        // Replace all separator characters and whitespace by a single separator
242
        $title = preg_replace('![' . preg_quote($separator) . '\s]+!u', $separator, $title);
243 28
244
        return trim($title, $separator);
245 28
    }
246
247
    /**
248
     * @param string $from
249
     * @param string $to
250
     * @return string
251
     */
252
    public static function getRelativePath($from, $to)
253
    {
254
        // some compatibility fixes for Windows paths
255 28
        $from = is_dir($from) ? rtrim($from, '\/') . '/' : $from;
256
        $to = is_dir($to) ? rtrim($to, '\/') . '/' : $to;
257 28
        $from = str_replace('\\', '/', $from);
258
        $to = str_replace('\\', '/', $to);
259 28
260 28
        $from = explode('/', $from);
261
        $to = explode('/', $to);
262
        $relPath = $to;
263
264
        foreach ($from as $depth => $dir) {
265 1
            // find first non-matching dir
266
            if ($dir === $to[$depth]) {
267
                // ignore this directory
268
                array_shift($relPath);
269
            } else {
270
                // get number of remaining dirs to $from
271
                $remaining = count($from) - $depth;
272
                if ($remaining > 1) {
273
                    // add traversals up to first matching dir
274
                    $padLength = (count($relPath) + $remaining - 1) * -1;
275
                    $relPath = array_pad($relPath, $padLength, '..');
276
                    break;
277
                } else {
278
                    //$relPath[0] = './' . $relPath[0];
279
                }
280
            }
281
        }
282
283
        return implode('/', $relPath);
284
    }
285
286
    public static function isAbsolutePath($path)
287
    {
288
        if (!is_string($path)) {
289
            $mess = sprintf('String expected but was given %s', gettype($path));
290
            throw new \InvalidArgumentException($mess);
291
        }
292
293
        if (!ctype_print($path)) {
294
            $mess = 'Path can NOT have non-printable characters or be empty';
295
            throw new \DomainException($mess);
296
        }
297
298
        // Optional wrapper(s).
299
        $regExp = '%^(?<wrappers>(?:[[:print:]]{2,}://)*)';
300
301
        // Optional root prefix.
302
        $regExp .= '(?<root>(?:[[:alpha:]]:/|/)?)';
303
304
        // Actual path.
305
        $regExp .= '(?<path>(?:[[:print:]]*))$%';
306
307
        $parts = [];
308
        if (!preg_match($regExp, $path, $parts)) {
309
            $mess = sprintf('Path is NOT valid, was given %s', $path);
310
            throw new \DomainException($mess);
311
        }
312
313
        return '' !== $parts['root'];
314
    }
315
316
    public static function getAbsolutePath($path) {
317
        if (DauxHelper::isAbsolutePath($path)) {
318
            return $path;
319
        }
320
321
        return getcwd() . '/' . $path;
322
    }
323
324
    public static function is($path, $type) {
325
        return ($type == 'dir') ? is_dir($path) : file_exists($path);
326
    }
327
328
    /**
329
     * @param Config $config
330
     * @param string $url
331
     * @return Entry
332
     * @throws LinkNotFoundException
333
     */
334
    public static function resolveInternalFile($config, $url)
335
    {
336
        $triedAbsolute = false;
337
338
        // Legacy absolute paths could start with
339
        // "!" In this case we will try to find
340
        // the file starting at the root
341
        if ($url[0] == '!' || $url[0] == '/') {
342
            $url = ltrim($url, '!/');
343
344
            if ($file = DauxHelper::getFile($config->getTree(), $url)) {
345
                return $file;
346
            }
347
348
            $triedAbsolute = true;
349
        }
350
351
        // Seems it's not an absolute path or not found,
352
        // so we'll continue with the current folder
353
        if ($file = DauxHelper::getFile($config->getCurrentPage()->getParent(), $url)) {
354
            return $file;
355
        }
356
357
        // If we didn't already try it, we'll
358
        // do a pass starting at the root
359
        if (!$triedAbsolute && $file = DauxHelper::getFile($config->getTree(), $url)) {
360
            return $file;
361
        }
362
363
        throw new LinkNotFoundException("Could not locate file '$url'");
364
    }
365
366
    public static function isValidUrl($url)
367
    {
368
        return !empty($url) && $url[0] != '#';
369
    }
370
371
    public static function isExternalUrl($url)
372
    {
373
        return preg_match('#^(?:[a-z]+:)?//|^mailto:#', $url);
374
    }
375
}
376