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
+ * @deprecated in Symfony 6.4, this property will be removed in Symfony 7.
58
+ */
74
59
protected $ reader ;
60
+
61
+ /**
62
+ * @var string|null
63
+ * @internal since Symfony 6.4, this property will be private in Symfony 7.
64
+ */
75
65
protected $ env ;
76
66
77
67
/**
78
68
* @var string
69
+ * @internal since Symfony 6.4, this property will be private in Symfony 7.
79
70
*/
80
71
protected $ routeAnnotationClass = RouteAnnotation::class;
81
72
82
73
/**
83
74
* @var int
75
+ * @internal since Symfony 6.4, this property will be private in Symfony 7.
84
76
*/
85
77
protected $ defaultRouteIndex = 0 ;
86
78
87
- public function __construct (Reader $ reader = null , string $ env = null )
79
+ private bool $ hasDeprecatedAnnotations = false ;
80
+
81
+ /**
82
+ * @param string|null $env
83
+ */
84
+ public function __construct ($ env = null )
88
85
{
89
- $ this ->reader = $ reader ;
90
- $ this ->env = $ env ;
86
+ if ($ env instanceof Reader || func_num_args () > 1 && null !== func_get_arg (1 )) {
87
+ 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__ );
88
+
89
+ $ this ->reader = $ env ;
90
+ $ env = func_num_args () > 1 ? func_get_arg (1 ) : null ;
91
+ }
92
+
93
+ if (is_string ($ env ) || null === $ env ) {
94
+ $ this ->env = $ env ;
95
+ } elseif ($ env instanceof \Stringable || is_scalar ($ env )) {
96
+ $ this ->env = (string ) $ env ;
97
+ } else {
98
+ throw new \TypeError (__METHOD__ . sprintf (': Parameter $env was expected to be a string or null, "%s" given. ' , get_debug_type ($ env )));
99
+ }
91
100
}
92
101
93
102
/**
@@ -116,43 +125,48 @@ public function load(mixed $class, string $type = null): RouteCollection
116
125
throw new \InvalidArgumentException (sprintf ('Annotations from class "%s" cannot be read as it is abstract. ' , $ class ->getName ()));
117
126
}
118
127
119
- $ globals = $ this ->getGlobals ($ class );
120
-
121
- $ collection = new RouteCollection ();
122
- $ collection ->addResource (new FileResource ($ class ->getFileName ()));
128
+ $ this ->hasDeprecatedAnnotations = false ;
123
129
124
- if ($ globals ['env ' ] && $ this ->env !== $ globals ['env ' ]) {
125
- return $ collection ;
126
- }
130
+ try {
131
+ $ globals = $ this ->getGlobals ($ class );
132
+ $ collection = new RouteCollection ();
133
+ $ collection ->addResource (new FileResource ($ class ->getFileName ()));
134
+ if ($ globals ['env ' ] && $ this ->env !== $ globals ['env ' ]) {
135
+ return $ collection ;
136
+ }
137
+ $ fqcnAlias = false ;
138
+ foreach ($ class ->getMethods () as $ method ) {
139
+ $ this ->defaultRouteIndex = 0 ;
140
+ $ routeNamesBefore = array_keys ($ collection ->all ());
141
+ foreach ($ this ->getAnnotations ($ method ) as $ annot ) {
142
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ method );
143
+ if ('__invoke ' === $ method ->name ) {
144
+ $ fqcnAlias = true ;
145
+ }
146
+ }
127
147
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 ) {
148
+ if (1 === $ collection ->count () - \count ($ routeNamesBefore )) {
149
+ $ newRouteName = current (array_diff (array_keys ($ collection ->all ()), $ routeNamesBefore ));
150
+ $ collection ->addAlias (sprintf ('%s::%s ' , $ class ->name , $ method ->name ), $ newRouteName );
151
+ }
152
+ }
153
+ if (0 === $ collection ->count () && $ class ->hasMethod ('__invoke ' )) {
154
+ $ globals = $ this ->resetGlobals ();
155
+ foreach ($ this ->getAnnotations ($ class ) as $ annot ) {
156
+ $ this ->addRoute ($ collection , $ annot , $ globals , $ class , $ class ->getMethod ('__invoke ' ));
135
157
$ fqcnAlias = true ;
136
158
}
137
159
}
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 );
160
+ if ($ fqcnAlias && 1 === $ collection ->count ()) {
161
+ $ collection ->addAlias ($ class ->name , $ invokeRouteName = key ($ collection ->all ()));
162
+ $ collection ->addAlias (sprintf ('%s::__invoke ' , $ class ->name ), $ invokeRouteName );
142
163
}
143
- }
144
164
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 ;
165
+ if ($ this ->hasDeprecatedAnnotations ) {
166
+ trigger_deprecation ('symfony/routing ' , '6.4 ' , 'Class "%s" uses Doctrine Annotations to configure routes, which is deprecated. Use PHP attributes instead. ' , $ class ->getName ());
150
167
}
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 );
168
+ } finally {
169
+ $ this ->hasDeprecatedAnnotations = false ;
156
170
}
157
171
158
172
return $ collection ;
@@ -282,7 +296,7 @@ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMetho
282
296
}
283
297
284
298
/**
285
- * @return array
299
+ * @return array<string, mixed>
286
300
*/
287
301
protected function getGlobals (\ReflectionClass $ class )
288
302
{
@@ -292,8 +306,8 @@ protected function getGlobals(\ReflectionClass $class)
292
306
if ($ attribute = $ class ->getAttributes ($ this ->routeAnnotationClass , \ReflectionAttribute::IS_INSTANCEOF )[0 ] ?? null ) {
293
307
$ annot = $ attribute ->newInstance ();
294
308
}
295
- if (!$ annot && $ this ->reader ) {
296
- $ annot = $ this ->reader -> getClassAnnotation ( $ class , $ this -> routeAnnotationClass ) ;
309
+ if (!$ annot && $ annot = $ this ->reader ?->getClassAnnotation( $ class , $ this -> routeAnnotationClass ) ) {
310
+ $ this ->hasDeprecatedAnnotations = true ;
297
311
}
298
312
299
313
if ($ annot ) {
@@ -380,11 +394,9 @@ protected function createRoute(string $path, array $defaults, array $requirement
380
394
abstract protected function configureRoute (Route $ route , \ReflectionClass $ class , \ReflectionMethod $ method , object $ annot );
381
395
382
396
/**
383
- * @param \ReflectionClass|\ReflectionMethod $reflection
384
- *
385
397
* @return iterable<int, RouteAnnotation>
386
398
*/
387
- private function getAnnotations (object $ reflection ): iterable
399
+ private function getAnnotations (\ ReflectionClass | \ ReflectionMethod $ reflection ): iterable
388
400
{
389
401
foreach ($ reflection ->getAttributes ($ this ->routeAnnotationClass , \ReflectionAttribute::IS_INSTANCEOF ) as $ attribute ) {
390
402
yield $ attribute ->newInstance ();
@@ -400,6 +412,8 @@ private function getAnnotations(object $reflection): iterable
400
412
401
413
foreach ($ annotations as $ annotation ) {
402
414
if ($ annotation instanceof $ this ->routeAnnotationClass ) {
415
+ $ this ->hasDeprecatedAnnotations = true ;
416
+
403
417
yield $ annotation ;
404
418
}
405
419
}
0 commit comments