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