PageRenderTime 24ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/vendor/zendframework/zend-loader/src/ModuleAutoloader.php

https://gitlab.com/koodersmiikka/operaatio-terveys
PHP | 426 lines | 248 code | 47 blank | 131 comment | 38 complexity | fb478c3c6a63d45829c1635e35ab679c 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-2014 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. if ($path == '.' || substr($path, 0, 2) == './' || substr($path, 0, 2) == '.\\') {
  159. $basePath = realpath('.');
  160. if (false === $basePath) {
  161. $basePath = getcwd();
  162. }
  163. $path = rtrim($basePath, '\/\\') . substr($path, 1);
  164. }
  165. $classLoaded = $this->loadModuleFromDir($path, $class);
  166. if ($classLoaded) {
  167. return $classLoaded;
  168. }
  169. // No directory with Module.php, searching for phars
  170. if ($pharSuffixPattern) {
  171. foreach (new GlobIterator($path . '.*') as $entry) {
  172. if ($entry->isDir()) {
  173. continue;
  174. }
  175. if (!preg_match('#.+\.' . $pharSuffixPattern . '$#', $entry->getPathname())) {
  176. continue;
  177. }
  178. $classLoaded = $this->loadModuleFromPhar($entry->getPathname(), $class);
  179. if ($classLoaded) {
  180. return $classLoaded;
  181. }
  182. }
  183. }
  184. }
  185. return false;
  186. }
  187. /**
  188. * loadModuleFromDir
  189. *
  190. * @param string $dirPath
  191. * @param string $class
  192. * @return mixed
  193. * False [if unable to load $class]
  194. * get_class($class) [if $class is successfully loaded]
  195. */
  196. protected function loadModuleFromDir($dirPath, $class)
  197. {
  198. $file = new SplFileInfo($dirPath . '/Module.php');
  199. if ($file->isReadable() && $file->isFile()) {
  200. // Found directory with Module.php in it
  201. require_once $file->getRealPath();
  202. if (class_exists($class)) {
  203. $this->moduleClassMap[$class] = $file->getRealPath();
  204. return $class;
  205. }
  206. }
  207. return false;
  208. }
  209. /**
  210. * loadModuleFromPhar
  211. *
  212. * @param string $pharPath
  213. * @param string $class
  214. * @return mixed
  215. * False [if unable to load $class]
  216. * get_class($class) [if $class is successfully loaded]
  217. */
  218. protected function loadModuleFromPhar($pharPath, $class)
  219. {
  220. $pharPath = static::normalizePath($pharPath, false);
  221. $file = new SplFileInfo($pharPath);
  222. if (!$file->isReadable() || !$file->isFile()) {
  223. return false;
  224. }
  225. $fileRealPath = $file->getRealPath();
  226. // Phase 0: Check for executable phar with Module class in stub
  227. if (strpos($fileRealPath, '.phar') !== false) {
  228. // First see if the stub makes the Module class available
  229. require_once $fileRealPath;
  230. if (class_exists($class)) {
  231. $this->moduleClassMap[$class] = $fileRealPath;
  232. return $class;
  233. }
  234. }
  235. // Phase 1: Not executable phar, no stub, or stub did not provide Module class; try Module.php directly
  236. $moduleClassFile = 'phar://' . $fileRealPath . '/Module.php';
  237. $moduleFile = new SplFileInfo($moduleClassFile);
  238. if ($moduleFile->isReadable() && $moduleFile->isFile()) {
  239. require_once $moduleClassFile;
  240. if (class_exists($class)) {
  241. $this->moduleClassMap[$class] = $moduleClassFile;
  242. return $class;
  243. }
  244. }
  245. // Phase 2: Check for nested module directory within archive
  246. // Checks for /path/to/MyModule.tar/MyModule/Module.php
  247. // (shell-integrated zip/tar utilities wrap directories like this)
  248. $pharBaseName = $this->pharFileToModuleName($fileRealPath);
  249. $moduleClassFile = 'phar://' . $fileRealPath . '/' . $pharBaseName . '/Module.php';
  250. $moduleFile = new SplFileInfo($moduleClassFile);
  251. if ($moduleFile->isReadable() && $moduleFile->isFile()) {
  252. require_once $moduleClassFile;
  253. if (class_exists($class)) {
  254. $this->moduleClassMap[$class] = $moduleClassFile;
  255. return $class;
  256. }
  257. }
  258. return false;
  259. }
  260. /**
  261. * Register the autoloader with spl_autoload registry
  262. *
  263. * @return void
  264. */
  265. public function register()
  266. {
  267. spl_autoload_register(array($this, 'autoload'));
  268. }
  269. /**
  270. * Unregister the autoloader with spl_autoload registry
  271. *
  272. * @return void
  273. */
  274. public function unregister()
  275. {
  276. spl_autoload_unregister(array($this, 'autoload'));
  277. }
  278. /**
  279. * registerPaths
  280. *
  281. * @param array|Traversable $paths
  282. * @throws \InvalidArgumentException
  283. * @return ModuleAutoloader
  284. */
  285. public function registerPaths($paths)
  286. {
  287. if (!is_array($paths) && !$paths instanceof Traversable) {
  288. require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  289. throw new Exception\InvalidArgumentException(
  290. 'Parameter to \\Zend\\Loader\\ModuleAutoloader\'s '
  291. . 'registerPaths method must be an array or '
  292. . 'implement the Traversable interface'
  293. );
  294. }
  295. foreach ($paths as $module => $path) {
  296. if (is_string($module)) {
  297. $this->registerPath($path, $module);
  298. } else {
  299. $this->registerPath($path);
  300. }
  301. }
  302. return $this;
  303. }
  304. /**
  305. * registerPath
  306. *
  307. * @param string $path
  308. * @param bool|string $moduleName
  309. * @throws \InvalidArgumentException
  310. * @return ModuleAutoloader
  311. */
  312. public function registerPath($path, $moduleName = false)
  313. {
  314. if (!is_string($path)) {
  315. require_once __DIR__ . '/Exception/InvalidArgumentException.php';
  316. throw new Exception\InvalidArgumentException(sprintf(
  317. 'Invalid path provided; must be a string, received %s',
  318. gettype($path)
  319. ));
  320. }
  321. if ($moduleName) {
  322. if (in_array( substr($moduleName, -2), array('\\*', '\\%'))) {
  323. $this->namespacedPaths[substr($moduleName, 0, -2)] = static::normalizePath($path);
  324. } else {
  325. $this->explicitPaths[$moduleName] = static::normalizePath($path);
  326. }
  327. } else {
  328. $this->paths[] = static::normalizePath($path);
  329. }
  330. return $this;
  331. }
  332. /**
  333. * getPaths
  334. *
  335. * This is primarily for unit testing, but could have other uses.
  336. *
  337. * @return array
  338. */
  339. public function getPaths()
  340. {
  341. return $this->paths;
  342. }
  343. /**
  344. * Returns the base module name from the path to a phar
  345. *
  346. * @param string $pharPath
  347. * @return string
  348. */
  349. protected function pharFileToModuleName($pharPath)
  350. {
  351. do {
  352. $pathinfo = pathinfo($pharPath);
  353. $pharPath = $pathinfo['filename'];
  354. } while (isset($pathinfo['extension']));
  355. return $pathinfo['filename'];
  356. }
  357. /**
  358. * Normalize a path for insertion in the stack
  359. *
  360. * @param string $path
  361. * @param bool $trailingSlash Whether trailing slash should be included
  362. * @return string
  363. */
  364. public static function normalizePath($path, $trailingSlash = true)
  365. {
  366. $path = rtrim($path, '/');
  367. $path = rtrim($path, '\\');
  368. if ($trailingSlash) {
  369. $path .= DIRECTORY_SEPARATOR;
  370. }
  371. return $path;
  372. }
  373. }