annotate vendor/symfony/routing/Loader/AnnotationFileLoader.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents af1871eacc83
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 /*
Chris@0 4 * This file is part of the Symfony package.
Chris@0 5 *
Chris@0 6 * (c) Fabien Potencier <fabien@symfony.com>
Chris@0 7 *
Chris@0 8 * For the full copyright and license information, please view the LICENSE
Chris@0 9 * file that was distributed with this source code.
Chris@0 10 */
Chris@0 11
Chris@0 12 namespace Symfony\Component\Routing\Loader;
Chris@0 13
Chris@17 14 use Symfony\Component\Config\FileLocatorInterface;
Chris@17 15 use Symfony\Component\Config\Loader\FileLoader;
Chris@17 16 use Symfony\Component\Config\Resource\FileResource;
Chris@0 17 use Symfony\Component\Routing\RouteCollection;
Chris@0 18
Chris@0 19 /**
Chris@0 20 * AnnotationFileLoader loads routing information from annotations set
Chris@0 21 * on a PHP class and its methods.
Chris@0 22 *
Chris@0 23 * @author Fabien Potencier <fabien@symfony.com>
Chris@0 24 */
Chris@0 25 class AnnotationFileLoader extends FileLoader
Chris@0 26 {
Chris@0 27 protected $loader;
Chris@0 28
Chris@0 29 /**
Chris@0 30 * @throws \RuntimeException
Chris@0 31 */
Chris@0 32 public function __construct(FileLocatorInterface $locator, AnnotationClassLoader $loader)
Chris@0 33 {
Chris@17 34 if (!\function_exists('token_get_all')) {
Chris@0 35 throw new \RuntimeException('The Tokenizer extension is required for the routing annotation loaders.');
Chris@0 36 }
Chris@0 37
Chris@0 38 parent::__construct($locator);
Chris@0 39
Chris@0 40 $this->loader = $loader;
Chris@0 41 }
Chris@0 42
Chris@0 43 /**
Chris@0 44 * Loads from annotations from a file.
Chris@0 45 *
Chris@0 46 * @param string $file A PHP file path
Chris@0 47 * @param string|null $type The resource type
Chris@0 48 *
Chris@0 49 * @return RouteCollection A RouteCollection instance
Chris@0 50 *
Chris@0 51 * @throws \InvalidArgumentException When the file does not exist or its routes cannot be parsed
Chris@0 52 */
Chris@0 53 public function load($file, $type = null)
Chris@0 54 {
Chris@0 55 $path = $this->locator->locate($file);
Chris@0 56
Chris@0 57 $collection = new RouteCollection();
Chris@0 58 if ($class = $this->findClass($path)) {
Chris@18 59 $refl = new \ReflectionClass($class);
Chris@18 60 if ($refl->isAbstract()) {
Chris@18 61 return;
Chris@18 62 }
Chris@18 63
Chris@0 64 $collection->addResource(new FileResource($path));
Chris@0 65 $collection->addCollection($this->loader->load($class, $type));
Chris@0 66 }
Chris@12 67 if (\PHP_VERSION_ID >= 70000) {
Chris@0 68 // PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
Chris@0 69 gc_mem_caches();
Chris@0 70 }
Chris@0 71
Chris@0 72 return $collection;
Chris@0 73 }
Chris@0 74
Chris@0 75 /**
Chris@0 76 * {@inheritdoc}
Chris@0 77 */
Chris@0 78 public function supports($resource, $type = null)
Chris@0 79 {
Chris@17 80 return \is_string($resource) && 'php' === pathinfo($resource, PATHINFO_EXTENSION) && (!$type || 'annotation' === $type);
Chris@0 81 }
Chris@0 82
Chris@0 83 /**
Chris@0 84 * Returns the full class name for the first class in the file.
Chris@0 85 *
Chris@0 86 * @param string $file A PHP file path
Chris@0 87 *
Chris@0 88 * @return string|false Full class name if found, false otherwise
Chris@0 89 */
Chris@0 90 protected function findClass($file)
Chris@0 91 {
Chris@0 92 $class = false;
Chris@0 93 $namespace = false;
Chris@0 94 $tokens = token_get_all(file_get_contents($file));
Chris@0 95
Chris@17 96 if (1 === \count($tokens) && T_INLINE_HTML === $tokens[0][0]) {
Chris@0 97 throw new \InvalidArgumentException(sprintf('The file "%s" does not contain PHP code. Did you forgot to add the "<?php" start tag at the beginning of the file?', $file));
Chris@0 98 }
Chris@0 99
Chris@0 100 for ($i = 0; isset($tokens[$i]); ++$i) {
Chris@0 101 $token = $tokens[$i];
Chris@0 102
Chris@0 103 if (!isset($token[1])) {
Chris@0 104 continue;
Chris@0 105 }
Chris@0 106
Chris@0 107 if (true === $class && T_STRING === $token[0]) {
Chris@0 108 return $namespace.'\\'.$token[1];
Chris@0 109 }
Chris@0 110
Chris@0 111 if (true === $namespace && T_STRING === $token[0]) {
Chris@0 112 $namespace = $token[1];
Chris@17 113 while (isset($tokens[++$i][1]) && \in_array($tokens[$i][0], [T_NS_SEPARATOR, T_STRING])) {
Chris@0 114 $namespace .= $tokens[$i][1];
Chris@0 115 }
Chris@0 116 $token = $tokens[$i];
Chris@0 117 }
Chris@0 118
Chris@0 119 if (T_CLASS === $token[0]) {
Chris@14 120 // Skip usage of ::class constant and anonymous classes
Chris@14 121 $skipClassToken = false;
Chris@0 122 for ($j = $i - 1; $j > 0; --$j) {
Chris@0 123 if (!isset($tokens[$j][1])) {
Chris@0 124 break;
Chris@0 125 }
Chris@0 126
Chris@14 127 if (T_DOUBLE_COLON === $tokens[$j][0] || T_NEW === $tokens[$j][0]) {
Chris@14 128 $skipClassToken = true;
Chris@0 129 break;
Chris@17 130 } elseif (!\in_array($tokens[$j][0], [T_WHITESPACE, T_DOC_COMMENT, T_COMMENT])) {
Chris@0 131 break;
Chris@0 132 }
Chris@0 133 }
Chris@0 134
Chris@14 135 if (!$skipClassToken) {
Chris@0 136 $class = true;
Chris@0 137 }
Chris@0 138 }
Chris@0 139
Chris@0 140 if (T_NAMESPACE === $token[0]) {
Chris@0 141 $namespace = true;
Chris@0 142 }
Chris@0 143 }
Chris@0 144
Chris@0 145 return false;
Chris@0 146 }
Chris@0 147 }