95% of 785OPs |
97% of 123Lines |
87% of 109Branches |
53% of 64Paths |
# | |
---|---|
1 |
<?php |
2 |
|
3 |
namespace mageekguy\atoum\fs; |
4 |
|
5 |
use |
6 |
mageekguy\atoum, |
7 |
mageekguy\atoum\fs\path\exception |
8 |
; |
9 |
|
10 |
class path |
11 |
{ |
12 |
protected $drive = ''; |
13 |
protected $components = ''; |
14 |
protected $directorySeparator = DIRECTORY_SEPARATOR; |
15 |
|
16 |
public function __construct($value, $directorySeparator = null)100% |
17 |
{ |
18 |
$this |
19 |
->setDriveAndComponents($value) |
20 |
->directorySeparator = (string) $directorySeparator ?: DIRECTORY_SEPARATOR |
21 |
; |
22 |
} |
23 |
|
24 |
public function __toString()100% |
25 |
{ |
26 |
$components = $this->components; |
27 |
|
28 |
if ($this->directorySeparator === '\\') |
29 |
{ |
30 |
$components = str_replace('/', '\\', $components); |
31 |
} |
32 |
|
33 |
return $this->drive . $components; |
34 |
} |
35 |
|
36 |
public function getDirectorySeparator()100% |
37 |
{ |
38 |
return $this->directorySeparator; |
39 |
} |
40 |
|
41 |
public function relativizeFrom(path $reference)90% |
42 |
{ |
43 |
$this->resolve(); |
44 |
|
45 |
$resolvedReferencePath = $reference->getResolvedPath(); |
46 |
|
47 |
switch (true) |
48 |
{ |
49 |
case $this->components === '/': |
50 |
$this->components = '.' . $this->components; |
51 |
break; |
52 |
|
53 |
case $this->components === $resolvedReferencePath->components: |
54 |
$this->components = '.'; |
55 |
break; |
56 |
|
57 |
case $this->isSubPathOf($resolvedReferencePath): |
58 |
$this->components = './' . ltrim(substr($this->components, strlen($resolvedReferencePath->components)), '/'); |
59 |
break; |
60 |
|
61 |
default: |
62 |
$relativePath = ''; |
63 |
|
64 |
while ($this->isNotSubPathOf($resolvedReferencePath)) |
65 |
{ |
66 |
$relativePath .= '../'; |
67 |
|
68 |
$resolvedReferencePath = $resolvedReferencePath->getParentDirectoryPath(); |
69 |
} |
70 |
|
71 |
$this->components = static::getComponents($relativePath) . '/' . ltrim(substr($this->components, strlen($resolvedReferencePath->components)), '/'); |
72 |
} |
73 |
|
74 |
return $this; |
75 |
} |
76 |
|
77 |
public function exists()100% |
78 |
{ |
79 |
return (file_exists((string) $this) === true); |
80 |
} |
81 |
|
82 |
public function resolve()95% |
83 |
{ |
84 |
if ($this->isAbsolute() === false) |
85 |
{ |
86 |
$this->absolutize(); |
87 |
} |
88 |
|
89 |
$components = array(); |
90 |
|
91 |
foreach (explode('/', ltrim($this->components, '/')) as $component) |
92 |
{ |
93 |
switch ($component) |
94 |
{ |
95 |
case '.': |
96 |
break; |
97 |
|
98 |
case '..': |
99 |
if (sizeof($components) <= 0) |
100 |
{ |
101 |
throw new exception('Unable to resolve path \'' . $this . '\''); |
102 |
} |
103 |
|
104 |
array_pop($components); |
105 |
break; |
106 |
|
107 |
default: |
108 |
$components[] = $component; |
109 |
} |
110 |
} |
111 |
|
112 |
$this->components = '/' . join('/', $components); |
113 |
|
114 |
return $this; |
115 |
} |
116 |
|
117 |
public function isSubPathOf(path $path)100% |
118 |
{ |
119 |
$this->resolve(); |
120 |
|
121 |
$resolvedPath = $path->getResolvedPath(); |
122 |
|
123 |
return ($this->components !== $resolvedPath->components && ($resolvedPath->isRoot() === true || strpos($this->components, $resolvedPath->components . '/') === 0)); |
124 |
} |
125 |
|
126 |
public function isNotSubPathOf(path $path)100% |
127 |
{ |
128 |
return ($this->isSubPathOf($path) === false); |
129 |
} |
130 |
|
131 |
public function isRoot()100% |
132 |
{ |
133 |
return static::pathIsRoot($this->getResolvedPath()->components); |
134 |
} |
135 |
|
136 |
public function isAbsolute()100% |
137 |
{ |
138 |
return static::pathIsAbsolute($this->components); |
139 |
} |
140 |
|
141 |
public function absolutize()100% |
142 |
{ |
143 |
if ($this->isAbsolute() === false) |
144 |
{ |
145 |
$this->setDriveAndComponents(getcwd() . DIRECTORY_SEPARATOR . $this->components); |
146 |
} |
147 |
|
148 |
return $this; |
149 |
} |
150 |
|
151 |
public function getRealPath()100% |
152 |
{ |
153 |
$absolutePath = $this->getAbsolutePath(); |
154 |
|
155 |
$files = ''; |
156 |
$realPath = realpath((string) $absolutePath); |
157 |
|
158 |
if ($realPath === false) |
159 |
{ |
160 |
while ($realPath === false && $absolutePath->isRoot() === false) |
161 |
{ |
162 |
$files = '/' . basename((string) $absolutePath) . $files; |
163 |
$absolutePath = $absolutePath->getParentDirectoryPath(); |
164 |
$realPath = realpath((string) $absolutePath); |
165 |
} |
166 |
} |
167 |
|
168 |
if ($realPath === false) |
169 |
{ |
170 |
throw new exception('Unable to get real path for \'' . $this . '\''); |
171 |
} |
172 |
|
173 |
return $absolutePath->setDriveAndComponents($realPath . $files); |
174 |
} |
175 |
|
176 |
public function getParentDirectoryPath()100% |
177 |
{ |
178 |
$parentDirectory = clone $this; |
179 |
$parentDirectory->components = self::getComponents(dirname($parentDirectory->components)); |
180 |
|
181 |
return $parentDirectory; |
182 |
} |
183 |
|
184 |
public function getRealParentDirectoryPath()88% |
185 |
{ |
186 |
$realParentDirectoryPath = $this->getParentDirectoryPath(); |
187 |
|
188 |
while ($realParentDirectoryPath->exists() === false && $realParentDirectoryPath->isRoot() === false) |
189 |
{ |
190 |
$realParentDirectoryPath = $realParentDirectoryPath->getParentDirectoryPath(); |
191 |
} |
192 |
|
193 |
if ($realParentDirectoryPath->exists() === false) |
194 |
{ |
195 |
throw new exception('Unable to find real parent directory for \'' . $this . '\''); |
196 |
} |
197 |
|
198 |
return $realParentDirectoryPath; |
199 |
} |
200 |
|
201 |
public function getRelativePathFrom(path $reference)100% |
202 |
{ |
203 |
$clone = clone $this; |
204 |
|
205 |
return $clone->relativizeFrom($reference); |
206 |
} |
207 |
|
208 |
public function getResolvedPath()100% |
209 |
{ |
210 |
$clone = clone $this; |
211 |
|
212 |
return $clone->resolve(); |
213 |
} |
214 |
|
215 |
public function getAbsolutePath()100% |
216 |
{ |
217 |
$clone = clone $this; |
218 |
|
219 |
return $clone->absolutize(); |
220 |
} |
221 |
|
222 |
public function createParentDirectory()100% |
223 |
{ |
224 |
$parentDirectory = $this->getParentDirectoryPath(); |
225 |
|
226 |
if (file_exists((string) $parentDirectory) === false && @mkdir($parentDirectory, 0777, true) === false) |
227 |
{ |
228 |
throw new exception('Unable to create directory \'' . $parentDirectory . '\''); |
229 |
} |
230 |
|
231 |
return $this; |
232 |
} |
233 |
|
234 |
public function putContents($data)100% |
235 |
{ |
236 |
if (@file_put_contents($this->createParentDirectory(), $data) === false) |
237 |
{ |
238 |
throw new exception('Unable to put data \'' . $data . '\' in file \'' . $this . '\''); |
239 |
} |
240 |
|
241 |
return $this; |
242 |
} |
243 |
|
244 |
protected function setDriveAndComponents($value)100% |
245 |
{ |
246 |
$drive = null; |
247 |
|
248 |
if (preg_match('#^[a-z]:#i', $value, $matches) == true) |
249 |
{ |
250 |
$drive = $matches[0]; |
251 |
$value = substr($value, 2); |
252 |
} |
253 |
|
254 |
$this->drive = $drive; |
255 |
$this->components = self::getComponents($value); |
256 |
|
257 |
return $this; |
258 |
} |
259 |
|
260 |
protected static function pathIsRoot($path)100% |
261 |
{ |
262 |
return ($path === '/'); |
263 |
} |
264 |
|
265 |
protected static function pathIsAbsolute($path)100% |
266 |
{ |
267 |
return (substr($path, 0, 1) === '/'); |
268 |
} |
269 |
|
270 |
protected static function getComponents($path)100% |
271 |
{ |
272 |
$path = str_replace('\\', '/', $path); |
273 |
|
274 |
if (static::pathIsRoot($path) === false) |
275 |
{ |
276 |
$path = rtrim($path, '/'); |
277 |
} |
278 |
|
279 |
return preg_replace('#/{2,}#', '/', $path); |
280 |
} |
281 |
} |