Security update for Core, with self-updated composer
[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
96         if (1 === count($tokens) && T_INLINE_HTML === $tokens[0][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));
98         }
99
100         for ($i = 0; isset($tokens[$i]); ++$i) {
101             $token = $tokens[$i];
102
103             if (!isset($token[1])) {
104                 continue;
105             }
106
107             if (true === $class && T_STRING === $token[0]) {
108                 return $namespace.'\\'.$token[1];
109             }
110
111             if (true === $namespace && T_STRING === $token[0]) {
112                 $namespace = $token[1];
113                 while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_NS_SEPARATOR, T_STRING))) {
114                     $namespace .= $tokens[$i][1];
115                 }
116                 $token = $tokens[$i];
117             }
118
119             if (T_CLASS === $token[0]) {
120                 // Skip usage of ::class constant
121                 $isClassConstant = false;
122                 for ($j = $i - 1; $j > 0; --$j) {
123                     if (!isset($tokens[$j][1])) {
124                         break;
125                     }
126
127                     if (T_DOUBLE_COLON === $tokens[$j][0]) {
128                         $isClassConstant = true;
129                         break;
130                     } elseif (!in_array($tokens[$j][0], array(T_WHITESPACE, T_DOC_COMMENT, T_COMMENT))) {
131                         break;
132                     }
133                 }
134
135                 if (!$isClassConstant) {
136                     $class = true;
137                 }
138             }
139
140             if (T_NAMESPACE === $token[0]) {
141                 $namespace = true;
142             }
143         }
144
145         return false;
146     }
147 }