PageRenderTime 40ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/phpspec/phpspec/src/PhpSpec/Locator/PSR0/PSR0Locator.php

https://gitlab.com/judielsm/Handora
PHP | 349 lines | 238 code | 36 blank | 75 comment | 19 complexity | 7483f48de6338e2d423282281f471582 MD5 | raw file
  1. <?php
  2. /*
  3. * This file is part of PhpSpec, A php toolset to drive emergent
  4. * design by specification.
  5. *
  6. * (c) Marcello Duarte <marcello.duarte@gmail.com>
  7. * (c) Konstantin Kudryashov <ever.zet@gmail.com>
  8. *
  9. * For the full copyright and license information, please view the LICENSE
  10. * file that was distributed with this source code.
  11. */
  12. namespace PhpSpec\Locator\PSR0;
  13. use PhpSpec\Locator\ResourceInterface;
  14. use PhpSpec\Locator\ResourceLocatorInterface;
  15. use PhpSpec\Util\Filesystem;
  16. use InvalidArgumentException;
  17. class PSR0Locator implements ResourceLocatorInterface
  18. {
  19. /**
  20. * @var string
  21. */
  22. private $srcPath;
  23. /**
  24. * @var string
  25. */
  26. private $specPath;
  27. /**
  28. * @var string
  29. */
  30. private $srcNamespace;
  31. /**
  32. * @var string
  33. */
  34. private $specNamespace;
  35. /**
  36. * @var string
  37. */
  38. private $fullSrcPath;
  39. /**
  40. * @var string
  41. */
  42. private $fullSpecPath;
  43. /**
  44. * @var \PhpSpec\Util\Filesystem
  45. */
  46. private $filesystem;
  47. /**
  48. * @var string
  49. */
  50. private $psr4Prefix;
  51. /**
  52. * @param string $srcNamespace
  53. * @param string $specNamespacePrefix
  54. * @param string $srcPath
  55. * @param string $specPath
  56. * @param Filesystem $filesystem
  57. */
  58. public function __construct(
  59. $srcNamespace = '',
  60. $specNamespacePrefix = 'spec',
  61. $srcPath = 'src',
  62. $specPath = '.',
  63. Filesystem $filesystem = null,
  64. $psr4Prefix = null
  65. ) {
  66. $this->filesystem = $filesystem ?: new Filesystem();
  67. $sepr = DIRECTORY_SEPARATOR;
  68. $this->srcPath = rtrim(realpath($srcPath), '/\\').$sepr;
  69. $this->specPath = rtrim(realpath($specPath), '/\\').$sepr;
  70. $this->srcNamespace = ltrim(trim($srcNamespace, ' \\').'\\', '\\');
  71. $this->psr4Prefix = (null === $psr4Prefix) ? null : ltrim(trim($psr4Prefix, ' \\').'\\', '\\');
  72. if (null !== $this->psr4Prefix && substr($this->srcNamespace, 0, strlen($psr4Prefix)) !== $psr4Prefix) {
  73. throw new InvalidArgumentException('PSR4 prefix doesn\'t match given class namespace.'.PHP_EOL);
  74. }
  75. $srcNamespacePath = null === $this->psr4Prefix ?
  76. $this->srcNamespace :
  77. substr($this->srcNamespace, strlen($this->psr4Prefix));
  78. $this->specNamespace = trim($specNamespacePrefix, ' \\').'\\'.$this->srcNamespace;
  79. $specNamespacePath = trim($specNamespacePrefix, ' \\').'\\'.$srcNamespacePath;
  80. $this->fullSrcPath = $this->srcPath.str_replace('\\', $sepr, $srcNamespacePath);
  81. $this->fullSpecPath = $this->specPath.str_replace('\\', $sepr, $specNamespacePath);
  82. if ($sepr === $this->srcPath) {
  83. throw new InvalidArgumentException(sprintf(
  84. 'Source code path should be existing filesystem path, but "%s" given.',
  85. $srcPath
  86. ));
  87. }
  88. if ($sepr === $this->specPath) {
  89. throw new InvalidArgumentException(sprintf(
  90. 'Specs code path should be existing filesystem path, but "%s" given.',
  91. $specPath
  92. ));
  93. }
  94. }
  95. /**
  96. * @return string
  97. */
  98. public function getFullSrcPath()
  99. {
  100. return $this->fullSrcPath;
  101. }
  102. /**
  103. * @return string
  104. */
  105. public function getFullSpecPath()
  106. {
  107. return $this->fullSpecPath;
  108. }
  109. /**
  110. * @return string
  111. */
  112. public function getSrcNamespace()
  113. {
  114. return $this->srcNamespace;
  115. }
  116. /**
  117. * @return string
  118. */
  119. public function getSpecNamespace()
  120. {
  121. return $this->specNamespace;
  122. }
  123. /**
  124. * @return ResourceInterface[]
  125. */
  126. public function getAllResources()
  127. {
  128. return $this->findSpecResources($this->fullSpecPath);
  129. }
  130. /**
  131. * @param string $query
  132. *
  133. * @return bool
  134. */
  135. public function supportsQuery($query)
  136. {
  137. $sepr = DIRECTORY_SEPARATOR;
  138. $path = rtrim(realpath(str_replace(array('\\', '/'), $sepr, $query)), $sepr);
  139. if (null === $path) {
  140. return false;
  141. }
  142. return 0 === strpos($path, $this->srcPath)
  143. || 0 === strpos($path, $this->specPath)
  144. ;
  145. }
  146. /**
  147. * @param string $query
  148. *
  149. * @return ResourceInterface[]
  150. */
  151. public function findResources($query)
  152. {
  153. $sepr = DIRECTORY_SEPARATOR;
  154. $path = rtrim(realpath(str_replace(array('\\', '/'), $sepr, $query)), $sepr);
  155. if ('.php' !== substr($path, -4)) {
  156. $path .= $sepr;
  157. }
  158. if ($path && 0 === strpos($path, $this->fullSrcPath)) {
  159. $path = $this->fullSpecPath.substr($path, strlen($this->fullSrcPath));
  160. $path = preg_replace('/\.php/', 'Spec.php', $path);
  161. return $this->findSpecResources($path);
  162. }
  163. if ($path && 0 === strpos($path, $this->srcPath)) {
  164. $path = $this->fullSpecPath.substr($path, strlen($this->srcPath));
  165. $path = preg_replace('/\.php/', 'Spec.php', $path);
  166. return $this->findSpecResources($path);
  167. }
  168. if ($path && 0 === strpos($path, $this->specPath)) {
  169. return $this->findSpecResources($path);
  170. }
  171. return array();
  172. }
  173. /**
  174. * @param string $classname
  175. *
  176. * @return bool
  177. */
  178. public function supportsClass($classname)
  179. {
  180. $classname = str_replace('/', '\\', $classname);
  181. return '' === $this->srcNamespace
  182. || 0 === strpos($classname, $this->srcNamespace)
  183. || 0 === strpos($classname, $this->specNamespace)
  184. ;
  185. }
  186. /**
  187. * @param string $classname
  188. *
  189. * @return null|PSR0Resource
  190. */
  191. public function createResource($classname)
  192. {
  193. $this->validatePsr0Classname($classname);
  194. $classname = str_replace('/', '\\', $classname);
  195. if (0 === strpos($classname, $this->specNamespace)) {
  196. $relative = substr($classname, strlen($this->specNamespace));
  197. return new PSR0Resource(explode('\\', $relative), $this);
  198. }
  199. if ('' === $this->srcNamespace || 0 === strpos($classname, $this->srcNamespace)) {
  200. $relative = substr($classname, strlen($this->srcNamespace));
  201. return new PSR0Resource(explode('\\', $relative), $this);
  202. }
  203. return null;
  204. }
  205. /**
  206. * @return int
  207. */
  208. public function getPriority()
  209. {
  210. return 0;
  211. }
  212. /**
  213. * @param string $path
  214. *
  215. * @return PSR0Resource[]
  216. */
  217. protected function findSpecResources($path)
  218. {
  219. if (!$this->filesystem->pathExists($path)) {
  220. return array();
  221. }
  222. if ('.php' === substr($path, -4)) {
  223. return array($this->createResourceFromSpecFile(realpath($path)));
  224. }
  225. $resources = array();
  226. foreach ($this->filesystem->findSpecFilesIn($path) as $file) {
  227. $resources[] = $this->createResourceFromSpecFile($file->getRealPath());
  228. }
  229. return $resources;
  230. }
  231. private function findSpecClassname($path)
  232. {
  233. // Find namespace and class name
  234. $namespace = '';
  235. $content = $this->filesystem->getFileContents($path);
  236. $tokens = token_get_all($content);
  237. $count = count($tokens);
  238. for ($i = 0; $i < $count; $i++) {
  239. if ($tokens[$i][0] === T_NAMESPACE) {
  240. for ($j = $i + 1; $j < $count; $j++) {
  241. if ($tokens[$j][0] === T_STRING) {
  242. $namespace .= $tokens[$j][1].'\\';
  243. } elseif ($tokens[$j] === '{' || $tokens[$j] === ';') {
  244. break;
  245. }
  246. }
  247. }
  248. if ($tokens[$i][0] === T_CLASS) {
  249. for ($j = $i+1; $j < $count; $j++) {
  250. if ($tokens[$j] === '{') {
  251. return $namespace.$tokens[$i+2][1];
  252. }
  253. }
  254. }
  255. }
  256. // No class found
  257. return null;
  258. }
  259. /**
  260. * @param string $path
  261. *
  262. * @return PSR0Resource
  263. */
  264. private function createResourceFromSpecFile($path)
  265. {
  266. $classname = $this->findSpecClassname($path);
  267. if (null === $classname) {
  268. throw new \RuntimeException('Spec file does not contains any class definition.');
  269. }
  270. // Remove spec namespace from the begining of the classname.
  271. $specNamespace = trim($this->getSpecNamespace(), '\\').'\\';
  272. if (0 !== strpos($classname, $specNamespace)) {
  273. throw new \RuntimeException(sprintf(
  274. 'Spec class `%s` must be in the base spec namespace `%s`.',
  275. $classname,
  276. $this->getSpecNamespace()
  277. ));
  278. }
  279. $classname = substr($classname, strlen($specNamespace));
  280. // cut "Spec" from the end
  281. $classname = preg_replace('/Spec$/', '', $classname);
  282. // Create the resource
  283. return new PSR0Resource(explode('\\', $classname), $this);
  284. }
  285. private function validatePsr0Classname($classname)
  286. {
  287. $pattern = '/^([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*[\/\\\\]?)*[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/';
  288. if (!preg_match($pattern, $classname)) {
  289. throw new InvalidArgumentException(
  290. sprintf('String "%s" is not a valid class name.', $classname).PHP_EOL.
  291. 'Please see reference document: '.
  292. 'https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md'
  293. );
  294. }
  295. }
  296. }