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
<
F438
code class="diff-text syntax-highlighted-line addition">+ 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
/**
@@ -116,43 +123,48 @@ public function load(mixed $class, string $type = null): RouteCollection
116
123
throw new \InvalidArgumentException (sprintf ('Annotations from class "%s" cannot be read as it is abstract. ' , $ class ->getName ()));
117
124
}
118
125
119
- $ globals = $ this ->getGlobals ( $ class ) ;
126
+ $ this ->hasDeprecatedAnnotations = false ;
120
127
121
- $ collection = new RouteCollection ();
122
- $ collection ->addResource (new FileResource ($ class ->getFileName ()));
123
-
124
- if ($ globals ['env ' ] && $ this ->env !== $ globals ['env ' ]) {
125
- return $ collection ;
126
- }
128
+ try {
129
+ $ globals = $ this ->getGlobals ($ class );
130
+ $ collection = new RouteCollection ();
131
+ $ collection ->addResource (new FileResource ($ class ->getFileName ()));
132
+ if ($ globals ['env ' ] && $ this ->env !== $ globals ['env ' ]) {
133
+ return $ collection ;
134
+ }
135
+ $ fqcnAlias = false ;
136
+ foreach ($ class ->getMethods () as $ method ) {
137
+ $ this ->defaultRouteIndex = 0 ;
138
+ $ routeNamesBefore = array_keys ($ collection ->all ());
139
+ foreach ($ this ->getAnnotations ($ method ) as $ annot ) {
140
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
141
+ if ('__invoke ' === $ method ->name ) {
142
+ $ fqcnAlias = true ;
143
+ }
144
+ }
127
145
128
- $ fqcnAlias = false ;
129
- foreach ($ class ->getMethods () as $ method ) {
130
- $ this ->defaultRouteIndex = 0 ;
131
- $ routeNamesBefore = array_keys ($ collection ->all ());
132
- foreach ($ this ->getAnnotations ($ method ) as $ annot ) {
133
- $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
134
- if ('__invoke ' === $ method ->name ) {
146
+ if (1 === $ collection ->count () - \count ($ routeNamesBefore )) {
147
+ $ newRouteName = current (array_diff (array_keys ($ collection ->all ()), $ routeNamesBefore ));
148
+ $ collection ->addAlias (sprintf ('%s::%s ' , $ class ->name , $ method ->name ), $ newRouteName );
149
+ }
150
+ }
151
+ if (0 === $ collection ->count () && $ class ->hasMethod ('__invoke ' )) {
152
+ $ globals = $ this ->resetGlobals ();
153
+ foreach ($ this ->getAnnotations ($ class ) as $ annot ) {
154
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
135
155
$ fqcnAlias = true ;
136
156
}
137
157
}
138
-
139
- if (1 === $ collection ->count () - \count ($ routeNamesBefore )) {
140
- $ newRouteName = current (array_diff (array_keys ($ collection ->all ()), $ routeNamesBefore ));
141
- $ collection ->addAlias (sprintf ('%s::%s ' , $ class ->name , $ method ->name ), $ newRouteName );
158
+ if ($ fqcnAlias && 1 === $ collection ->count ()) {
159
+ $ collection ->addAlias ($ class ->name , $ invokeRouteName = key ($ collection ->all ()));
160
+ $ collection ->addAlias (sprintf ('%s::__invoke ' , $ class ->name ), $ invokeRouteName );
142
161
}
143
- }
144
162
145
- if (0 === $ collection ->count () && $ class ->hasMethod ('__invoke ' )) {
146
- $ globals = $ this ->resetGlobals ();
147
- foreach ($ this ->getAnnotations ($ class ) as $ annot ) {
148
- $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
149
- $ fqcnAlias = true ;
163
+ if ($ this ->hasDeprecatedAnnotations ) {
164
+ trigger_deprecation ('symfony/routing ' , '6.4 ' , 'Class "%s" uses Doctrine Annotations to configure routes, which is deprecated. Use PHP attributes instead. ' , $ class ->getName ());
150
165
}
151
- }
152
-
153
- if ($ fqcnAlias && 1 === $ collection ->count ()) {
154
- $ collection ->addAlias ($ class ->name , $ invokeRouteName = key ($ collection ->all ()));
155
- $ collection ->addAlias (sprintf ('%s::__invoke ' , $ class ->name ), $ invokeRouteName );
166
+ } finally {
167
+ $ this ->hasDeprecatedAnnotations = false ;
156
168
}
157
169
158
170
return $ collection ;
@@ -279,7 +291,7 @@ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMetho
279
291
}
280
292
281
293
/**
282
- * @return array
294
+ * @return array<string, mixed>
283
295
*/
284
296
protected function getGlobals (\ReflectionClass $ class )
285
297
{
@@ -289,8 +301,8 @@ protected function getGlobals(\ReflectionClass $class)
289
301
if ($ attribute = $ class ->getAttributes ($ this ->routeAnnotationClass , \ReflectionAttribute::IS_INSTANCEOF )[0 ] ?? null ) {
290
302
$ annot = $ attribute ->newInstance ();
291
303
}
292
- if (!$ annot && $ this ->reader ) {
293
- $ annot = $ this ->reader -> getClassAnnotation ( $ class , $ this -> routeAnnotationClass ) ;
304
+ if (!$ annot && $ annot = $ this ->reader ?->getClassAnnotation( $ class , $ this -> routeAnnotationClass ) ) {
305
+ $ this ->hasDeprecatedAnnotations = true ;
294
306
}
295
307
296
308
if ($ annot ) {
@@ -377,11 +389,9 @@ protected function createRoute(string $path, array $defaults, array $requirement
377
389
abstract protected function configureRoute (Route $ route , \ReflectionClass $ class , \ReflectionMethod $ method , object $ annot );
378
390
379
391
/**
380
- * @param \ReflectionClass|\ReflectionMethod $reflection
381
- *
382
392
* @return iterable<int, RouteAnnotation>
383
393
*/
384
- private function getAnnotations (object $ reflection ): iterable
394
+ private function getAnnotations (\ ReflectionClass | \ ReflectionMethod $ reflection ): iterable
385
395
{
386
396
foreach ($ reflection ->getAttributes ($ this ->routeAnnotationClass , \ReflectionAttribute::IS_INSTANCEOF ) as $ attribute ) {
387
397
yield $ attribute ->newInstance ();
@@ -397,6 +407,8 @@ private function getAnnotations(object $reflection): iterable
397
407
398
408
foreach ($ annotations as $ annotation ) {
399
409
if ($ annotation instanceof $ this ->routeAnnotationClass ) {
410
+ $ this ->hasDeprecatedAnnotations = true ;
411
+
400
412
yield $ annotation ;
401
413
}
402
414
}
0 commit comments