Completed
Pull Request — master (#3)
by Cristiano
01:29
created

FileOperationTrait::getExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 3
c 0
b 0
f 0
ccs 2
cts 2
cp 1
rs 10
cc 1
nc 1
nop 0
crap 1
1
<?php
2
namespace phootwork\file;
3
4
use \DateTime;
5
use phootwork\file\exception\FileException;
6
use phootwork\lang\Text;
7
8
trait FileOperationTrait {
9
	
10
	protected $pathname;
11
	
12
	/**
13
	 * Static instantiator
14
	 * 
15
	 * @param string $pathname
16
	 * @return static
17
	 */
18 1
	public static function create($pathname) {
19 1
		return new static($pathname);
20
	}
21
22 19
	protected function init($pathname) {
23 19
		$this->pathname = ''.$pathname; // "cast" to string
24 19
	}
25
26
	/**
27
	 * Returns the file extensions
28
	 * 
29
	 * @return string the file extension
30
	 */
31 1
	public function getExtension() {
32 1
		return pathinfo($this->pathname, PATHINFO_EXTENSION);
33
	}
34
35
	/**
36
	 * Returns the filename
37
	 * 
38
	 * @return string the filename
39
	 */
40 6
	public function getFilename() {
41 6
		return basename($this->pathname);
42
	}
43
	
44
	/**
45
	 * Gets the path without filename
46
	 * 
47
	 * @return string
48
	 */
49 8
	public function getDirname() {
50 8
		return dirname($this->pathname);
51
	}
52
	
53
	/**
54
	 * Gets the path to the file
55
	 * 
56
	 * @return Text
57
	 */
58 7
	public function getPathname() {
59 7
		return $this->pathname;
60
	}
61
	
62
	/**
63
	 * Converts the path into a path object
64
	 *
65
	 * @return Path
66
	 */
67 1
	public function toPath() {
68 1
		return new Path($this->pathname);
69
	}
70
	
71
	/**
72
	 * Gets last access time.
73
	 * 
74
	 * @return DateTime
75
	 */
76 1
	public function getLastAccessedAt() {
77 1
		$timestamp = fileatime($this->pathname);
78 1
		$time = new DateTime();
79 1
		$time->setTimestamp($timestamp);
80 1
		return $time;
81
	}
82
	
83
	/**
84
	 * Gets the created time.
85
	 *
86
	 * @return DateTime
87
	 */
88 1
	public function getCreatedAt() {
89 1
		$timestamp = filemtime($this->pathname);
90 1
		$time = new DateTime();
91 1
		$time->setTimestamp($timestamp);
92 1
		return $time;
93
	}
94
	
95
	/**
96
	 * Gets last modified time.
97
	 *
98
	 * @return DateTime
99
	 */
100
	public function getModifiedAt() {
101
		$timestamp = filemtime($this->pathname);
102
		$time = new DateTime();
103
		$time->setTimestamp($timestamp);
104
		return $time;
105
	}
106
	
107
	/**
108
	 * Gets file inode
109
	 * 
110
	 * @return int Returns the inode number of the file, or FALSE on failure. 
111
	 */
112
	public function getInode() {
113
		return fileinode($this->pathname);
114
	}
115
	
116
	/**
117
	 * Gets file group
118
	 * 
119
	 * @return int Returns the group ID, or FALSE if an error occurs.
120
	 */
121
	public function getGroup() {
122
		return filegroup($this->pathname);
123
	}
124
	
125
	/**
126
	 * Gets file owner
127
	 *
128
	 * @return int Returns the user ID of the owner, or FALSE on failure.
129
	 */
130
	public function getOwner() {
131
		return fileowner($this->pathname);
132
	}
133
	
134
	/**
135
	 * Gets file permissions
136
	 * 
137
	 * @return int Returns the file's permissions as a numeric mode. Lower bits of this 
138
	 * 		mode are the same as the permissions expected by chmod(), however on most platforms 
139
	 * 		the return value will also include information on the type of file given as filename. 
140
	 * 		The examples below demonstrate how to test the return value for specific permissions 
141
	 * 		and file types on POSIX systems, including Linux and Mac OS X. 
142
	 */
143
	public function getPermissions() {
144
		return fileperms($this->pathname);
145
	}
146
	
147
	/**
148
	 * Checks its existance
149
	 *
150
	 * @return boolean Returns TRUE if exists; FALSE otherwise. Will return FALSE for symlinks
151
	 * 		pointing to non-existing files.
152
	 */
153 16
	public function exists() {
154 16
		return file_exists($this->pathname);
155
	}
156
	
157
	/**
158
	 * Tells whether is executable
159
	 *
160
	 * @return boolean Returns TRUE if exists and is executable.
161
	 */
162
	public function isExecutable() {
163
		return is_executable($this->pathname);
164
	}
165
	
166
	/**
167
	 * Tells whether is readable
168
	 *
169
	 * @return boolean Returns TRUE if exists and is readable.
170
	 */
171 3
	public function isReadable() {
172 3
		return is_readable($this->pathname);
173
	}
174
	
175
	/**
176
	 * Tells whether is writable
177
	 * 
178
	 * @return boolean Returns TRUE if exists and is writable. 
179
	 */
180
	public function isWritable() {
181
		return is_writable($this->pathname);
182
	}
183
184
	/**
185
	 * Tells whether the filename is a symbolic link
186
	 *
187
	 * @return boolean Returns TRUE if the filename exists and is a symbolic link, FALSE otherwise.
188
	 */
189 4
	public function isLink() {
190 4
		return is_link($this->pathname);
191
	}
192
	
193
	/**
194
	 * Returns the target if this is a symbolic link
195
	 * 
196
	 * @see #isLink
197
	 * @return Path|null The target path or null if this isn't a link
198
	 */
199 1
	public function getLinkTarget() {
200 1
		if ($this->isLink()) {
201 1
			return new Path(readlink($this->pathname));
202
		}
203 1
		return null;
204
	}
205
	
206
	/**
207
	 * Attempts to change the group.
208
	 *
209
	 * Only the superuser may change the group arbitrarily; other users may
210
	 * change the group of a file to any group of which that user is a member.
211
	 *
212
	 * @param mixed $group A group name or number.
213
	 * @return boolean Returns TRUE on success or FALSE on failure.
214
	 */
215
	public function setGroup($group) {
216
		if ($this->isLink()) {
217
			return lchgrp($this->pathname, $group);
218
		} else {
219
			return chgrp($this->pathname, $group);
220
		}
221
	}
222
	
223
	/**
224
	 * Attempts to change the mode.
225
	 *
226
	 * @see #setGroup
227
	 * @see #setOwner
228
	 *
229
	 * @param int $mode
230
	 * 		Note that mode is not automatically assumed to be an octal value, so strings
231
	 * 		(such as "g+w") will not work properly. To ensure the expected operation, you
232
	 * 		need to prefix mode with a zero (0).
233
	 *
234
	 * @return boolean Returns TRUE on success or FALSE on failure.
235
	 */
236 3
	public function setMode($mode) {
237 3
		if ($this->isLink()) {
238
			return lchmod($this->pathname, $mode);
239
		} else {
240 3
			return chmod($this->pathname, $mode);
241
		}
242
	}
243
	
244
	/**
245
	 * Changes file owner
246
	 *
247
	 * Attempts to change the owner. Only the superuser may change the owner of a file.
248
	 *
249
	 * @param mixed $user A user name or number.
250
	 * @return boolean Returns TRUE on success or FALSE on failure.
251
	 */
252
	public function setOwner($user) {
253
		if ($this->isLink()) {
254
			return lchown($this->pathname, $user);
255
		} else {
256
			return chown($this->pathname, $user);
257
		}
258
	}
259
	
260
	/**
261
	 * Copies the file
262
	 *
263
	 * If the destination file already exists, it will be overwritten.
264
	 *
265
	 * @throws FileException When an error appeared.
266
	 * @param string|Path $destination The destination path.
267
	 */
268 2
	public function copy($destination) {
269 2
		$destination = $this->getDestination($destination);
0 ignored issues
show
Bug introduced by
It seems like $destination defined by $this->getDestination($destination) on line 269 can also be of type object<phootwork\file\Path>; however, phootwork\file\FileOpera...Trait::getDestination() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
270
	
271 2
		if (!@copy($this->getPathname(), $destination)) {
272 1
			throw new FileException(sprintf('Failed to copy %s to %s', $this->pathname, $destination));
273
		}
274 1
	}
275
	
276
	/**
277
	 * Moves the file
278
	 *
279
	 * @throws FileException When an error appeared.
280
	 * @param string|Path $destination
281
	 */
282 2
	public function move($destination) {
283 2
		$destination = $this->getDestination($destination);
0 ignored issues
show
Bug introduced by
It seems like $destination defined by $this->getDestination($destination) on line 283 can also be of type object<phootwork\file\Path>; however, phootwork\file\FileOpera...Trait::getDestination() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
284
285 2
		if (@rename($this->getPathname(), $destination)) {
286 1
			$this->pathname = $destination;
287
		} else {
288 1
			throw new FileException(sprintf('Failed to move %s to %s', $this->pathname, $destination));
289
		}
290 1
	}
291
	
292
	/**
293
	 * Transforms destination into path and ensures, parent directory exists
294
	 * 
295
	 * @param string $destination
296
	 * @return Path
297
	 */
298 4
	private function getDestination($destination) {
299 4
		$destination = $destination instanceof Path ? $destination : new Path($destination);
300 4
		$targetDir = new Directory($destination->getDirname());
301 4
		$targetDir->make();
302 4
		return $destination;
303
	}
304
	
305
	/**
306
	 * Creates a symlink to the given destination
307
	 * 
308
	 * @param string|Path $destination
309
	 */
310 1
	public function linkTo($destination) {
311 1
		$target = new FileDescriptor($destination); 
312 1
		$targetDir = new Directory($target->getDirname());
313 1
		$targetDir->make();
314
		
315 1
		$ok = false;
316 1
		if ($target->isLink()) {
317
			if (!$target->getLinkTarget()->equals($this->pathname)) {
318
				$target->delete();
319
			} else {
320
				$ok = true;
321
			}
322
		}
323
324 1
		if (!$ok && @symlink($this->pathname, $target->getPathname()) !== true) {
325
			$report = error_get_last();
326
			if (is_array($report) && DIRECTORY_SEPARATOR === '\\' && strpos($report['message'], 'error code(1314)') !== false) {
327
				throw new FileException('Unable to create symlink due to error code 1314: \'A required privilege is not held by the client\'. Do you have the required Administrator-rights?');
328
			}
329
			throw new FileException(sprintf('Failed to create symbolic link from %s to %s', $this->pathname, $targetDir));
330
		}
331 1
	}
332
333
	public abstract function delete();
334
335
}