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(); |