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

Path::init()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 7
c 0
b 0
f 0
ccs 7
cts 7
cp 1
rs 10
cc 2
nc 2
nop 1
crap 2
1
<?php
2
namespace phootwork\file;
3
4
use phootwork\lang\ArrayObject;
5
use phootwork\lang\Text;
6
7
class Path {
8
	
9
	/** @var ArrayObject */
10
	private $segments;
11
	
12
	/** @var Text */
13
	private $pathname;
14
	
15
	/** @var string */
16
	private $dirname;
17
	
18
	/** @var string */
19
	private $filename;
20
	
21
	/** @var string */
22
	private $extension;
23
	
24
	
25 14
	public function __construct($pathname) {
26 14
		$this->init($pathname);
27 14
	}
28
29 14
	private function init($pathname) {
30 14
		$this->pathname = $pathname instanceof Text ? $pathname : new Text($pathname);
31 14
		$this->segments = $this->pathname->split('/');
32 14
		$this->extension = pathinfo($this->pathname, PATHINFO_EXTENSION);
33 14
		$this->filename = basename($this->pathname);
34 14
		$this->dirname = dirname($this->pathname);
35 14
	}
36
37
	/**
38
	 * Returns the extension
39
	 * 
40
	 * @return string the extension
41
	 */
42 2
	public function getExtension() {
43 2
		return $this->extension;
44
	}
45
	
46
	/**
47
	 * Returns the filename
48
	 *
49
	 * @return string the filename
50
	 */
51 1
	public function getFilename() {
52 1
		return $this->filename;
53
	}
54
	
55
	/**
56
	 * Gets the path without filename
57
	 *
58
	 * @return string
59
	 */
60 5
	public function getDirname() {
61 5
		return $this->dirname;
62
	}
63
	
64
	/**
65
	 * Gets the full pathname
66
	 *
67
	 * @return Text
68
	 */
69 4
	public function getPathname() {
70 4
		return $this->pathname;
71
	}
72
	
73
	/**
74
	 * Changes the extension of this path
75
	 * 
76
	 * @param string $extension the new extension
77
	 * @return $this
78
	 */
79 1
	public function setExtension($extension) {
80 1
		$pathinfo = pathinfo($this->pathname);
81
		
82 1
		$pathname = new Text($pathinfo['dirname']);
83 1
		if (!empty($pathinfo['dirname'])) {
84 1
			$pathname = $pathname->append('/');
85
		}
86
		
87 1
		$this->init($pathname
88 1
			->append($pathinfo['filename'])
89 1
			->append('.')
90 1
			->append($extension))
91
		;
92
93 1
		return $this;
94
	}
95
	
96
	/**
97
	 * Returns a path with the same segments as this path but with a 
98
	 * trailing separator added (if not already existent).
99
	 * 
100
	 * @return $this
101
	 */
102 3
	public function addTrailingSeparator() {
103 3
		if (!$this->hasTrailingSeparator()) {
104 3
			$this->pathname = $this->pathname->append('/');
105
		}
106 3
		return $this;
107
	}
108
109
	/**
110
	 * Returns the path obtained from the concatenation of the given path's 
111
	 * segments/string to the end of this path.
112
	 * 
113
	 * @param string|Text|Path $path
114
	 * @return Path
115
	 */
116 2
	public function append($path) {
117 2
		if ($path instanceof Path) {
118 1
			$path = $path->getPathname();
119
		}
120
		
121 2
		if (!$this->hasTrailingSeparator()) {
122 2
			$this->addTrailingSeparator();
123
		}
124
		
125 2
		return new Path($this->pathname->append($path));
126
	}
127
128
	/**
129
	 * Returns whether this path has a trailing separator.
130
	 * 
131
	 * @return boolean
132
	 */
133 5
	public function hasTrailingSeparator() {
134 5
		return $this->pathname->endsWith('/');
135
	}
136
	
137
	/**
138
	 * Returns whether this path is empty
139
	 * 
140
	 * @return boolean
141
	 */
142
	public function isEmpty() {
143
		return $this->pathname->isEmpty();
144
	}
145
	
146
	/**
147
	 * Returns whether this path is an absolute path.
148
	 * 
149
	 * @return boolean
150
	 */
151 1
	public function isAbsolute() {
152 1
		if (realpath($this->pathname->toString()) == $this->pathname->toString()) {
153 1
			return true;
154
		}
155
		
156 1
		if ($this->pathname->length() == 0 || $this->pathname->charAt(0) == '.') {
0 ignored issues
show
Deprecated Code introduced by
The method phootwork\lang\Text::charAt() has been deprecated with message: use <code>at()</code> method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
157 1
			return false;
158
		}
159
		
160
		// Windows allows absolute paths like this.
161 1
		if ($this->pathname->match('#^[a-zA-Z]:\\\\#')) {
162 1
			return true;
163
		}
164
165
		// A path starting with / or \ is absolute; anything else is relative.
166
		return $this->pathname->charAt(0) == '/' || $this->pathname->charAt(0) == '\\';
0 ignored issues
show
Deprecated Code introduced by
The method phootwork\lang\Text::charAt() has been deprecated with message: use <code>at()</code> method instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
167
	}
168
	
169
	/**
170
	 * Checks whether this path is the prefix of another path
171
	 * 
172
	 * @param Path $anotherPath
173
	 * @return boolean
174
	 */
175 1
	public function isPrefixOf(Path $anotherPath) {
176 1
		return $anotherPath->getPathname()->startsWith($this->pathname);
177
	}
178
179
	/**
180
	 * Returns the last segment of this path, or null if it does not have any segments.
181
	 * 
182
	 * @return Text
183
	 */
184 1
	public function lastSegment() {
185 1
		return new Text($this->segments[count($this->segments) - 1]);
186
	}
187
188
	/**
189
	 * Makes the path relative to another given path
190
	 * 
191
	 * @param Path $base
192
	 * @return Path the new relative path
193
	 */
194 2
	public function makeRelativeTo(Path $base) {
195 2
		$pathname = clone $this->pathname;
196 2
		return new Path($pathname->replace($base->removeTrailingSeparator()->getPathname(), ''));
197
	}
198
	
199
	/**
200
	 * Returns a count of the number of segments which match in this 
201
	 * path and the given path, comparing in increasing segment number order.
202
	 * 
203
	 * @param Path $anotherPath
204
	 * @return int
205
	 */
206 1
	public function matchingFirstSegments(Path $anotherPath) {
207 1
		$segments = $anotherPath->segments();
208 1
		$count = 0;
209 1
		foreach ($this->segments as $i => $segment) {
210 1
			if ($segment != $segments[$i]) {
211 1
				break;
212
			}
213 1
			$count++;
214
		}
215
		
216 1
		return $count;
217
	}
218
	
219
	/**
220
	 * Returns a new path which is the same as this path but with the file extension removed.
221
	 * 
222
	 * @return Path
223
	 */
224 1
	public function removeExtension() {
225 1
		return new Path($this->pathname->replace('.' . $this->getExtension(), ''));
226
	}
227
	
228
	/**
229
	 * Returns a copy of this path with the given number of segments removed from the beginning.
230
	 * 
231
	 * @param int $count
232
	 * @return Path
233
	 */
234 1
	public function removeFirstSegments($count) {
235 1
		$segments = new ArrayObject();
236 1
		for ($i = $count; $i < $this->segmentCount(); $i++) {
237 1
			$segments->push($this->segments[$i]);
238
		}
239 1
		return new Path($segments->join('/'));
240
	}
241
	
242
	/**
243
	 * Returns a copy of this path with the given number of segments removed from the end.
244
	 * 
245
	 * @param int $count
246
	 * @return Path
247
	 */
248 1
	public function removeLastSegments($count) {
249 1
		$segments = new ArrayObject();
250 1
		for ($i = 0; $i < $this->segmentCount() - $count; $i++) {
251 1
			$segments->push($this->segments[$i]);
252
		}
253 1
		return new Path($segments->join('/'));
254
	}
255
	
256
	/**
257
	 * Returns a copy of this path with the same segments as this path but with a trailing separator removed.
258
	 * 
259
	 * @return $this
260
	 */
261 3
	public function removeTrailingSeparator() {
262 3
		if ($this->hasTrailingSeparator()) {
263 1
			$this->pathname = $this->pathname->substring(0, -1);
264
		}
265 3
		return $this;
266
	}
267
	
268
	/**
269
	 * Returns the specified segment of this path, or null if the path does not have such a segment.
270
	 * 
271
	 * @param int $index
272
	 * @return string
273
	 */
274 1
	public function segment($index) {
275 1
		if (isset($this->segments[$index])) {
276 1
			return $this->segments[$index];
277
		}
278
279 1
		return null;
280
	}
281
	
282
	/**
283
	 * Returns the number of segments in this path.
284
	 * 
285
	 * @return int
286
	 */
287 1
	public function segmentCount() {
288 1
		return $this->segments->count();
289
	}
290
	
291
	/**
292
	 * Returns the segments in this path in order.
293
	 * 
294
	 * @return ArrayObject<string>
295
	 */
296 2
	public function segments() {
297 2
		return $this->segments;
298
	}
299
	
300
	/**
301
	 * Returns a FileDescriptor corresponding to this path.
302
	 * 
303
	 * @return FileDescriptor
304
	 */
305 2
	public function toFileDescriptor() {
306 2
		return new FileDescriptor($this->pathname);
307
	}
308
	
309
	/**
310
	 * Returns a string representation of this path
311
	 * 
312
	 * @return string A string representation of this path
313
	 */
314 9
	public function toString() {
315 9
		return $this->pathname->toString();
316
	}
317
	
318
	/**
319
	 * String representation as pathname
320
	 */
321 7
	public function __toString() {
322 7
		return $this->toString();
323
	}
324
	
325
	/**
326
	 * Returns a copy of this path truncated after the given number of segments.
327
	 * 
328
	 * @param int $count
329
	 * @return Path
330
	 */
331 1
	public function upToSegment($count) {
332 1
		$segments = new ArrayObject();
333 1
		for ($i = 0; $i < $count; $i++) {
334 1
			$segments->push($this->segments[$i]);
335
		}
336
337 1
		return new Path($segments->join('/'));
338
	}
339
	
340
	/**
341
	 * Checks whether both paths point to the same location
342
	 * 
343
	 * @param Path|string $anotherPath
344
	 * @return boolean true if the do, false if they don't
345
	 */
346 2
	public function equals($anotherPath) {
347 2
		$anotherPath = $anotherPath instanceof Path ? $anotherPath : new Path($anotherPath);
348
349
		// do something else, when path's are urls
350 2
		$regexp = '/^[a-zA-Z]+:\/\//';
351 2
		$thisUrl = $this->pathname->match($regexp);
352 2
		$anotherUrl = $anotherPath->getPathname()->match($regexp);
353
354 2
		if ($thisUrl ^ $anotherUrl) {
355 1
			return false;
356 2
		} else if ($thisUrl && $anotherUrl) {
357 1
			return $this->pathname->equals($anotherPath->getPathname());
358
		}
359
360 2
		return realpath($this->pathname->toString()) == realpath($anotherPath->toString());
361
	}
362
363
}
364