AutoloadManager.php 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. <?php
  2. namespace Elgg;
  3. /**
  4. * Manages core autoloading and caching of class maps
  5. *
  6. * @access private
  7. *
  8. * @package Elgg.Core
  9. * @subpackage Autoloader
  10. */
  11. class AutoloadManager {
  12. const FILENAME = 'autoload_data.php';
  13. const KEY_CLASSES = 'classes';
  14. const KEY_SCANNED_DIRS = 'scannedDirs';
  15. /**
  16. * @var \Elgg\ClassLoader
  17. */
  18. protected $loader;
  19. /**
  20. * @var array directories that have already been scanned for classes
  21. */
  22. protected $scannedDirs = array();
  23. /**
  24. * @var bool was data in the manager altered?
  25. */
  26. protected $altered = false;
  27. /**
  28. * @var \ElggCache
  29. */
  30. protected $storage = null;
  31. /**
  32. * Constructor
  33. *
  34. * @param \Elgg\ClassLoader $loader Class loader object
  35. */
  36. public function __construct(\Elgg\ClassLoader $loader) {
  37. $this->loader = $loader;
  38. }
  39. /**
  40. * Add classes found in this directory to the class map and allow classes in
  41. * subdirectories to be found by PSR-0 rules.
  42. *
  43. * We keep track of which dirs were scanned on previous requests so we don't need to
  44. * rescan unless the cache is emptied.
  45. *
  46. * @param string $dir Directory of classes
  47. * @return \Elgg\AutoloadManager
  48. */
  49. public function addClasses($dir) {
  50. if (!in_array($dir, $this->scannedDirs)) {
  51. $map = $this->loader->getClassMap();
  52. $map->mergeMap($this->scanClassesDir($dir));
  53. $this->scannedDirs[] = $dir;
  54. $this->altered = true;
  55. }
  56. $this->loader->addFallback($dir);
  57. return $this;
  58. }
  59. /**
  60. * Scan (non-recursively) a /classes directory for PHP files to map directly to classes.
  61. *
  62. * For BC with Elgg 1.8's autoloader we map these files directly, but besides this
  63. * the autoloader is PSR-0 compatible.
  64. *
  65. * @param string $dir Directory of classes
  66. * @return array
  67. */
  68. protected function scanClassesDir($dir) {
  69. $dir = new \DirectoryIterator($dir);
  70. $map = array();
  71. foreach ($dir as $file) {
  72. /* @var \SplFileInfo $file */
  73. if (!$file->isFile() || !$file->isReadable()) {
  74. continue;
  75. }
  76. $path = $file->getRealPath();
  77. if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
  78. continue;
  79. }
  80. $class = $file->getBasename('.php');
  81. $map[$class] = $path;
  82. }
  83. return $map;
  84. }
  85. /**
  86. * Register the location of a class on the class map
  87. *
  88. * @param string $class Class name
  89. * @param string $path Path of class file
  90. * @return \Elgg\AutoloadManager
  91. */
  92. public function setClassPath($class, $path) {
  93. $this->loader->getClassMap()->setPath($class, $path);
  94. return $this;
  95. }
  96. /**
  97. * If necessary, save necessary state details
  98. *
  99. * @return \Elgg\AutoloadManager
  100. */
  101. public function saveCache() {
  102. if ($this->storage) {
  103. $map = $this->loader->getClassMap();
  104. if ($this->altered || $map->getAltered()) {
  105. $spec[self::KEY_CLASSES] = $map->getMap();
  106. $spec[self::KEY_SCANNED_DIRS] = $this->scannedDirs;
  107. $this->storage->save(self::FILENAME, serialize($spec));
  108. }
  109. }
  110. return $this;
  111. }
  112. /**
  113. * Set the state of the manager from the cache
  114. *
  115. * @return bool was the cache loaded?
  116. */
  117. public function loadCache() {
  118. $spec = $this->getSpec();
  119. if ($spec) {
  120. // the cached class map will have the full scanned core classes, so
  121. // don't consider the earlier mappings as "altering" the map
  122. $this->loader->getClassMap()
  123. ->setMap($spec[self::KEY_CLASSES])
  124. ->setAltered(false);
  125. $this->scannedDirs = $spec[self::KEY_SCANNED_DIRS];
  126. return true;
  127. }
  128. $this->altered = true;
  129. return false;
  130. }
  131. /**
  132. * Some method that does something
  133. *
  134. * @todo what is a spec?
  135. * @return bool|array
  136. */
  137. protected function getSpec() {
  138. if ($this->storage) {
  139. $serialization = $this->storage->load(self::FILENAME);
  140. if ($serialization) {
  141. $spec = unserialize($serialization);
  142. if (isset($spec[self::KEY_CLASSES])) {
  143. return $spec;
  144. }
  145. }
  146. }
  147. return false;
  148. }
  149. /**
  150. * Delete the cache file
  151. *
  152. * @return \Elgg\AutoloadManager
  153. */
  154. public function deleteCache() {
  155. if ($this->storage) {
  156. $this->storage->delete(self::FILENAME);
  157. }
  158. return $this;
  159. }
  160. /**
  161. * Get the class loader
  162. *
  163. * @return \Elgg\ClassLoader
  164. */
  165. public function getLoader() {
  166. return $this->loader;
  167. }
  168. /**
  169. * Set the cache storage object
  170. *
  171. * @param \ElggCache $storage Cache object
  172. * @return void
  173. */
  174. public function setStorage(\ElggCache $storage) {
  175. $this->storage = $storage;
  176. }
  177. }