Completed
Push — master ( 91ecad...693adf )
by Michael
02:48
created

File   C

Complexity

Total Complexity 56

Size/Duplication

Total Lines 420
Duplicated Lines 19.76 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 100%

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 56
c 1
b 0
f 1
lcom 1
cbo 1
dl 83
loc 420
ccs 116
cts 116
cp 1
rs 6.5957

26 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 8 2
A __toString() 0 4 1
A getPath() 0 4 1
A getDirectory() 0 4 1
A getName() 0 4 1
A exists() 0 4 1
A canExecute() 0 4 1
A canRead() 0 4 1
A canWrite() 0 4 1
A isFile() 0 4 1
A isDirectory() 0 4 1
A count() 10 10 3
A lastModified() 10 10 3
A listAllIterator() 0 21 4
A listAll() 13 13 2
A listDirectories() 15 15 3
A listFiles() 15 15 3
A makeFile() 0 9 3
A makeDirectory() 0 15 2
B move() 0 19 5
A rename() 0 4 1
A removeDirectory() 0 15 4
A removeFile() 0 10 2
A read() 0 12 3
A append() 10 10 3
A write() 10 10 3

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

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

1
<?php
2
3
/**
4
 * This file is part of the miBadger package.
5
 *
6
 * @author Michael Webbers <[email protected]>
7
 * @license http://opensource.org/licenses/Apache-2.0 Apache v2 License
8
 * @version 1.0.0
9
 */
10
11
namespace miBadger\File;
12
13
/**
14
 * The file class.
15
 *
16
 * @since 1.0.0
17
 */
18
class File implements \Countable
19
{
20
	const DIRECTORY_SEPARATOR = \DIRECTORY_SEPARATOR;
21
22
	/** @var string the file path. */
23
	private $path;
24
25
	/**
26
	 * Constructs a File object with the given path.
27
	 *
28
	 * @param string $path
29
	 */
30 35
	public function __construct($path)
31
	{
32 35
		if (substr($path, -1) === static::DIRECTORY_SEPARATOR) {
33 1
			$this->path = substr($path, 0, -1);
34 1
		} else {
35 35
			$this->path = $path;
36
		}
37 35
	}
38
39
	/**
40
	 * Returns the string representation of the File object.
41
	 *
42
	 * @return string the string representation of the File object.
43
	 */
44 2
	public function __toString()
45
	{
46 2
		return $this->getPath();
47
	}
48
49
	/**
50
	 * Returns the path of the file.
51
	 *
52
	 * @return string the path of the file.
53
	 */
54 5
	public function getPath()
55
	{
56 5
		return $this->path;
57
	}
58
59
	/**
60
	 * Returns the parent directory of the file.
61
	 *
62
	 * @return string the parent directory of the file.
63
	 */
64 2
	public function getDirectory()
65
	{
66 2
		return dirname($this->path);
67
	}
68
69
	/**
70
	 * Returns the name of the file.
71
	 *
72
	 * @return string the name of the file.
73
	 */
74 1
	public function getName()
75
	{
76 1
		return basename($this->path);
77
	}
78
79
	/**
80
	 * Returns true if the file exists.
81
	 *
82
	 * @return bool true if the file exists.
83
	 */
84 7
	public function exists()
85
	{
86 7
		return file_exists($this->path);
87
	}
88
89
	/**
90
	 * Returns true if you can execute the file.
91
	 *
92
	 * @return bool true if you can execute the file.
93
	 */
94 1
	public function canExecute()
95
	{
96 1
		return is_executable($this->path);
97
	}
98
99
	/**
100
	 * Returns true if you can read the file.
101
	 *
102
	 * @return bool true if you can read the file.
103
	 */
104 1
	public function canRead()
105
	{
106 1
		return is_readable($this->path);
107
	}
108
109
	/**
110
	 * Returns true if you can write the file.
111
	 *
112
	 * @return bool true if you can write the file.
113
	 */
114 1
	public function canWrite()
115
	{
116 1
		return is_writeable($this->path);
117
	}
118
119
	/**
120
	 * Returns true if the file is a file.
121
	 *
122
	 * @return bool true if the file is a file.
123
	 */
124 2
	public function isFile()
125
	{
126 2
		return is_file($this->path);
127
	}
128
129
	/**
130
	 * Returns true if the file is a directory.
131
	 *
132
	 * @return bool true if the file is a directory.
133
	 */
134 5
	public function isDirectory()
135
	{
136 5
		return is_dir($this->path);
137
	}
138
139
	/**
140
	 * Returns the numer of bytes in the file, or -1 on failure.
141
	 *
142
	 * @return int the number of bytes in the file, or -1 on failure.
143
	 */
144 1 View Code Duplication
	public function count()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
145
	{
146
		// Check if the file exists
147 1
		if (!$this->exists()) {
148 1
			return -1;
149
		}
150
151
		// Return length
152 1
		return ($result = filesize($this->path)) !== false ? $result : -1;
153
	}
154
155
	/**
156
	 * Returns the time of the last modification as a unixtimestap, or -1 on failure.
157
	 *
158
	 * @return int the time of the last modification as a unixtimestap, or -1 on failure.
159
	 */
160 1 View Code Duplication
	public function lastModified()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
161
	{
162
		// Check if the file exists
163 1
		if (!$this->exists()) {
164 1
			return -1;
165
		}
166
167
		// Return last modified timestamp
168 1
		return ($result = filemtime($this->path)) !== false ? $result : -1;
169
	}
170
171
	/**
172
	 * Returns an iterator with the files and directories in the current directory.
173
	 *
174
	 * @param bool $recursive = false
175
	 * @param bool $showHidden = false
176
	 * @return \ArrayIterator|\FilesystemIterator|\RecursiveIteratorIterator an iterator with the files and directories in the current directory.
177
	 */
178 4
	private function listAllIterator($recursive = false, $showHidden = false)
179
	{
180
		// Check file
181 4
		if (!$this->isDirectory()) {
182 4
			return new \ArrayIterator([]);
183
		}
184
185
		// Check flags
186 4
		$flags = \FilesystemIterator::KEY_AS_PATHNAME | \FilesystemIterator::CURRENT_AS_FILEINFO;
187
188 4
		if (!$showHidden) {
189 4
			$flags = $flags | \FilesystemIterator::SKIP_DOTS;
190 4
		}
191
192
		// Check recursive
193 4
		if ($recursive) {
194 1
			return new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->path, $flags), \RecursiveIteratorIterator::SELF_FIRST);
195
		}
196
197 3
		return new \FilesystemIterator($this->path, $flags);
198
	}
199
200
	/**
201
	 * Returns an array with the files and directories in the current directory.
202
	 *
203
	 * @param bool $recursive = false
204
	 * @param bool $showHidden = false
205
	 * @return string[] an array with the files and directories in the current directory.
206
	 */
207 2 View Code Duplication
	public function listAll($recursive = false, $showHidden = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
208
	{
209
		// Init
210 2
		$result = [];
211
212
		// List all
213 2
		foreach ($this->listAllIterator($recursive, $showHidden) as $element) {
214 2
			$result[] = $element->getFilename();
215 2
		}
216
217
		// Return all
218 2
		return $result;
219
	}
220
221
	/**
222
	 * Returns an array with the directories in the current directory.
223
	 *
224
	 * @param bool $recursive = false
225
	 * @param bool $showHidden = false
226
	 * @return string[] an array with the directories in the current directory.
227
	 */
228 1 View Code Duplication
	public function listDirectories($recursive = false, $showHidden = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
229
	{
230
		// Init
231 1
		$result = [];
232
233
		// List directories
234 1
		foreach ($this->listAllIterator($recursive, $showHidden) as $element) {
235 1
			if ($element->isDir()) {
236 1
				$result[] = $element->getFilename();
237 1
			}
238 1
		}
239
240
		// Return directories
241 1
		return $result;
242
	}
243
244
	/**
245
	 * Returns an array with the files in the current directory.
246
	 *
247
	 * @param bool $recursive = false
248
	 * @param bool $showHidden = false
249
	 * @return string[] an array with the files in the current directory.
250
	 */
251 1 View Code Duplication
	public function listFiles($recursive = false, $showHidden = false)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
252
	{
253
		// Init
254 1
		$result = [];
255
256
		// List files
257 1
		foreach ($this->listAllIterator($recursive, $showHidden) as $element) {
258 1
			if ($element->isFile()) {
259 1
				$result[] = $element->getFilename();
260 1
			}
261 1
		}
262
263
		// Return files
264 1
		return $result;
265
	}
266
267
	/**
268
	 * Returns true if the file has been created.
269
	 *
270
	 * @param bool $override = false
271
	 * @return bool true if the file has been created.
272
	 */
273 1
	public function makeFile($override = false)
274
	{
275
		// Check if the file exists
276 1
		if ($this->exists() && !$override) {
277 1
			return false;
278
		}
279
280 1
		return file_put_contents($this->path, '') !== false;
281
	}
282
283
	/**
284
	 * Returns true if the directory has been created.
285
	 *
286
	 * @param bool $recursive = false
287
	 * @param int $permissions = 0755
288
	 * @return bool true if the directory has been created.
289
	 */
290 1
	public function makeDirectory($recursive = false, $permissions = 0775)
291
	{
292
		// Check if the directory exists
293 1
		if ($this->exists()) {
294 1
			return false;
295
		}
296
297
		// Make directory
298 1
		$old = umask(0777 - $permissions);
299 1
		$result = mkdir($this->path, $permissions, $recursive);
300 1
		umask($old);
301
302
		// Return result
303 1
		return $result;
304
	}
305
306
	/**
307
	 * Returns true if the file is succesfully moved.
308
	 *
309
	 * @param string $path
310
	 * @param bool $override = false
311
	 * @return bool true if the file is succesfully moved.
312
	 */
313 2
	public function move($path, $override = false)
314
	{
315
		// Check if the old file exists
316 2
		if (!$this->exists()) {
317 2
			return false;
318
		}
319
320
		// Create file
321 2
		$file = new File($path);
322
323
		// Check if the new file exists
324 2
		if (($file->exists() && !$override) || !rename($this->path, $file->getPath())) {
325 1
			return false;
326
		}
327
328 2
		$this->path = $file->getPath();
329
330 2
		return true;
331
	}
332
333
	/**
334
	 * Returns true if the file is succesfully renamed.
335
	 *
336
	 * @param string $file
337
	 * @param bool $override = false
338
	 * @return bool true if the file is succesfully renamed.
339
	 */
340 1
	public function rename($file, $override = false)
341
	{
342 1
		return $this->move($this->getDirectory() . static::DIRECTORY_SEPARATOR . basename($file), $override);
343
	}
344
345
	/**
346
	 * Returns true if the directory is succesfully removed.
347
	 *
348
	 * @param bool $recursive = false
349
	 * @return bool true if the directory is succesfully removed.
350
	 */
351 1
	public function removeDirectory($recursive = false)
352
	{
353
		// Check if the directory has to be removed recursive
354 1
		if (!$recursive) {
355 1
			return rmdir($this->path);
356
		}
357
358
		// Loop trough the directory
359 1
		foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($this->path, \FilesystemIterator::SKIP_DOTS), \RecursiveIteratorIterator::CHILD_FIRST) as $path) {
360 1
			$path->isFile() ? unlink($path->getPathname()) : rmdir($path->getPathname());
361 1
		}
362
363
		// Return true
364 1
		return true;
365
	}
366
367
	/**
368
	 * Returns true if the file is succesfully removed.
369
	 *
370
	 * @return bool true if the file is succesfully removed.
371
	 */
372 1
	public function removeFile()
373
	{
374
		// Check if the file exists
375 1
		if (!$this->isFile()) {
376 1
			return false;
377
		}
378
379
		// Remove file
380 1
		return unlink($this->path);
381
	}
382
383
	/**
384
	 * Returns the content of the file.
385
	 *
386
	 * @return string the content of the file.
387
	 * @throws FileException on failure.
388
	 */
389 8
	public function read()
390
	{
391
		try {
392 8
			if (($result = file_get_contents($this->path)) === false) {
393 1
				throw new \Exception('Failed');
394
			}
395
396 5
			return $result;
397 3
		} catch (\Exception $e) {
398 3
			throw new FileException('Can\'t read the content.', $e->getCode(), $e);
399
		}
400
	}
401
402
	/**
403
	 * Append the given content.
404
	 *
405
	 * @param string $content
406
	 * @return null
407
	 * @throws FileException on failure.
408
	 */
409 4 View Code Duplication
	public function append($content)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
410
	{
411
		try {
412 4
			if (file_put_contents($this->path, $content, \FILE_APPEND) === false) {
413 1
				throw new \Exception('Failed');
414
			}
415 4
		} catch (\Exception $e) {
416 2
			throw new FileException('Can\'t append the given content.', $e->getCode(), $e);
417
		}
418 2
	}
419
420
	/**
421
	 * Write the given content.
422
	 *
423
	 * @param string $content
424
	 * @return null
425
	 * @throws FileException on failure.
426
	 */
427 4 View Code Duplication
	public function write($content)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
428
	{
429
		try {
430 4
			if (file_put_contents($this->path, $content) === false) {
431 1
				throw new \Exception('Failed');
432
			}
433 4
		} catch (\Exception $e) {
434 2
			throw new FileException('Can\'t write the given content.', $e->getCode(), $e);
435
		}
436 2
	}
437
}
438