/sites/all/modules/xautoload/lib/ClassFinder/GenericPrefixMap.php

https://gitlab.com/bossagna/meik · PHP · 241 lines · 110 code · 23 blank · 108 comment · 15 complexity · 2aaace6a7945eb306a46aabafb9a26e9 MD5 · raw file

  1. <?php
  2. namespace Drupal\xautoload\ClassFinder;
  3. use Drupal\xautoload\DirectoryBehavior\DirectoryBehaviorInterface;
  4. use Drupal\xautoload\ClassFinder\InjectedApi\LoadClassInjectedAPI;
  5. use Drupal\xautoload\ClassFinder\InjectedApi\InjectedApiInterface;
  6. use Drupal\xautoload\DirectoryBehavior\DefaultDirectoryBehavior;
  7. use xautoload_FinderPlugin_Interface;
  8. use Drupal\xautoload\DirectoryBehavior\Psr0DirectoryBehavior;
  9. /**
  10. * Helper class for the class finder.
  11. * This is not part of ClassFinder, because we want to use the same logic for
  12. * namespaces (PSR-0) and prefixes (PEAR).
  13. *
  14. * This thing does not actually deal with class names, but with transformed
  15. * paths.
  16. *
  17. * Example A:
  18. * When looking for a class \Aaa\Bbb\Ccc_Ddd, the class finder will
  19. * 1. Determine that this class is within a namespace.
  20. * 2. Transform that into "Aaa/Bbb/Ccc/Ddd.php".
  21. * 3. Check if the namespace map evaluator has anything registered for
  22. * 3.1. "Aaa/Bbb/"
  23. * 3.2. "Aaa/"
  24. * 3.3. ""
  25. *
  26. * Example A:
  27. * When looking for a class Aaa_Bbb_Ccc, the class finder will
  28. * 1. Determine that this class is NOT within a namespace.
  29. * 2. Check if a file is explicitly registered for the class itself.
  30. * 3. Transform the class name into "Aaa/Bbb/Ccc.php".
  31. * 4. Check if the prefix map evaluator has anything registered for
  32. * 4.1. "Aaa/Bbb/"
  33. * 4.2. "Aaa/"
  34. * 4.3. ""
  35. */
  36. class GenericPrefixMap {
  37. /**
  38. * @var array[]
  39. */
  40. protected $paths = array();
  41. /**
  42. * @var string
  43. * Either '\\' or '_'.
  44. */
  45. protected $separator;
  46. /**
  47. * @param string $separator
  48. */
  49. function __construct($separator) {
  50. $this->separator = $separator;
  51. }
  52. /**
  53. * If a class file would be in
  54. * $psr0_root . '/' . $path_fragment . $path_suffix
  55. * then instead, we look in
  56. * $deep_path . $path_suffix
  57. *
  58. * @param string $logical_base_path
  59. * The would-be namespace path relative to PSR-0 root.
  60. * That is, the namespace with '\\' replaced by '/'.
  61. * @param string $deep_path
  62. * The filesystem location of the (PSR-0) subfolder for the given namespace.
  63. * @param DirectoryBehaviorInterface $behavior
  64. * Behavior in this directory.
  65. */
  66. function registerDeepPath($logical_base_path, $deep_path, $behavior) {
  67. $this->paths[$logical_base_path][$deep_path] = $behavior;
  68. }
  69. /**
  70. * @param string $logical_base_path
  71. * The would-be namespace path relative to PSR-0 root.
  72. * That is, the namespace with '\\' replaced by '/'.
  73. * @param string $deep_path
  74. * The filesystem location of the (PSR-0) subfolder for the given namespace.
  75. * @param DirectoryBehaviorInterface $behavior
  76. * Behavior in this directory.
  77. */
  78. function prependDeepPath($logical_base_path, $deep_path, $behavior) {
  79. $this->paths[$logical_base_path]
  80. = isset($this->paths[$logical_base_path])
  81. ? array($deep_path => $behavior) + $this->paths[$logical_base_path]
  82. : array($deep_path => $behavior);
  83. }
  84. /**
  85. * Register a bunch of those paths ..
  86. *
  87. * @param array[] $map
  88. *
  89. * @throws \Exception
  90. */
  91. function registerDeepPaths(array $map) {
  92. foreach ($map as $key => $paths) {
  93. if (isset($this->paths[$key])) {
  94. $paths += $this->paths[$key];
  95. }
  96. $this->paths[$key] = $paths;
  97. }
  98. }
  99. /**
  100. * Delete a registered path mapping.
  101. *
  102. * @param string $logical_base_path
  103. * @param string $deep_path
  104. */
  105. function unregisterDeepPath($logical_base_path, $deep_path) {
  106. unset($this->paths[$logical_base_path][$deep_path]);
  107. }
  108. /**
  109. * @param string $class
  110. * @param string $logical_path
  111. * Class name translated into a logical path, either with PSR-4 or with PEAR
  112. * translation rules.
  113. * @param int|bool $lastpos
  114. * Position of the last directory separator in $logical_path.
  115. * FALSE, if there is no directory separator in $logical_path.
  116. *
  117. * @return bool|NULL
  118. * TRUE, if the class was found.
  119. */
  120. function loadClass($class, $logical_path, $lastpos) {
  121. $pos = $lastpos;
  122. while (TRUE) {
  123. $logical_base_path = (FALSE === $pos)
  124. ? ''
  125. : substr($logical_path, 0, $pos + 1);
  126. if (isset($this->paths[$logical_base_path])) {
  127. foreach ($this->paths[$logical_base_path] as $dir => $behavior) {
  128. if ($behavior instanceof DefaultDirectoryBehavior) {
  129. // PSR-4 and PEAR
  130. if (file_exists($file = $dir . substr($logical_path, $pos + 1))) {
  131. require $file;
  132. return TRUE;
  133. }
  134. }
  135. elseif ($behavior instanceof Psr0DirectoryBehavior) {
  136. // PSR-0
  137. if (file_exists(
  138. $file = $dir
  139. . substr($logical_path, $pos + 1, $lastpos - $pos)
  140. . str_replace('_', '/', substr($logical_path, $lastpos + 1))
  141. )) {
  142. require $file;
  143. return TRUE;
  144. }
  145. }
  146. elseif ($behavior instanceof xautoload_FinderPlugin_Interface) {
  147. // Legacy "FinderPlugin".
  148. $api = new LoadClassInjectedAPI($class);
  149. if ($behavior->findFile($api, $logical_base_path, substr($logical_path, $pos + 1), $dir)) {
  150. return TRUE;
  151. }
  152. }
  153. }
  154. }
  155. // Continue with parent fragment.
  156. if (FALSE === $pos) {
  157. return NULL;
  158. }
  159. $pos = strrpos($logical_base_path, '/', -2);
  160. }
  161. return NULL;
  162. }
  163. /**
  164. * Find the file for a class that in PSR-0 or PEAR would be in
  165. * $psr_0_root . '/' . $path_fragment . $path_suffix
  166. *
  167. * @param InjectedApiInterface $api
  168. * @param string $logical_path
  169. * Class name translated into a logical path, either with PSR-4 or with PEAR
  170. * translation rules.
  171. * @param int|bool $lastpos
  172. * Position of the last directory separator in $logical_path.
  173. * FALSE, if there is no directory separator in $logical_path.
  174. *
  175. * @return bool|NULL
  176. * TRUE, if the class was found.
  177. */
  178. function apiFindFile($api, $logical_path, $lastpos) {
  179. $pos = $lastpos;
  180. while (TRUE) {
  181. $logical_base_path = (FALSE === $pos)
  182. ? ''
  183. : substr($logical_path, 0, $pos + 1);
  184. if (isset($this->paths[$logical_base_path])) {
  185. foreach ($this->paths[$logical_base_path] as $dir => $behavior) {
  186. if ($behavior instanceof DefaultDirectoryBehavior) {
  187. // PSR-4 and PEAR
  188. if ($api->suggestFile($dir . substr($logical_path, $pos + 1))) {
  189. return TRUE;
  190. }
  191. }
  192. elseif ($behavior instanceof Psr0DirectoryBehavior) {
  193. // PSR-0
  194. if ($api->suggestFile(
  195. $dir
  196. . substr($logical_path, $pos + 1, $lastpos - $pos)
  197. . str_replace('_', '/', substr($logical_path, $lastpos + 1))
  198. )) {
  199. return TRUE;
  200. }
  201. }
  202. elseif ($behavior instanceof xautoload_FinderPlugin_Interface) {
  203. // Legacy "FinderPlugin".
  204. if ($behavior->findFile($api, $logical_base_path, substr($logical_path, $pos + 1), $dir)) {
  205. return TRUE;
  206. }
  207. }
  208. }
  209. }
  210. // Continue with parent fragment.
  211. if (FALSE === $pos) {
  212. return NULL;
  213. }
  214. $pos = strrpos($logical_base_path, '/', -2);
  215. }
  216. return NULL;
  217. }
  218. }