42% of 1147OPs |
43% of 182Lines |
25% of 208Branches |
2% of 740Paths |
# | |
---|---|
1 |
<?php |
2 |
|
3 |
namespace mageekguy\atoum; |
4 |
|
5 |
class autoloader |
6 |
{ |
7 |
const version = 1; |
8 |
const defaultFileSuffix = '.php'; |
9 |
const defaultCacheFileName = '%s.atoum.cache'; |
10 |
|
11 |
protected $version = null; |
12 |
protected $classes = array(); |
13 |
protected $directories = array(); |
14 |
protected $classAliases = array(); |
15 |
protected $namespaceAliases = array(); |
16 |
protected $cacheFileInstance = null; |
17 |
|
18 |
protected static $autoloader = null; |
19 |
|
20 |
private $cacheUsed = false; |
21 |
|
22 |
private static $cacheFile = null; |
23 |
private static $registeredAutoloaders = null; |
24 |
|
25 |
public function __construct(array $namespaces = array(), array $namespaceAliases = array(), $classAliases = array())100% |
26 |
{ |
27 |
$this->version = static::version; |
28 |
|
29 |
if (sizeof($namespaces) <= 0) |
30 |
{ |
31 |
$namespaces = array(__NAMESPACE__ => __DIR__); |
32 |
} |
33 |
|
34 |
foreach ($namespaces as $namespace => $directory) |
35 |
{ |
36 |
$this->addDirectory($namespace, $directory); |
37 |
} |
38 |
|
39 |
foreach ($namespaceAliases ?: array('atoum' => __NAMESPACE__) as $alias => $target) |
40 |
{ |
41 |
$this->addNamespaceAlias($alias, $target); |
42 |
} |
43 |
|
44 |
foreach ($classAliases ?: array('atoum' => __NAMESPACE__ . '\test', __NAMESPACE__ => __NAMESPACE__ . '\test') as $alias => $target) |
45 |
{ |
46 |
$this->addClassAlias($alias, $target); |
47 |
} |
48 |
} |
49 |
|
50 |
public function register($prepend = false)0% |
51 |
{ |
52 |
if (spl_autoload_register(array($this, 'requireClass'), true, $prepend) === false) |
53 |
{ |
54 |
throw new \runtimeException('Unable to register autoloader \'' . get_class($this) . '\''); |
55 |
} |
56 |
|
57 |
if (self::$registeredAutoloaders === null) |
58 |
{ |
59 |
self::$registeredAutoloaders = new \splObjectStorage(); |
60 |
} |
61 |
|
62 |
self::$registeredAutoloaders->attach($this); |
63 |
|
64 |
return $this; |
65 |
} |
66 |
|
67 |
public function unregister()0% |
68 |
{ |
69 |
if (spl_autoload_unregister(array($this, 'requireClass')) === false) |
70 |
{ |
71 |
throw new \runtimeException('Unable to unregister'); |
72 |
} |
73 |
|
74 |
self::$registeredAutoloaders->detach($this); |
75 |
|
76 |
return $this; |
77 |
} |
78 |
|
79 |
public function addDirectory($namespace, $directory, $suffix = self::defaultFileSuffix)100% |
80 |
{ |
81 |
$namespace = strtolower(trim($namespace, '\\') . '\\'); |
82 |
$directory = rtrim($directory, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR; |
83 |
|
84 |
if ($this->directoryIsSet($namespace, $directory) === false) |
85 |
{ |
86 |
$this->directories[$namespace][] = array($directory, $suffix); |
87 |
|
88 |
krsort($this->directories, \SORT_STRING); |
89 |
} |
90 |
|
91 |
return $this; |
92 |
} |
93 |
|
94 |
public function directoryIsSet($namespace, $directory)33% |
95 |
{ |
96 |
if (isset($this->directories[$namespace]) === true) |
97 |
{ |
98 |
foreach ($this->directories[$namespace] as $directoryData) |
99 |
{ |
100 |
if ($directoryData[0] == $directory) |
101 |
{ |
102 |
return true; |
103 |
} |
104 |
} |
105 |
} |
106 |
|
107 |
return false; |
108 |
} |
109 |
|
110 |
public function getDirectories()100% |
111 |
{ |
112 |
return $this->directories; |
113 |
} |
114 |
|
115 |
public function getClasses()100% |
116 |
{ |
117 |
return $this->classes; |
118 |
} |
119 |
|
120 |
public function setClasses(array $classes)0% |
121 |
{ |
122 |
$this->classes = $classes; |
123 |
|
124 |
return $this; |
125 |
} |
126 |
|
127 |
public function addNamespaceAlias($alias, $target)100% |
128 |
{ |
129 |
$this->namespaceAliases[strtolower(trim($alias, '\\')) . '\\'] = trim($target, '\\') . '\\'; |
130 |
|
131 |
return $this; |
132 |
} |
133 |
|
134 |
public function getNamespaceAliases()100% |
135 |
{ |
136 |
return $this->namespaceAliases; |
137 |
} |
138 |
|
139 |
public function addClassAlias($alias, $target)100% |
140 |
{ |
141 |
$this->classAliases[strtolower(trim($alias, '\\'))] = trim($target, '\\'); |
142 |
|
143 |
return $this; |
144 |
} |
145 |
|
146 |
public function getClassAliases()100% |
147 |
{ |
148 |
return $this->classAliases; |
149 |
} |
150 |
|
151 |
public function getPath($class)24% |
152 |
{ |
153 |
$this->readCache(); |
154 |
|
155 |
$class = strtolower($class); |
156 |
|
157 |
$path = (isset($this->classes[$class]) === false || is_file($this->classes[$class]) === false ? null : $this->classes[$class]); |
158 |
|
159 |
if ($path === null && $this->handleNamespaceOfClass($class) === true) |
160 |
{ |
161 |
$classes = array(); |
162 |
|
163 |
foreach ($this->directories as $namespace => $directories) |
164 |
{ |
165 |
foreach ($directories as $directoryData) |
166 |
{ |
167 |
list($directory, $suffix) = $directoryData; |
168 |
|
169 |
$directoryLength = strlen($directory); |
170 |
$suffixLength = - strlen($suffix); |
171 |
|
172 |
foreach (new \recursiveIteratorIterator(new \recursiveDirectoryIterator($directory, \filesystemIterator::SKIP_DOTS|\filesystemIterator::CURRENT_AS_FILEINFO), \recursiveIteratorIterator::LEAVES_ONLY) as $file) |
173 |
{ |
174 |
$filePath = $file->getPathname(); |
175 |
|
176 |
$classes[$namespace . strtolower(str_replace('/', '\\', substr($filePath, $directoryLength, $suffixLength)))] = $filePath; |
177 |
} |
178 |
} |
179 |
} |
180 |
|
181 |
if ($classes != $this->classes) |
182 |
{ |
183 |
$this->classes = $classes; |
184 |
|
185 |
$this->writeCache(); |
186 |
|
187 |
$path = (isset($this->classes[$class]) === false ? null : $this->classes[$class]); |
188 |
} |
189 |
} |
190 |
|
191 |
return $path; |
192 |
} |
193 |
|
194 |
public function requireClass($class)59% |
195 |
{ |
196 |
$class = strtolower($class); |
197 |
|
198 |
if (static::exists($class) === false && ($path = $this->getPath($class)) !== null) |
199 |
{ |
200 |
$realClass = $class; |
201 |
|
202 |
require $path; |
203 |
} |
204 |
else |
205 |
{ |
206 |
$realClass = $this->resolveClassAlias($class); |
207 |
|
208 |
if (static::exists($realClass) === false && ($path = $this->getPath($realClass)) !== null) |
209 |
{ |
210 |
require $path; |
211 |
} |
212 |
else |
213 |
{ |
214 |
$realClass = $this->resolveNamespaceAlias($realClass); |
215 |
|
216 |
if (static::exists($realClass) === false && ($path = $this->getPath($realClass)) !== null) |
217 |
{ |
218 |
require $path; |
219 |
} |
220 |
} |
221 |
} |
222 |
|
223 |
if (static::exists($realClass) === false && ($path = $this->getPath($realClass)) !== null) |
224 |
{ |
225 |
require $path; |
226 |
} |
227 |
|
228 |
if (static::exists($realClass) === true) |
229 |
{ |
230 |
$alias = ($realClass !== $class ? $class : $this->getClassAlias($realClass) ?: $this->getNamespaceAlias($realClass)); |
231 |
|
232 |
if ($alias !== null) |
233 |
{ |
234 |
class_alias($realClass, $alias); |
235 |
} |
236 |
} |
237 |
} |
238 |
|
239 |
public function setCacheFileForInstance($cacheFile)100% |
240 |
{ |
241 |
$this->cacheFileInstance = $cacheFile; |
242 |
|
243 |
return $this; |
244 |
} |
245 |
|
246 |
public function getCacheFileForInstance()100% |
247 |
{ |
248 |
return ($this->cacheFileInstance ?: static::getCacheFile()); |
249 |
} |
250 |
|
251 |
public static function set()0% |
252 |
{ |
253 |
if (static::$autoloader === null) |
254 |
{ |
255 |
static::$autoloader = new static(); |
256 |
static::$autoloader->register(); |
257 |
} |
258 |
|
259 |
return static::$autoloader; |
260 |
} |
261 |
|
262 |
public static function get()0% |
263 |
{ |
264 |
return static::set(); |
265 |
} |
266 |
|
267 |
public static function setCacheFile($cacheFile)100% |
268 |
{ |
269 |
self::$cacheFile = $cacheFile; |
270 |
} |
271 |
|
272 |
public static function getCacheFile()100% |
273 |
{ |
274 |
return (self::$cacheFile ?: rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . sprintf(static::defaultCacheFileName, md5(__FILE__))); |
275 |
} |
276 |
|
277 |
public static function getRegisteredAutoloaders()0% |
278 |
{ |
279 |
$registeredAutoloaders = array(); |
280 |
|
281 |
foreach (self::$registeredAutoloaders as $autoloader) |
282 |
{ |
283 |
$registeredAutoloaders[] = $autoloader; |
284 |
} |
285 |
|
286 |
return $registeredAutoloaders; |
287 |
} |
288 |
|
289 |
protected function resolveNamespaceAlias($class)0% |
290 |
{ |
291 |
$class = strtolower($class); |
292 |
|
293 |
foreach ($this->namespaceAliases as $alias => $target) |
294 |
{ |
295 |
if (strpos($class, $alias) === 0) |
296 |
{ |
297 |
return $target . substr($class, strlen($alias)); |
298 |
} |
299 |
} |
300 |
|
301 |
return $class; |
302 |
} |
303 |
|
304 |
protected function getNamespaceAlias($class)71% |
305 |
{ |
306 |
$class = strtolower($class); |
307 |
|
308 |
foreach ($this->namespaceAliases as $alias => $target) |
309 |
{ |
310 |
if (strpos($class, $target) === 0) |
311 |
{ |
312 |
return $alias . substr($class, strlen($target)); |
313 |
} |
314 |
} |
315 |
|
316 |
return null; |
317 |
} |
318 |
|
319 |
protected function resolveClassAlias($class)0% |
320 |
{ |
321 |
$class = strtolower($class); |
322 |
|
323 |
foreach ($this->classAliases as $alias => $target) |
324 |
{ |
325 |
if ($alias === $class) |
326 |
{ |
327 |
return $target; |
328 |
} |
329 |
} |
330 |
|
331 |
return $class; |
332 |
} |
333 |
|
334 |
protected function getClassAlias($class)86% |
335 |
{ |
336 |
$class = strtolower($class); |
337 |
|
338 |
foreach ($this->classAliases as $alias => $target) |
339 |
{ |
340 |
if ($target === $class) |
341 |
{ |
342 |
return $alias; |
343 |
} |
344 |
} |
345 |
|
346 |
return null; |
347 |
} |
348 |
|
349 |
protected function handleNamespaceOfClass($class)0% |
350 |
{ |
351 |
foreach ($this->directories as $namespace => $directories) |
352 |
{ |
353 |
if (strpos($class, $namespace) === 0) |
354 |
{ |
355 |
return true; |
356 |
} |
357 |
} |
358 |
|
359 |
return false; |
360 |
} |
361 |
|
362 |
protected function readCache()21% |
363 |
{ |
364 |
if ($this->cacheUsed === false) |
365 |
{ |
366 |
$cacheContents = @file_get_contents($this->getCacheFileForInstance()); |
367 |
|
368 |
if ($cacheContents !== false) |
369 |
{ |
370 |
$cacheContents = @unserialize($cacheContents) ?: null; |
371 |
} |
372 |
|
373 |
if (is_array($cacheContents) === true && isset($cacheContents['version']) === true && $cacheContents['version'] === static::version) |
374 |
{ |
375 |
$this->classes = $cacheContents['classes']; |
376 |
} |
377 |
|
378 |
$this->cacheUsed = true; |
379 |
} |
380 |
|
381 |
return $this; |
382 |
} |
383 |
|
384 |
protected function writeCache()0% |
385 |
{ |
386 |
$cacheFile = $this->getCacheFileForInstance(); |
387 |
|
388 |
if (@file_put_contents($cacheFile, serialize(array('version' => static::version, 'classes' => $this->classes))) === false) |
389 |
{ |
390 |
throw new \runtimeException('Unable to write in \'' . $cacheFile . '\''); |
391 |
} |
392 |
|
393 |
return $this; |
394 |
} |
395 |
|
396 |
protected static function exists($class)100% |
397 |
{ |
398 |
return (class_exists($class, false) === true || interface_exists($class, false) === true); |
399 |
} |
400 |
} |
401 |
|
402 |
autoloader::set(); |