PageRenderTime 27ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/zendframework/zendframework/library/Zend/Loader/ModuleAutoloader.php

https://bitbucket.org/zbahij/eprojets_app
PHP | 416 lines | 240 code | 45 blank | 131 comment | 37 complexity | d2517ae5af2f4a70cf8c95a49b0eadb7 MD5 | raw file
  1. <?php
  2. /**
  3. * Zend Framework (http://framework.zend.com/)
  4. *
  5. * @link http://github.com/zendframework/zf2 for the canonical source repository
  6. * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
  7. * @license http://framework.zend.com/license/new-bsd New BSD License
  8. */
  9. namespace Zend\Loader;
  10. // Grab SplAutoloader interface
  11. require_once __DIR__ . '/SplAutoloader.php';
  12. use GlobIterator;
  13. use SplFileInfo;
  14. use Traversable;
  15. class ModuleAutoloader implements SplAutoloader
  16. {
  17. /**
  18. * @var array An array of module paths to scan
  19. */
  20. protected $paths = array();
  21. /**
  22. * @var array An array of modulename => path
  23. */
  24. protected $explicitPaths = array();
  25. /**
  26. * @var array An array of namespaceName => namespacePath
  27. */
  28. protected $namespacedPaths = array();
  29. /**
  30. * @var array An array of supported phar extensions (filled on constructor)
  31. */
  32. protected $pharExtensions = array();
  33. /**
  34. * @var array An array of module classes to their containing files
  35. */
  36. protected $moduleClassMap = array();
  37. /**
  38. * Constructor
  39. *
  40. * Allow configuration of the autoloader via the constructor.
  41. *
  42. * @param null|array|Traversable $options
  43. */
  44. public function __construct($options = null)
  45. {
  46. if (extension_loaded('phar')) {
  47. $this->pharExtensions = array(
  48. 'phar',
  49. 'phar.tar',
  50. 'tar',
  51. );
  52. // ext/zlib enabled -> phar can read gzip & zip compressed files
  53. if (extension_loaded('zlib')) {
  54. $this->pharExtensions[] = 'phar.gz';
  55. $this->pharExtensions[] = 'phar.tar.gz';
  56. $this->pharExtensions[] = 'tar.gz';
  57. $this->pharExtensions[] = 'phar.zip';
  58. $this->pharExtensions[] = 'zip';
  59. }
  60. // ext/bzip2 enabled -> phar can read bz2 compressed files
  61. if (extension_loaded('bzip2')) {
  62. $this->pharExtensions[] = 'phar.bz2';
  63. $this->pharExtensions[] = 'phar.tar.bz2';
  64. $this->pharExtensions[] = 'tar.bz2';
  65. }
  66. }
  67. if (null !== $options) {
  68. $this->setOptions($options);
  69. }
  70. }
  71. /**
  72. * Configure the autoloader
  73. *
  74. * In most cases, $options should be either an associative array or
  75. * Traversable object.
  76. *
  77. * @param array|Traversable $options
  78. * @return ModuleAutoloader
  79. */
  80. public function setOptions($options)
  81. {
  82. $this->registerPaths($options);
  83. return $this;
  84. }
  85. /**
  86. * Retrieves the class map for all loaded modules.
  87. *
  88. * @return array
  89. */
  90. public function getModuleClassMap()
  91. {
  92. return $this->moduleClassMap;
  93. }
  94. /**
  95. * Sets the class map used to speed up the module autoloading.
  96. *
  97. * @param array $classmap
  98. * @return ModuleAutoloader
  99. */
  100. public function setModuleClassMap(array $classmap)
  101. {
  102. $this->moduleClassMap = $classmap;
  103. return $this;
  104. }
  105. /**
  106. * Autoload a class
  107. *
  108. * @param $class
  109. * @return mixed
  110. * False [if unable to load $class]
  111. * get_class($class) [if $class is successfully loaded]
  112. */
  113. public function autoload($class)
  114. {
  115. // Limit scope of this autoloader
  116. if (substr($class, -7) !== '\Module') {
  117. return false;
  118. }
  119. if (isset($this->moduleClassMap[$class])) {
  120. require_once $this->moduleClassMap[$class];
  121. return $class;
  122. }
  123. $moduleName = substr($class, 0, -7);
  124. if (isset($this->explicitPaths[$moduleName])) {
  125. $classLoaded = $this->loadModuleFromDir($this->explicitPaths[$moduleName], $class);
  126. if ($classLoaded) {
  127. return $classLoaded;
  128. }
  129. $classLoaded = $this->loadModuleFromPhar($this->explicitPaths[$moduleName], $class);
  130. if ($classLoaded) {
  131. return $classLoaded;
  132. }
  133. }
  134. if (count($this->namespacedPaths) >= 1) {
  135. foreach ($this->namespacedPaths as $namespace => $path) {
  136. if (false === strpos($moduleName, $namespace)) {
  137. continue;
  138. }
  139. $moduleNameBuffer = str_replace($namespace . "\\", "", $moduleName );
  140. $path .= DIRECTORY_SEPARATOR . $moduleNameBuffer . DIRECTORY_SEPARATOR;
  141. $classLoaded = $this->loadModuleFromDir($path, $class);
  142. if ($classLoaded) {
  143. return $classLoaded;
  144. }
  145. $classLoaded = $this->loadModuleFromPhar($path, $class);
  146. if ($classLoaded) {
  147. return $classLoaded;
  148. }
  149. }
  150. }
  151. $moduleClassPath = str_replace('\\', DIRECTORY_SEPARATOR, $moduleName);
  152. $pharSuffixPattern = null;
  153. if ($this->pharExtensions) {
  154. $pharSuffixPattern = '(' . implode('|', array_map('preg_quote', $this->pharExtensions)) . ')';
  155. }
  156. foreach ($this->paths as $path) {
  157. $path = $path . $moduleClassPath;
  158. $classLoaded = $this->loadModuleFromDir($path, $class);
  159. if ($classLoaded) {
  160. return $classLoaded;
  161. }
  162. // No directory with Module.php, searching for phars
  163. if ($pharSuffixPattern) {
  164. foreach (new GlobIterator($path . '.*') as $entry) {
  165. if ($entry->isDir()) {
  166. continue;
  167. }
  168. if (!preg_match('#.+\.' . $pharSuffixPattern . '$#', $entry->getPathname())) {
  169. continue;
  170. }
  171. $classLoaded = $this->loadModuleFromPhar($entry->getPathname(), $class);
  172. if ($classLoaded) {
  173. return $classLoaded;
  174. }
  175. }
  176. }
  177. }
  178. return false;
  179. }
  180. /**
  181. * loadModuleFromDir
  182. *
  183. * @param string $dirPath
  184. * @param string $class
  185. * @return mixed
  186. * False [if unable to load $class]
  187. * get_class($class) [if $class is successfully loaded]
  188. */
  189. protected function loadModuleFromDir($dirPath, $class)
  190. {
  191. $file = new SplFileInfo($dirPath . '/Module.php');
  192. if ($file->isReadable() && $file->isFile()) {
  193. // Found directory with Module.php in it
  194. require_once $file->getRealPath();
  195. if (class_exists($class)) {
  196. $this->moduleClassMap[$class] = $file->getRealPath();
  197. return $class;
  198. }
  199. }
  200. return false;
  201. }
  202. /**
  203. * loadModuleFromPhar
  204. *
  205. * @param string $pharPath
  206. * @param string $class
  207. * @return mixed
  208. * False [if unable to load $class]
  209. * get_class($class) [if $class is successfully loaded]
  210. */
  211. protected function loadModuleFromPhar($pharPath, $class)
  212. {
  213. $pharPath = static::normalizePath($pharPath, false);
  214. $file = new SplFileInfo($pharPath);
  215. if (!$file->isReadable() || !$file->isFile()) {
  216. return false;
  217. }
  218. $fileRealPath = $file->getRealPath();
  219. // Phase 0: Check for executable phar with Module class in stub
  220. if (strpos($fileRealPath, '.phar') !== false) {
  221. // First see if the stub makes the Module class available
  222. require_once $fileRealPath;
  223. if (class_exists($class)) {
  224. $this->moduleClassMap[$class] = $fileRealPath;
  225. return $class;
  226. }
  227. }
  228. // Phase 1: Not executable phar, no stub, or stub did not provide Module class; try Module.php directly
  229. $moduleClassFile = 'phar://' . $fileRealPath . '/Module.php';
  230. $moduleFile = new SplFileInfo($moduleClassFile);
  231. if ($moduleFile->isReadable() && $moduleFile->isFile()) {
  232. require_once $moduleClassFile;
  233. if (class_exists($class)) {
  234. $this->moduleClassMap[$class] = $moduleClassFile;
  235. return $class;
  236. }
  237. }
  238. // Phase 2: Check for nested module directory within archive
  239. // Checks for /path/to/MyModule.tar/MyModule/Module.php
  240. // (shell-integrated zip/tar utilities wrap directories like this)
  241. $pharBaseName = $this->pharFileToModuleName($fileRealPath);
  242. $moduleClassFile = 'phar://' . $fileRealPath . '/' . $pharBaseName . '/Module.php';
  243. $moduleFile = new SplFileInfo($moduleClassFile);
  244. if ($moduleFile->isReadable() && $moduleFile->isFile()) {
  245. require_once $moduleClassFile;
  246. if (class_exists($class)) {
  247. $this->moduleClassMap[$class] = $moduleClassFile;
  248. return $class;
  249. }
  250. }
  251. return false;
  252. }
  253. /**
  254. * Register the autoloader with spl_autoload registry
  255. *
  256. * @return void
  257. */
  258. public function register()
  259. {
  260. spl_autoload_register(array($this, 'autoload'));
  261. }
  262. /**
  263. * Unregister the autoloader with spl_autoload registry
  264. *
  265. * @return void
  266. */
  267. public function unregister()
  268. {
  269. spl_autoload_unregister(array($this, 'autoload'));
  270. }
  271. /**
  272. * registerPaths
  273. *
  274. * @param array|Traversable $paths
  275. * @throws \InvalidArgumentException
  276. * @return ModuleAutoloader
  277. */
  278. public function registerPaths($paths)
  279. {
  280. if (!is_array($paths) && !$paths instanceof Traversable) {
  281. require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  282. throw new Exception\InvalidArgumentException(
  283. 'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s '
  284. . 'registerPaths method must be an array or '
  285. . 'implement the Traversable interface'
  286. );
  287. }
  288. foreach ($paths as $module => $path) {
  289. if (is_string($module)) {
  290. $this->registerPath($path, $module);
  291. } else {
  292. $this->registerPath($path);
  293. }
  294. }
  295. return $this;
  296. }
  297. /**
  298. * registerPath
  299. *
  300. * @param string $path
  301. * @param bool|string $moduleName
  302. * @throws \InvalidArgumentException
  303. * @return ModuleAutoloader
  304. */
  305. public function registerPath($path, $moduleName = false)
  306. {
  307. if (!is_string($path)) {
  308. require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  309. throw new Exception\InvalidArgumentException(sprintf(
  310. 'Invalid path provided; must be a string, received %s',
  311. gettype($path)
  312. ));
  313. }
  314. if ($moduleName) {
  315. if (in_array( substr($moduleName, -2), array('\\*', '\\%'))) {
  316. $this->namespacedPaths[substr($moduleName, 0, -2)] = static::normalizePath($path);
  317. } else {
  318. $this->explicitPaths[$moduleName] = static::normalizePath($path);
  319. }
  320. } else {
  321. $this->paths[] = static::normalizePath($path);
  322. }
  323. return $this;
  324. }
  325. /**
  326. * getPaths
  327. *
  328. * This is primarily for unit testing, but could have other uses.
  329. *
  330. * @return array
  331. */
  332. public function getPaths()
  333. {
  334. return $this->paths;
  335. }
  336. /**
  337. * Returns the base module name from the path to a phar
  338. *
  339. * @param string $pharPath
  340. * @return string
  341. */
  342. protected function pharFileToModuleName($pharPath)
  343. {
  344. do {
  345. $pathinfo = pathinfo($pharPath);
  346. $pharPath = $pathinfo['filename'];
  347. } while (isset($pathinfo['extension']));
  348. return $pathinfo['filename'];
  349. }
  350. /**
  351. * Normalize a path for insertion in the stack
  352. *
  353. * @param string $path
  354. * @param bool $trailingSlash Whether trailing slash should be included
  355. * @return string
  356. */
  357. public static function normalizePath($path, $trailingSlash = true)
  358. {
  359. $path = rtrim($path, '/');
  360. $path = rtrim($path, '\\');
  361. if ($trailingSlash) {
  362. $path .= DIRECTORY_SEPARATOR;
  363. }
  364. return $path;
  365. }
  366. }