/Framework/Bootstrap/Autoloader.php

https://gitlab.com/Erdrix/overviewCompanies · PHP · 234 lines · 129 code · 35 blank · 70 comment · 14 complexity · 953ee2678923e1c00f359b723a38d8f1 MD5 · raw file

  1. <?php
  2. /**
  3. * Filtrage des extension de fichiers
  4. */
  5. class ExtensionFilterIteratorDecorator extends FilterIterator
  6. {
  7. private $_ext;
  8. public function accept()
  9. {
  10. if (substr($this->current(), -1 * strlen($this->_ext)) === $this->_ext) {
  11. return is_readable($this->current());
  12. }
  13. return false;
  14. }
  15. /**
  16. * Définis l'extension
  17. *
  18. * @param string $pExt
  19. */
  20. public function setExtension($pExt)
  21. {
  22. $this->_ext = $pExt;
  23. }
  24. }
  25. /**
  26. * Auto chargement des fichiers requis pour
  27. * le fonctionnement de l'application
  28. */
  29. class DirectoriesAutoloader
  30. {
  31. private static $_instance = false;
  32. private $_canRegenerate = true;
  33. private $_classes = [];
  34. private $_directories = [];
  35. private $_cachePath;
  36. private function __construct()
  37. {
  38. }
  39. /**
  40. * Register de l'autoloader
  41. * Utilisé lors de l'initialisation de l'objet
  42. *
  43. * @param string $pTmpPath : Chemin utilisé pour la sauvegarde du cache
  44. * @param array $folder : Liste des dossiers à ajouter au chemin de recherche
  45. *
  46. * @return DirectoriesAutoloader
  47. */
  48. public static function register($pTmpPath, $folder = [])
  49. {
  50. $autoloader = new DirectoriesAutoloader();
  51. $autoloader->setCachePath($pTmpPath);
  52. foreach ($folder as $name) {
  53. $autoloader->addDirectory($name);
  54. }
  55. spl_autoload_register([$autoloader, 'autoload']);
  56. return (self::$_instance = $autoloader);
  57. }
  58. /**
  59. * Récupération du singleton
  60. * @return mixed : false si pas d'instance
  61. */
  62. public static function instance()
  63. {
  64. return self::$_instance;
  65. }
  66. /**
  67. * Définis le chemin de sauvegarde du cache
  68. *
  69. * @param string $pTmp : Chemin vers le cache
  70. *
  71. * @throws Exception : Fichier de cache invalide
  72. */
  73. public function setCachePath($pTmp)
  74. {
  75. $path = getTemporary($pTmp);
  76. if (!is_writable($path)) {
  77. throw new Exception('Cannot write in given CachePath [' . $path . ']');
  78. }
  79. $this->_cachePath = $path;
  80. }
  81. /**
  82. * Fonction utilisée lors de la résolution de chemin
  83. * False : Impossible de charger le fichier
  84. * Object : Contenu du fichier chargé
  85. *
  86. * @param string $pClassName : Nom de la classe à charger
  87. *
  88. * @return mixed True : Classe déja chargée
  89. */
  90. public function autoload($pClassName)
  91. {
  92. if ($this->_loadClass($pClassName)) {
  93. return true;
  94. }
  95. if ($this->_canRegenerate) {
  96. $this->_canRegenerate = false;
  97. $this->_includesAll();
  98. $this->_saveInCache();
  99. return $this->autoload($pClassName);
  100. }
  101. return false;
  102. }
  103. /**
  104. * Ajoute un répertoire a la liste de ceux à autoloader
  105. *
  106. * @param string $pDirectory : Dossier à ajouter
  107. * @param boolean $pRecursive : Recherche dans les sous-dossier (default: true)
  108. *
  109. * @throws Exception
  110. * @return Autoloader
  111. */
  112. public function addDirectory($pDirectory, $pRecursive = true)
  113. {
  114. if (!is_readable($pDirectory)) {
  115. throw new Exception('Cannot read from [' . $pDirectory . ']');
  116. }
  117. $this->_directories[$pDirectory] = $pRecursive ? true : false;
  118. return $this;
  119. }
  120. /**
  121. * Recherche de toutes les classes dans les répertoires donnés
  122. */
  123. private function _includesAll()
  124. {
  125. foreach ($this->_directories as $directory => $recursive) {
  126. $directories = new AppendIterator();
  127. if ($recursive) {
  128. $directories->append(new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)));
  129. } else {
  130. $directories->append(new DirectoryIterator($directory));
  131. }
  132. $files = new ExtensionFilterIteratorDecorator($directories);
  133. $files->setExtension('.php');
  134. foreach ($files as $file) {
  135. $classes = $this->_extractClasses((string)$file);
  136. foreach ($classes as $className => $fileName) {
  137. $this->_classes[strtolower($className)] = $fileName;
  138. }
  139. }
  140. }
  141. }
  142. /**
  143. * Extraction des classes & interfaces d'un fichier
  144. *
  145. * @param string $pFileName : Nom du fichier de lecture
  146. *
  147. * @return array
  148. */
  149. private function _extractClasses($pFileName)
  150. {
  151. $toReturn = [];
  152. $tokens = token_get_all(file_get_contents($pFileName, false));
  153. $tokens = array_filter($tokens, 'is_array');
  154. $classHunt = false;
  155. foreach ($tokens as $token) {
  156. if (T_INTERFACE === $token[0] || T_CLASS === $token[0]) {
  157. $classHunt = true;
  158. continue;
  159. }
  160. if ($classHunt && T_STRING === $token[0]) {
  161. $toReturn[$token[1]] = $pFileName;
  162. $classHunt = false;
  163. }
  164. }
  165. return $toReturn;
  166. }
  167. /**
  168. * Sauvegarde la liste des classes dans le fichier de cache
  169. */
  170. private function _saveIncache()
  171. {
  172. $file = $this->_cachePath . 'autoloader.php';
  173. $toSave = '<?php $classes = ' . var_export($this->_classes, true) . '; ?>';
  174. file_put_contents($file, $toSave);
  175. chmod($file, octdec('0777'));
  176. }
  177. /**
  178. * Charger une classe
  179. *
  180. * @param string $pClassName : Nom de la classe à charger
  181. *
  182. * @return boolean : False si impossible de charger la classe
  183. */
  184. private function _loadClass($pClassName)
  185. {
  186. $className = strtolower($pClassName);
  187. if (count($this->_classes) === 0) {
  188. if (is_readable($this->_cachePath . 'autoloader.php')) {
  189. require $this->_cachePath . 'autoloader.php';
  190. $this->_classes = $classes;
  191. }
  192. }
  193. if (isset($this->_classes[$className])) {
  194. require_once $this->_classes[$className];
  195. return true;
  196. }
  197. return false;
  198. }
  199. }