Util   B
last analyzed

Coupling/Cohesion

Components 1
Dependencies 2

Complexity

Total Complexity 47

Size/Duplication

Total Lines 345
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 47
lcom 1
cbo 2
dl 0
loc 345
ccs 112
cts 112
cp 1
rs 8.439
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A dirname() 0 4 1
A map() 0 14 3
A pathinfo() 0 14 2
A normalizeDirname() 0 4 2
A normalizePath() 0 4 1
B normalizeRelativePath() 0 30 6
A removeFunkyWhiteSpace() 0 9 2
A normalizePrefix() 0 4 1
A contentSize() 0 4 2
A guessMimeType() 0 10 3
A ensureConfig() 0 16 4
A rewindStream() 0 6 3
A isSeekableStream() 0 6 1
A getStreamSize() 0 6 1
C emulateObjectDirectories() 0 25 7
B basename() 0 28 5
A emulateDirectories() 0 21 3

How to fix   Complexity   

Complex Class

Complex classes like Util 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 Util, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace League\Flysystem;
4
5
use League\Flysystem\Util\MimeType;
6
use LogicException;
7
8
class Util
9
{
10
    /**
11
     * Get normalized pathinfo.
12
     *
13
     * @param string $path
14
     *
15
     * @return array pathinfo
16
     */
17 129
    public static function pathinfo($path)
18
    {
19 129
        $pathinfo = compact('path');
20
21 129
        if ('' !== $dirname = dirname($path)) {
22 126
            $pathinfo['dirname'] = static::normalizeDirname($dirname);
23 84
        }
24
25 129
        $pathinfo['basename'] = static::basename($path);
0 ignored issues
show
Bug introduced by Chris Leppanen
Since basename() is declared private, calling it with static will lead to errors in possible sub-classes. You can either use self, or increase the visibility of basename() to at least protected.

Let’s assume you have a class which uses late-static binding:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
}

public static function getSomeVariable()
{
    return static::getTemperature();
}

}

The code above will run fine in your PHP runtime. However, if you now create a sub-class and call the getSomeVariable() on that sub-class, you will receive a runtime error:

class YourSubClass extends YourClass {
      private static function getTemperature() {
        return "-182 °C";
    }
}

print YourSubClass::getSomeVariable(); // Will cause an access error.

In the case above, it makes sense to update SomeClass to use self instead:

class YourClass
{
    private static function getTemperature() {
        return "3422 °C";
    }

    public static function getSomeVariable()
    {
        return self::getTemperature();
    }
}
Loading history...
26
27 129
        $pathinfo += pathinfo($pathinfo['basename']);
28
29 129
        return $pathinfo;
30
    }
31
32
    /**
33
     * Normalize a dirname return value.
34
     *
35
     * @param string $dirname
36
     *
37
     * @return string normalized dirname
38
     */
39 150
    public static function normalizeDirname($dirname)
40
    {
41 150
        return $dirname === '.' ? '' : $dirname;
42
    }
43
44
    /**
45
     * Get a normalized dirname from a path.
46
     *
47
     * @param string $path
48
     *
49
     * @return string dirname
50
     */
51 33
    public static function dirname($path)
52
    {
53 33
        return static::normalizeDirname(dirname($path));
54
    }
55
56
    /**
57
     * Map result arrays.
58
     *
59
     * @param array $object
60
     * @param array $map
61
     *
62
     * @return array mapped result
63
     */
64 6
    public static function map(array $object, array $map)
65
    {
66 6
        $result = [];
67
68 6
        foreach ($map as $from => $to) {
69 6
            if ( ! isset($object[$from])) {
70 3
                continue;
71
            }
72
73 6
            $result[$to] = $object[$from];
74 4
        }
75
76 6
        return $result;
77
    }
78
79
    /**
80
     * Normalize path.
81
     *
82
     * @param string $path
83
     *
84
     * @throws LogicException
85
     *
86
     * @return string
87
     */
88 285
    public static function normalizePath($path)
89
    {
90 285
        return static::normalizeRelativePath($path);
91
    }
92
93
    /**
94
     * Normalize relative directories in a path.
95
     *
96
     * @param string $path
97
     *
98
     * @throws LogicException
99
     *
100
     * @return string
101
     */
102 285
    public static function normalizeRelativePath($path)
103
    {
104 285
        $path = str_replace('\\', '/', $path);
105 285
        $path = static::removeFunkyWhiteSpace($path);
106
107 285
        $parts = [];
108
109 285
        foreach (explode('/', $path) as $part) {
110
            switch ($part) {
111 285
                case '':
112 283
                case '.':
113 66
                break;
114
115 276
            case '..':
116 30
                if (empty($parts)) {
117 15
                    throw new LogicException(
118 15
                        'Path is outside of the defined root, path: [' . $path . ']'
119 10
                    );
120
                }
121 27
                array_pop($parts);
122 27
                break;
123
124 182
            default:
125 273
                $parts[] = $part;
126 276
                break;
127 182
            }
128 188
        }
129
130 270
        return implode('/', $parts);
131
    }
132
133
    /**
134
     * Removes unprintable characters and invalid unicode characters.
135
     *
136
     * @param string $path
137
     *
138
     * @return string $path
139
     */
140 285
    protected static function removeFunkyWhiteSpace($path) {
141
        // We do this check in a loop, since removing invalid unicode characters
142
        // can lead to new characters being created.
143 285
        while (preg_match('#\p{C}+|^\./#u', $path)) {
144 6
            $path = preg_replace('#\p{C}+|^\./#u', '', $path);
145 4
        }
146
147 285
        return $path;
148
    }
149
150
    /**
151
     * Normalize prefix.
152
     *
153
     * @param string $prefix
154
     * @param string $separator
155
     *
156
     * @return string normalized path
157
     */
158 3
    public static function normalizePrefix($prefix, $separator)
159
    {
160 3
        return rtrim($prefix, $separator) . $separator;
161
    }
162
163
    /**
164
     * Get content size.
165
     *
166
     * @param string $contents
167
     *
168
     * @return int content size
169
     */
170 3
    public static function contentSize($contents)
171
    {
172 3
        return defined('MB_OVERLOAD_STRING') ? mb_strlen($contents, '8bit') : strlen($contents);
173
    }
174
175
    /**
176
     * Guess MIME Type based on the path of the file and it's content.
177
     *
178
     * @param string $path
179
     * @param string|resource $content
180
     *
181
     * @return string|null MIME Type or NULL if no extension detected
182
     */
183 27
    public static function guessMimeType($path, $content)
184
    {
185 27
        $mimeType = MimeType::detectByContent($content);
186
187 27
        if ( ! (empty($mimeType) || in_array($mimeType, ['application/x-empty', 'text/plain', 'text/x-asm']))) {
188 3
            return $mimeType;
189
        }
190
191 24
        return MimeType::detectByFilename($path);
192
    }
193
194
    /**
195
     * Emulate directories.
196
     *
197
     * @param array $listing
198
     *
199
     * @return array listing with emulated directories
200
     */
201 3
    public static function emulateDirectories(array $listing)
202
    {
203 3
        $directories = [];
204 3
        $listedDirectories = [];
205
206 3
        foreach ($listing as $object) {
207 3
            list($directories, $listedDirectories) = static::emulateObjectDirectories(
208 3
                $object,
209 3
                $directories,
210 1
                $listedDirectories
211 2
            );
212 2
        }
213
214 3
        $directories = array_diff(array_unique($directories), array_unique($listedDirectories));
215
216 3
        foreach ($directories as $directory) {
217 3
            $listing[] = static::pathinfo($directory) + ['type' => 'dir'];
218 2
        }
219
220 3
        return $listing;
221
    }
222
223
    /**
224
     * Ensure a Config instance.
225
     *
226
     * @param null|array|Config $config
227
     *
228
     * @return Config config instance
229
     *
230
     * @throw  LogicException
231
     */
232 147
    public static function ensureConfig($config)
233
    {
234 147
        if ($config === null) {
235 3
            return new Config();
236
        }
237
238 147
        if ($config instanceof Config) {
239 144
            return $config;
240
        }
241
242 6
        if (is_array($config)) {
243 3
            return new Config($config);
244
        }
245
246 3
        throw new LogicException('A config should either be an array or a Flysystem\Config object.');
247
    }
248
249
    /**
250
     * Rewind a stream.
251
     *
252
     * @param resource $resource
253
     */
254 39
    public static function rewindStream($resource)
255
    {
256 39
        if (ftell($resource) !== 0 && static::isSeekableStream($resource)) {
257 21
            rewind($resource);
258 14
        }
259 39
    }
260
261 21
    public static function isSeekableStream($resource)
262
    {
263 21
        $metadata = stream_get_meta_data($resource);
264
265 21
        return $metadata['seekable'];
266
    }
267
268
    /**
269
     * Get the size of a stream.
270
     *
271
     * @param resource $resource
272
     *
273
     * @return int stream size
274
     */
275 3
    public static function getStreamSize($resource)
276
    {
277 3
        $stat = fstat($resource);
278
279 3
        return $stat['size'];
280
    }
281
282
    /**
283
     * Emulate the directories of a single object.
284
     *
285
     * @param array $object
286
     * @param array $directories
287
     * @param array $listedDirectories
288
     *
289
     * @return array
290
     */
291 3
    protected static function emulateObjectDirectories(array $object, array $directories, array $listedDirectories)
292
    {
293 3
        if ($object['type'] === 'dir') {
294 3
            $listedDirectories[] = $object['path'];
295 2
        }
296
297 3
        if (empty($object['dirname'])) {
298 3
            return [$directories, $listedDirectories];
299
        }
300
301 3
        $parent = $object['dirname'];
302
303 3
        while ( ! empty($parent) && ! in_array($parent, $directories)) {
304 3
            $directories[] = $parent;
305 3
            $parent = static::dirname($parent);
306 2
        }
307
308 3
        if (isset($object['type']) && $object['type'] === 'dir') {
309 3
            $listedDirectories[] = $object['path'];
310
311 3
            return [$directories, $listedDirectories];
312
        }
313
314 3
        return [$directories, $listedDirectories];
315
    }
316
317
    /**
318
     * Returns the trailing name component of the path.
319
     *
320
     * @param string $path
321
     *
322
     * @return string
323
     */
324 129
    private static function basename($path)
325
    {
326 129
        $separators = DIRECTORY_SEPARATOR === '/' ? '/' : '\/';
327
328 129
        $path = rtrim($path, $separators);
329
330 129
        $basename = preg_replace('#.*?([^' . preg_quote($separators, '#') . ']+$)#', '$1', $path);
331
332 129
        if (DIRECTORY_SEPARATOR === '/') {
333 129
            return $basename;
334
        }
335
        // @codeCoverageIgnoreStart
336
        // Extra Windows path munging. This is tested via AppVeyor, but code
337
        // coverage is not reported.
338
339
        // Handle relative paths with drive letters. c:file.txt.
340
        while (preg_match('#^[a-zA-Z]{1}:[^\\\/]#', $basename)) {
341
            $basename = substr($basename, 2);
342
        }
343
344
        // Remove colon for standalone drive letter names.
345
        if (preg_match('#^[a-zA-Z]{1}:$#', $basename)) {
346
            $basename = rtrim($basename, ':');
347
        }
348
349
        return $basename;
350
        // @codeCoverageIgnoreEnd
351
    }
352
}
353