51
51
* {
52
52
* }
53
53
* }
54
+ *
55
+ * On PHP 8, the annotation class can be used as an attribute as well:
56
+ * #[Route('/Blog')]
57
+ * class Blog
58
+ * {
59
+ * #[Route('/', name: 'blog_index')]
60
+ * public function index()
61
+ * {
62
+ * }
63
+ * #[Route('/{id}', name: 'blog_post', requirements: ["id" => '\d+'])]
64
+ * public function show()
65
+ * {
66
+ * }
67
+ * }
68
+
54
69
*
55
70
* @author Fabien Potencier <fabien@symfony.com>
71
+ * @author Alexander M. Turek <me@derrabus.de>
56
72
*/
57
73
abstract class AnnotationClassLoader implements LoaderInterface
58
74
{
@@ -61,14 +77,14 @@ abstract class AnnotationClassLoader implements LoaderInterface
61
77
/**
62
78
* @var string
63
79
*/
64
- protected $ routeAnnotationClass = ' Symfony \\ Component \\ Routing \\ Annotation \\ Route ' ;
80
+ protected $ routeAnnotationClass = RouteAnnotation::class ;
65
81
66
82
/**
67
83
* @var int
68
84
*/
69
85
protected $ defaultRouteIndex = 0 ;
70
86
71
- public function __construct (Reader $ reader )
87
+ public function __construct (Reader $ reader = null )
72
88
{
73
89
$ this ->reader = $ reader ;
74
90
}
@@ -108,19 +124,15 @@ public function load($class, string $type = null)
108
124
109
125
foreach ($ class ->getMethods () as $ method ) {
110
126
$ this ->defaultRouteIndex = 0 ;
111
- foreach ($ this ->reader ->getMethodAnnotations ($ method ) as $ annot ) {
112
- if ($ annot instanceof $ this ->routeAnnotationClass ) {
113
- $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
114
- }
127
+ foreach ($ this ->getAnnotations ($ method ) as $ annot ) {
128
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
115
129
}
116
130
}
117
131
118
132
if (0 === $ collection ->count () && $ class ->hasMethod ('__invoke ' )) {
119
133
$ globals = $ this ->resetGlobals ();
120
- foreach ($ this ->reader ->getClassAnnotations ($ class ) as $ annot ) {
121
- if ($ annot instanceof $ this ->routeAnnotationClass ) {
122
- $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
123
- }
134
+ foreach ($ this ->getAnnotations ($ class ) as $ annot ) {
135
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
124
136
}
125
137
}
126
138
@@ -130,7 +142,7 @@ public function load($class, string $type = null)
130
142
/**
131
143
* @param RouteAnnotation $annot or an object that exposes a similar interface
132
144
*/
133
- protected function addRoute (RouteCollection $ collection , $ annot , array $ globals , \ReflectionClass $ class , \ReflectionMethod $ method )
145
+ protected function addRoute (RouteCollection $ collection , object $ annot , array $ globals , \ReflectionClass $ class , \ReflectionMethod $ method )
134
146
{
135
147
$ name = $ annot ->getName ();
136
148
if (null === $ name ) {
@@ -257,7 +269,15 @@ protected function getGlobals(\ReflectionClass $class)
257
269
{
258
270
$ globals = $ this ->resetGlobals ();
259
271
260
- if ($ annot = $ this ->reader ->getClassAnnotation ($ class , $ this ->routeAnnotationClass )) {
272
+ $ annot = null ;
273
+ if (\PHP_VERSION_ID >= 80000 && ($ attribute = $ class ->getAttributes ($ this ->routeAnnotationClass )[0 ] ?? null )) {
274
+ $ annot = $ attribute ->newInstance ();
275
+ }
276
+ if (!$ annot && $ this ->reader ) {
277
+ $ annot = $ this ->reader ->getClassAnnotation ($ class , $ this ->routeAnnotationClass );
278
+ }
279
+
280
+ if ($ annot ) {
261
281
if (null !== $ annot ->getName ()) {
262
282
$ globals ['name ' ] = $ annot ->getName ();
263
283
}
@@ -330,5 +350,33 @@ protected function createRoute(string $path, array $defaults, array $requirement
330
350
return new Route ($ path , $ defaults , $ requirements , $ options , $ host , $ schemes , $ methods , $ condition );
331
351
}
332
352
333
- abstract protected function configureRoute (Route $ route , \ReflectionClass $ class , \ReflectionMethod $ method , $ annot );
353
+ abstract protected function configureRoute (Route $ route , \ReflectionClass $ class , \ReflectionMethod $ method , object $ annot );
354
+
355
+ /**
356
+ * @param \ReflectionClass|\ReflectionMethod $reflection
357
+ *
358
+ * @return iterable|RouteAnnotation[]
359
+ */
360
+ private function getAnnotations (object $ reflection ): iterable
361
+ {
362
+ if (\PHP_VERSION_ID >= 80000 ) {
363
+ foreach ($ reflection ->getAttributes ($ this ->routeAnnotationClass ) as $ attribute ) {
364
+ yield $ attribute ->newInstance ();
365
+ }
366
+ }
367
+
368
+ if (!$ this ->reader ) {
369
+ return ;
370
+ }
371
+
372
+ $ anntotations = $ reflection instanceof \ReflectionClass
373
+ ? $ this ->reader ->getClassAnnotations ($ reflection )
374
+ : $ this ->reader ->getMethodAnnotations ($ reflection );
375
+
376
+ foreach ($ anntotations as $ annotation ) {
377
+ if ($ annotation instanceof $ this ->routeAnnotationClass ) {
378
+ yield $ annotation ;
379
+ }
380
+ }
381
+ }
334
382
}
0 commit comments