Updated Drupal to 8.6. This goes with the following updates because it's possible...
[yaffs-website] / vendor / symfony / routing / Loader / AnnotationClassLoader.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 Doctrine\Common\Annotations\Reader;
15 use Symfony\Component\Config\Loader\LoaderInterface;
16 use Symfony\Component\Config\Loader\LoaderResolverInterface;
17 use Symfony\Component\Config\Resource\FileResource;
18 use Symfony\Component\Routing\Route;
19 use Symfony\Component\Routing\RouteCollection;
20
21 /**
22  * AnnotationClassLoader loads routing information from a PHP class and its methods.
23  *
24  * You need to define an implementation for the getRouteDefaults() method. Most of the
25  * time, this method should define some PHP callable to be called for the route
26  * (a controller in MVC speak).
27  *
28  * The @Route annotation can be set on the class (for global parameters),
29  * and on each method.
30  *
31  * The @Route annotation main value is the route path. The annotation also
32  * recognizes several parameters: requirements, options, defaults, schemes,
33  * methods, host, and name. The name parameter is mandatory.
34  * Here is an example of how you should be able to use it:
35  *
36  *     /**
37  *      * @Route("/Blog")
38  *      * /
39  *     class Blog
40  *     {
41  *         /**
42  *          * @Route("/", name="blog_index")
43  *          * /
44  *         public function index()
45  *         {
46  *         }
47  *
48  *         /**
49  *          * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
50  *          * /
51  *         public function show()
52  *         {
53  *         }
54  *     }
55  *
56  * @author Fabien Potencier <fabien@symfony.com>
57  */
58 abstract class AnnotationClassLoader implements LoaderInterface
59 {
60     protected $reader;
61
62     /**
63      * @var string
64      */
65     protected $routeAnnotationClass = 'Symfony\\Component\\Routing\\Annotation\\Route';
66
67     /**
68      * @var int
69      */
70     protected $defaultRouteIndex = 0;
71
72     public function __construct(Reader $reader)
73     {
74         $this->reader = $reader;
75     }
76
77     /**
78      * Sets the annotation class to read route properties from.
79      *
80      * @param string $class A fully-qualified class name
81      */
82     public function setRouteAnnotationClass($class)
83     {
84         $this->routeAnnotationClass = $class;
85     }
86
87     /**
88      * Loads from annotations from a class.
89      *
90      * @param string      $class A class name
91      * @param string|null $type  The resource type
92      *
93      * @return RouteCollection A RouteCollection instance
94      *
95      * @throws \InvalidArgumentException When route can't be parsed
96      */
97     public function load($class, $type = null)
98     {
99         if (!class_exists($class)) {
100             throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
101         }
102
103         $class = new \ReflectionClass($class);
104         if ($class->isAbstract()) {
105             throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName()));
106         }
107
108         $globals = $this->getGlobals($class);
109
110         $collection = new RouteCollection();
111         $collection->addResource(new FileResource($class->getFileName()));
112
113         foreach ($class->getMethods() as $method) {
114             $this->defaultRouteIndex = 0;
115             foreach ($this->reader->getMethodAnnotations($method) as $annot) {
116                 if ($annot instanceof $this->routeAnnotationClass) {
117                     $this->addRoute($collection, $annot, $globals, $class, $method);
118                 }
119             }
120         }
121
122         if (0 === $collection->count() && $class->hasMethod('__invoke')) {
123             foreach ($this->reader->getClassAnnotations($class) as $annot) {
124                 if ($annot instanceof $this->routeAnnotationClass) {
125                     $globals['path'] = '';
126                     $globals['name'] = '';
127
128                     $this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke'));
129                 }
130             }
131         }
132
133         return $collection;
134     }
135
136     protected function addRoute(RouteCollection $collection, $annot, $globals, \ReflectionClass $class, \ReflectionMethod $method)
137     {
138         $name = $annot->getName();
139         if (null === $name) {
140             $name = $this->getDefaultRouteName($class, $method);
141         }
142         $name = $globals['name'].$name;
143
144         $defaults = array_replace($globals['defaults'], $annot->getDefaults());
145         foreach ($method->getParameters() as $param) {
146             if (false !== strpos($globals['path'].$annot->getPath(), sprintf('{%s}', $param->getName())) && !isset($defaults[$param->getName()]) && $param->isDefaultValueAvailable()) {
147                 $defaults[$param->getName()] = $param->getDefaultValue();
148             }
149         }
150         $requirements = array_replace($globals['requirements'], $annot->getRequirements());
151         $options = array_replace($globals['options'], $annot->getOptions());
152         $schemes = array_merge($globals['schemes'], $annot->getSchemes());
153         $methods = array_merge($globals['methods'], $annot->getMethods());
154
155         $host = $annot->getHost();
156         if (null === $host) {
157             $host = $globals['host'];
158         }
159
160         $condition = $annot->getCondition();
161         if (null === $condition) {
162             $condition = $globals['condition'];
163         }
164
165         $route = $this->createRoute($globals['path'].$annot->getPath(), $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
166
167         $this->configureRoute($route, $class, $method, $annot);
168
169         $collection->add($name, $route);
170     }
171
172     /**
173      * {@inheritdoc}
174      */
175     public function supports($resource, $type = null)
176     {
177         return \is_string($resource) && preg_match('/^(?:\\\\?[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)+$/', $resource) && (!$type || 'annotation' === $type);
178     }
179
180     /**
181      * {@inheritdoc}
182      */
183     public function setResolver(LoaderResolverInterface $resolver)
184     {
185     }
186
187     /**
188      * {@inheritdoc}
189      */
190     public function getResolver()
191     {
192     }
193
194     /**
195      * Gets the default route name for a class method.
196      *
197      * @param \ReflectionClass  $class
198      * @param \ReflectionMethod $method
199      *
200      * @return string
201      */
202     protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMethod $method)
203     {
204         $name = strtolower(str_replace('\\', '_', $class->name).'_'.$method->name);
205         if ($this->defaultRouteIndex > 0) {
206             $name .= '_'.$this->defaultRouteIndex;
207         }
208         ++$this->defaultRouteIndex;
209
210         return $name;
211     }
212
213     protected function getGlobals(\ReflectionClass $class)
214     {
215         $globals = array(
216             'path' => '',
217             'requirements' => array(),
218             'options' => array(),
219             'defaults' => array(),
220             'schemes' => array(),
221             'methods' => array(),
222             'host' => '',
223             'condition' => '',
224             'name' => '',
225         );
226
227         if ($annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass)) {
228             if (null !== $annot->getName()) {
229                 $globals['name'] = $annot->getName();
230             }
231
232             if (null !== $annot->getPath()) {
233                 $globals['path'] = $annot->getPath();
234             }
235
236             if (null !== $annot->getRequirements()) {
237                 $globals['requirements'] = $annot->getRequirements();
238             }
239
240             if (null !== $annot->getOptions()) {
241                 $globals['options'] = $annot->getOptions();
242             }
243
244             if (null !== $annot->getDefaults()) {
245                 $globals['defaults'] = $annot->getDefaults();
246             }
247
248             if (null !== $annot->getSchemes()) {
249                 $globals['schemes'] = $annot->getSchemes();
250             }
251
252             if (null !== $annot->getMethods()) {
253                 $globals['methods'] = $annot->getMethods();
254             }
255
256             if (null !== $annot->getHost()) {
257                 $globals['host'] = $annot->getHost();
258             }
259
260             if (null !== $annot->getCondition()) {
261                 $globals['condition'] = $annot->getCondition();
262             }
263         }
264
265         return $globals;
266     }
267
268     protected function createRoute($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition)
269     {
270         return new Route($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
271     }
272
273     abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, $annot);
274 }