Filesystem   C
last analyzed

Complexity

Total Complexity 57

Size/Duplication

Total Lines 435
Duplicated Lines 0 %

Test Coverage

Coverage 95.33%

Importance

Changes 0
Metric Value
eloc 83
dl 0
loc 435
ccs 102
cts 107
cp 0.9533
rs 5.04
c 0
b 0
f 0
wmc 57

29 Methods

Rating   Name   Duplication   Size   Complexity  
A cleanDirectory() 0 3 1
A windowsOs() 0 3 1
A append() 0 3 1
A get() 0 7 3
A hash() 0 3 1
A exists() 0 3 1
A chmod() 0 7 2
A name() 0 3 1
A sharedGet() 0 21 4
A isFile() 0 3 1
A moveDirectory() 0 7 4
A makeDirectory() 0 7 2
A move() 0 3 1
B copyDirectory() 0 31 8
A prepend() 0 7 2
A isWritable() 0 3 1
A dirname() 0 3 1
A deleteDirectory() 0 21 6
A isDirectory() 0 3 1
A mimeType() 0 3 1
A put() 0 3 2
A lastModified() 0 3 1
A copy() 0 3 1
A extension() 0 3 1
A type() 0 3 1
A delete() 0 17 5
A size() 0 3 1
A basename() 0 3 1
A isReadable() 0 3 1

How to fix   Complexity   

Complex Class

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

1
<?php
2
3
namespace Yiranzai\File;
4
5
use FilesystemIterator;
6
7
class Filesystem
8
{
9
10
    /**
11
     * Get the MD5 hash of the file at the given path.
12
     *
13
     * @param  string $path
14
     * @return string
15
     */
16 3
    public function hash($path): string
17
    {
18 3
        return md5_file($path);
19
    }
20
21
    /**
22
     * Prepend to a file.
23
     *
24
     * @param  string $path
25
     * @param  string $data
26
     * @return int
27
     */
28 3
    public function prepend($path, $data): int
29
    {
30 3
        if ($this->exists($path)) {
31 3
            return $this->put($path, $data . $this->get($path));
32
        }
33
34 3
        return $this->put($path, $data);
35
    }
36
37
    /**
38
     * Determine if a file or directory exists.
39
     *
40
     * @param  string $path
41
     * @return bool
42
     */
43 21
    public function exists($path): bool
44
    {
45 21
        return file_exists($path);
46
    }
47
48
    /**
49
     * Write the contents of a file.
50
     *
51
     * @param  string $path
52
     * @param  string $contents
53
     * @param  bool   $lock
54
     * @return int
55
     */
56 12
    public function put($path, $contents, $lock = false): int
57
    {
58 12
        return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
59
    }
60
61
    /**
62
     * Get the contents of a file.
63
     *
64
     * @param  string $path
65
     * @param  bool   $lock
66
     * @return string
67
     */
68 15
    public function get($path, $lock = false): string
69
    {
70 15
        if ($this->isFile($path)) {
71 12
            return $lock ? $this->sharedGet($path) : file_get_contents($path);
72
        }
73
74 3
        throw new \RuntimeException("File does not exist at path {$path}");
75
    }
76
77
    /**
78
     * Determine if the given path is a file.
79
     *
80
     * @param  string $file
81
     * @return bool
82
     */
83 15
    public function isFile($file): bool
84
    {
85 15
        return is_file($file);
86
    }
87
88
    /**
89
     * Get contents of a file with shared access.
90
     *
91
     * @param  string $path
92
     * @return string
93
     */
94 3
    public function sharedGet($path): string
95
    {
96 3
        $contents = '';
97
98 3
        $handle = fopen($path, 'rb');
99
100 3
        if ($handle !== false) {
101
            try {
102 3
                if (flock($handle, LOCK_SH)) {
103 3
                    clearstatcache(true, $path);
104
105 3
                    $contents = fread($handle, $this->size($path) ?: 1);
106
107 3
                    flock($handle, LOCK_UN);
108
                }
109 3
            } finally {
110 3
                fclose($handle);
111
            }
112
        }
113
114 3
        return $contents;
115
    }
116
117
    /**
118
     * Get the file size of a given file.
119
     *
120
     * @param  string $path
121
     * @return int
122
     */
123 3
    public function size($path): int
124
    {
125 3
        return filesize($path);
126
    }
127
128
    /**
129
     * Append to a file.
130
     *
131
     * @param  string $path
132
     * @param  string $data
133
     * @return int
134
     */
135 3
    public function append($path, $data): int
136
    {
137 3
        return file_put_contents($path, $data, FILE_APPEND);
138
    }
139
140
    /**
141
     * Get or set UNIX mode of a file or directory.
142
     *
143
     * @param  string $path
144
     * @param  int    $mode
145
     * @return mixed
146
     */
147 9
    public function chmod($path, $mode = null)
148
    {
149 9
        if ($mode !== null) {
150 9
            return chmod($path, $mode);
151
        }
152
153 3
        return substr(sprintf('%o', fileperms($path)), -4);
154
    }
155
156
    /**
157
     * Move a file to a new location.
158
     *
159
     * @param  string $path
160
     * @param  string $target
161
     * @return bool
162
     */
163 3
    public function move($path, $target): bool
164
    {
165 3
        return rename($path, $target);
166
    }
167
168
    /**
169
     * Extract the file name from a file path.
170
     *
171
     * @param  string $path
172
     * @return string
173
     */
174 3
    public function name($path): string
175
    {
176 3
        return pathinfo($path, PATHINFO_FILENAME);
177
    }
178
179
    /**
180
     * Extract the trailing name component from a file path.
181
     *
182
     * @param  string $path
183
     * @return string
184
     */
185 3
    public function basename($path): string
186
    {
187 3
        return pathinfo($path, PATHINFO_BASENAME);
188
    }
189
190
    /**
191
     * Extract the parent directory from a file path.
192
     *
193
     * @param  string $path
194
     * @return string
195
     */
196 3
    public function dirname($path): string
197
    {
198 3
        return pathinfo($path, PATHINFO_DIRNAME);
199
    }
200
201
    /**
202
     * Extract the file extension from a file path.
203
     *
204
     * @param  string $path
205
     * @return string
206
     */
207 3
    public function extension($path): string
208
    {
209 3
        return pathinfo($path, PATHINFO_EXTENSION);
210
    }
211
212
    /**
213
     * Get the file type of a given file.
214
     *
215
     * @param  string $path
216
     * @return string
217
     */
218 3
    public function type($path): string
219
    {
220 3
        return filetype($path);
221
    }
222
223
    /**
224
     * Get the mime-type of a given file.
225
     *
226
     * @param  string $path
227
     * @return string|false
228
     */
229 3
    public function mimeType($path)
230
    {
231 3
        return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
232
    }
233
234
    /**
235
     * Get the file's last modification time.
236
     *
237
     * @param  string $path
238
     * @return int
239
     */
240 3
    public function lastModified($path): int
241
    {
242 3
        return filemtime($path);
243
    }
244
245
    /**
246
     * Determine if the given path is readable.
247
     *
248
     * @param  string $path
249
     * @return bool
250
     */
251 9
    public function isReadable($path): bool
252
    {
253 9
        return is_readable($path);
254
    }
255
256
    /**
257
     * Determine if the given path is writable.
258
     *
259
     * @param  string $path
260
     * @return bool
261
     */
262 9
    public function isWritable($path): bool
263
    {
264 9
        return is_writable($path);
265
    }
266
267
    /**
268
     * Move a directory.
269
     *
270
     * @param  string $from
271
     * @param  string $to
272
     * @param  bool   $overwrite
273
     * @return bool
274
     */
275 6
    public function moveDirectory($from, $to, $overwrite = false): bool
276
    {
277 6
        if ($overwrite && $this->isDirectory($to) && !$this->deleteDirectory($to)) {
278
            return false;
279
        }
280
281 6
        return @rename($from, $to) === true;
282
    }
283
284
    /**
285
     * Determine if the given path is a directory.
286
     *
287
     * @param  string $directory
288
     * @return bool
289
     */
290 15
    public function isDirectory($directory): bool
291
    {
292 15
        return is_dir($directory);
293
    }
294
295
    /**
296
     * Recursively delete a directory.
297
     *
298
     * The directory itself may be optionally preserved.
299
     *
300
     * @param  string $directory
301
     * @param  bool   $preserve
302
     * @return bool
303
     */
304 15
    public function deleteDirectory($directory, $preserve = false): bool
305
    {
306 15
        if (!$this->isDirectory($directory)) {
307 3
            return false;
308
        }
309
310 15
        $items = new FilesystemIterator($directory);
311
312 15
        foreach ($items as $item) {
313 12
            if ($item->isDir() && !$item->isLink()) {
314 12
                $this->deleteDirectory($item->getPathname());
315
            } else {
316 10
                $this->delete($item->getPathname());
317
            }
318
        }
319
320 15
        if (!$preserve) {
321 15
            /** @scrutinizer ignore-unhandled */ @rmdir($directory);
322
        }
323
324 15
        return true;
325
    }
326
327
    /**
328
     * Delete the file at a given path.
329
     *
330
     * @param  string|array $paths
331
     * @return bool
332
     */
333 12
    public function delete($paths): bool
334
    {
335 12
        $paths = is_array($paths) ? $paths : func_get_args();
336
337 12
        $success = true;
338
339 12
        foreach ($paths as $path) {
340
            try {
341 12
                if (!@unlink($path)) {
342 12
                    $success = false;
343
                }
344
            } catch (\Exception $e) {
345 8
                $success = false;
346
            }
347
        }
348
349 12
        return $success;
350
    }
351
352
    /**
353
     * Copy a directory from one location to another.
354
     *
355
     * @param  string $directory
356
     * @param  string $destination
357
     * @param  int    $options
358
     * @return bool
359
     */
360 6
    public function copyDirectory($directory, $destination, $options = null): bool
361
    {
362 6
        if (!$this->isDirectory($directory)) {
363
            return false;
364
        }
365
366 6
        $options = $options ?: FilesystemIterator::SKIP_DOTS;
367
368 6
        if (!$this->isDirectory($destination)) {
369 6
            $this->makeDirectory($destination, 0777, true);
370
        }
371
372 6
        $items = new FilesystemIterator($directory, $options);
373
374 6
        foreach ($items as $item) {
375 3
            $target = $destination . '/' . $item->getBasename();
376
377 3
            if (!$item->isDir()) {
378
                if (!$this->copy($item->getPathname(), $target)) {
379
                    return false;
380
                }
381
            } else {
382 3
                $path = $item->getPathname();
383
384 3
                if (!$this->copyDirectory($path, $target, $options)) {
385 2
                    return false;
386
                }
387
            }
388
        }
389
390 6
        return true;
391
    }
392
393
    /**
394
     * Create a directory.
395
     *
396
     * @param  string $path
397
     * @param  int    $mode
398
     * @param  bool   $recursive
399
     * @param  bool   $force
400
     * @return bool
401
     */
402 18
    public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false): bool
403
    {
404 18
        if ($force) {
405 15
            return @mkdir($path, $mode, $recursive);
406
        }
407
408 6
        return mkdir($path, $mode, $recursive);
409
    }
410
411
    /**
412
     * Copy a file to a new location.
413
     *
414
     * @param  string $path
415
     * @param  string $target
416
     * @return bool
417
     */
418 3
    public function copy($path, $target): bool
419
    {
420 3
        return copy($path, $target);
421
    }
422
423
    /**
424
     * Empty the specified directory of all files and folders.
425
     *
426
     * @param  string $directory
427
     * @return bool
428
     */
429 3
    public function cleanDirectory($directory): bool
430
    {
431 3
        return $this->deleteDirectory($directory, true);
432
    }
433
434
    /**
435
     * Determine whether the current environment is Windows based.
436
     *
437
     * @return bool
438
     */
439 3
    public function windowsOs(): bool
440
    {
441 3
        return stripos(PHP_OS, 'win') === 0;
442
    }
443
}
444