DauxHelper   F
last analyzed

Complexity

Total Complexity 61

Size/Duplication

Total Lines 401
Duplicated Lines 0 %

Test Coverage

Coverage 57.14%

Importance

Changes 10
Bugs 2 Features 0
Metric Value
eloc 152
dl 0
loc 401
ccs 84
cts 147
cp 0.5714
rs 3.52
c 10
b 2
f 0
wmc 61

13 Methods

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