26
26
* time, this method should define some PHP callable to be called for the route
27
27
* (a controller in MVC speak).
28
28
*
29
- * The @ Route annotation can be set on the class (for global parameters),
29
+ * The #[ Route] attribute can be set on the class (for global parameters),
30
30
* and on each method.
31
31
*
32
- * The @ Route annotation main value is the route path. The annotation also
32
+ * The #[ Route] attribute main value is the route path. The attribute also
33
33
* recognizes several parameters: requirements, options, defaults, schemes,
34
34
* methods, host, and name. The name parameter is mandatory.
35
35
* Here is an example of how you should be able to use it:
36
- * /**
37
- * * @Route("/Blog")
38
- * * /
39
- * class Blog
40
- * {
41
- * /**
42
- * * @Route("/", name="blog_index")
43
- * * /
44
- * public function index()
45
- * {
46
- * }
47
- * /**
48
- * * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"})
49
- * * /
50
- * public function show()
51
- * {
52
- * }
53
- * }
54
36
*
55
- * On PHP 8, the annotation class can be used as an attribute as well:
56
37
* #[Route('/Blog')]
57
38
* class Blog
58
39
* {
71
52
*/
72
53
abstract class AnnotationClassLoader implements LoaderInterface
73
54
{
55
+ /**
56
+ * @var Reader|null
57
+ *
58
+ * @deprecated in Symfony 6.4, this property will be removed in Symfony 7.
59
+ */
74
60
protected $ reader ;
61
+
62
+ /**
63
+ * @var string|null
64
+ */
75
65
protected $ env ;
76
66
77
67
/**
@@ -84,10 +74,27 @@ abstract class AnnotationClassLoader implements LoaderInterface
84
74
*/
85
75
protected $ defaultRouteIndex = 0 ;
86
76
87
- public function __construct (Reader $ reader = null , string $ env = null )
77
+ private bool $ hasDeprecatedAnnotations = false ;
78
+
79
+ /**
80
+ * @param string|null $env
81
+ */
82
+ public function __construct ($ env = null )
88
83
{
89
- $ this ->reader = $ reader ;
90
- $ this ->env = $ env ;
84
+ if ($ env instanceof Reader || null === $ env && \func_num_args () > 1 && null !== func_get_arg (1 )) {
85
+ trigger_deprecation ('symfony/routing ' , '6.4 ' , 'Passing an instance of "%s" as first and the environment as second argument to "%s" is deprecated. Pass the environment as first argument instead. ' , Reader::class, __METHOD__ );
86
+
87
+ $ this ->reader = $ env ;
88
+ $ env = \func_num_args () > 1 ? func_get_arg (1 ) : null ;
89
+ }
90
+
91
+ if (\is_string ($ env ) || null === $ env ) {
92
+ $ this ->env = $ env ;
93
+ } elseif ($ env instanceof \Stringable || \is_scalar ($ env )) {
94
+ $ this ->env = (string ) $ env ;
95
+ } else {
96
+ throw new \TypeError (__METHOD__ .sprintf (': Parameter $env was expected to be a string or null, "%s" given. ' , get_debug_type ($ env )));
97
+ }
91
98
}
92
99
93
100
/**
@@ -114,43 +121,48 @@ public function load(mixed $class, string $type = null): RouteCollection
114
121
throw new \InvalidArgumentException (sprintf ('Annotations from class "%s" cannot be read as it is abstract. ' , $ class ->getName ()));
115
122
}
116
123
117
- $ globals = $ this ->getGlobals ($ class );
118
-
119
- $ collection = new RouteCollection ();
120
- $ collection ->addResource (new FileResource ($ class ->getFileName ()));
124
+ $ this ->hasDeprecatedAnnotations = false ;
121
125
122
- if ($ globals ['env ' ] && $ this ->env !== $ globals ['env ' ]) {
123
- return $ collection ;
124
- }
126
+ try {
127
+ $ globals = $ this ->getGlobals ($ class );
128
+ $ collection = new RouteCollection ();
129
+ $ collection ->addResource (new FileResource ($ class ->getFileName ()));
130
+ if ($ globals ['env ' ] && $ this ->env !== $ globals ['env ' ]) {
131
+ return $ collection ;
132
+ }
133
+ $ fqcnAlias = false ;
134
+ foreach ($ class ->getMethods () as $ method ) {
135
+ $ this ->defaultRouteIndex = 0 ;
136
+ $ routeNamesBefore = array_keys ($ collection ->all ());
137
+ foreach ($ this ->getAnnotations ($ method ) as $ annot ) {
138
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
139
+ if ('__invoke ' === $ method ->name ) {
140
+ $ fqcnAlias = true ;
141
+ }
142
+ }
125
143
126
- $ fqcnAlias = false ;
127
- foreach ($ class ->getMethods () as $ method ) {
128
- $ this ->defaultRouteIndex = 0 ;
129
- $ routeNamesBefore = array_keys ($ collection ->all ());
130
- foreach ($ this ->getAnnotations ($ method ) as $ annot ) {
131
- $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
132
- if ('__invoke ' === $ method ->name ) {
144
+ if (1 === $ collection ->count () - \count ($ routeNamesBefore )) {
145
+ $ newRouteName = current (array_diff (array_keys ($ collection ->all ()), $ routeNamesBefore ));
146
+ $ collection ->addAlias (sprintf ('%s::%s ' , $ class ->name , $ method ->name ), $ newRouteName );
147
+ }
148
+ }
149
+ if (0 === $ collection ->count () && $ class ->hasMethod ('__invoke ' )) {
150
+ $ globals = $ this ->resetGlobals ();
151
+ foreach ($ this ->getAnnotations ($ class ) as $ annot ) {
152
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
133
153
$ fqcnAlias = true ;
134
154
}
135
155
}
136
-
137
- if (1 === $ collection ->count () - \count ($ routeNamesBefore )) {
138
- $ newRouteName = current (array_diff (array_keys ($ collection ->all ()), $ routeNamesBefore ));
139
- $ collection ->addAlias (sprintf ('%s::%s ' , $ class ->name , $ method ->name ), $ newRouteName );
156
+ if ($ fqcnAlias && 1 === $ collection ->count ()) {
157
+ $ collection ->addAlias ($ class ->name , $ invokeRouteName = key ($ collection ->all ()));
158
+ $ collection ->addAlias (sprintf ('%s::__invoke ' , $ class ->name ), $ invokeRouteName );
140
159
}
141
- }
142
160
143
- if (0 === $ collection ->count () && $ class ->hasMethod ('__invoke ' )) {
144
- $ globals = $ this ->resetGlobals ();
145
- foreach ($ this ->getAnnotations ($ class ) as $ annot ) {
146
- $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
147
- $ fqcnAlias = true ;
161
+ if ($ this ->hasDeprecatedAnnotations ) {
162
+ trigger_deprecation ('symfony/routing ' , '6.4 ' , 'Class "%s" uses Doctrine Annotations to configure routes, which is deprecated. Use PHP attributes instead. ' , $ class ->getName ());
148
163
}
149
- }
150
-
151
- if ($ fqcnAlias && 1 === $ collection ->count ()) {
152
- $ collection ->addAlias ($ class ->name , $ invokeRouteName = key ($ collection ->all ()));
153
- $ collection ->addAlias (sprintf ('%s::__invoke ' , $ class ->name ), $ invokeRouteName );
164
+ } finally {
165
+ $ this ->hasDeprecatedAnnotations = false ;
154
166
}
155
167
156
168
return $ collection ;
@@ -272,6 +284,9 @@ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMetho
272
284
return $ name ;
273
285
}
274
286
287
+ /**
288
+ * @return array<string, mixed>
289
+ */
275
290
protected function getGlobals (\ReflectionClass $ class ): array
276
291
{
277
292
$ globals = $ this ->resetGlobals ();
@@ -280,8 +295,8 @@ protected function getGlobals(\ReflectionClass $class): array
280
295
if ($ attribute = $ class ->getAttributes ($ this ->routeAnnotationClass , \ReflectionAttribute::IS_INSTANCEOF )[0 ] ?? null ) {
281
296
$ annot = $ attribute ->newInstance ();
282
297
}
283
- if (!$ annot && $ this ->reader ) {
284
- $ annot = $ this ->reader -> getClassAnnotation ( $ class , $ this -> routeAnnotationClass ) ;
298
+ if (!$ annot && $ annot = $ this ->reader ?->getClassAnnotation( $ class , $ this -> routeAnnotationClass ) ) {
299
+ $ this ->hasDeprecatedAnnotations = true ;
285
300
}
286
301
287
302
if ($ annot ) {
@@ -365,11 +380,9 @@ protected function createRoute(string $path, array $defaults, array $requirement
365
380
abstract protected function configureRoute (Route $ route , \ReflectionClass $ class , \ReflectionMethod $ method , object $ annot );
366
381
367
382
/**
368
- * @param \ReflectionClass|\ReflectionMethod $reflection
369
- *
370
383
* @return iterable<int, RouteAnnotation>
371
384
*/
372
- private function getAnnotations (object $ reflection ): iterable
385
+ private function getAnnotations (\ ReflectionClass | \ ReflectionMethod $ reflection ): iterable
373
386
{
374
387
foreach ($ reflection ->getAttributes ($ this ->routeAnnotationClass , \ReflectionAttribute::IS_INSTANCEOF ) as $ attribute ) {
375
388
yield $ attribute ->newInstance ();
@@ -385,6 +398,8 @@ private function getAnnotations(object $reflection): iterable
385
398
386
399
foreach ($ annotations as $ annotation ) {
387
400
if ($ annotation instanceof $ this ->routeAnnotationClass ) {
401
+ $ this ->hasDeprecatedAnnotations = true ;
402
+
388
403
yield $ annotation ;
389
404
}
390
405
}
0 commit comments