Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 427785e

Browse files
committed
[Routing] Deprecate annotations in favor of attributes
1 parent 5a2ee5a commit 427785e

12 files changed

+185
-196
lines changed

src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php

Lines changed: 61 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -72,23 +72,49 @@
7272
*/
7373
abstract class AnnotationClassLoader implements LoaderInterface
7474
{
75+
/**
76+
* @var Reader|null
77+
* @deprecated in Symfony 6.3, this property will be removed in Symfony 7.
78+
*/
7579
protected $reader;
80+
81+
/**
82+
* @var string|null
83+
* @internal since Symfony 6.3, this property will be private in Symfony 7.
84+
*/
7685
protected $env;
7786

7887
/**
7988
* @var string
89+
* @internal since Symfony 6.3, this property will be private in Symfony 7.
8090
*/
8191
protected $routeAnnotationClass = RouteAnnotation::class;
8292

8393
/**
8494
* @var int
95+
* @internal since Symfony 6.3, this property will be private in Symfony 7.
8596
*/
8697
protected $defaultRouteIndex = 0;
8798

88-
public function __construct(Reader $reader = null, string $env = null)
99+
private bool $hasDeprecatedAnnotations = false;
100+
101+
/**
102+
* @param string|null $env
103+
*/
104+
public function __construct($env = null)
89105
{
90-
$this->reader = $reader;
91-
$this->env = $env;
106+
if ($env instanceof Reader || func_num_args() > 1 && null !== func_get_arg(1)) {
107+
trigger_deprecation( 'symfony/routing', '6.3', '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__);
108+
109+
$this->reader = $env;
110+
$this->env = func_num_args() > 1 ? func_get_arg(1) : null;
111+
} elseif (is_string($env) || null === $env) {
112+
$this->env = $env;
113+
} elseif ($env instanceof \Stringable || is_scalar($env)) {
114+
$this->env = (string) $env;
115+
} else {
116+
throw new \TypeError(__METHOD__ . sprintf(': Parameter #1 ($env) was expected to be a string or null, "%s" given.', get_debug_type($env)));
117+
}
92118
}
93119

94120
/**
@@ -117,27 +143,33 @@ public function load(mixed $class, string $type = null): RouteCollection
117143
throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName()));
118144
}
119145

120-
$globals = $this->getGlobals($class);
121-
122-
$collection = new RouteCollection();
123-
$collection->addResource(new FileResource($class->getFileName()));
146+
$this->hasDeprecatedAnnotations = false;
124147

125-
if ($globals['env'] && $this->env !== $globals['env']) {
126-
return $collection;
127-
}
128-
129-
foreach ($class->getMethods() as $method) {
130-
$this->defaultRouteIndex = 0;
131-
foreach ($this->getAnnotations($method) as $annot) {
132-
$this->addRoute($collection, $annot, $globals, $class, $method);
148+
try {
149+
$globals = $this->getGlobals($class);
150+
$collection = new RouteCollection();
151+
$collection->addResource(new FileResource($class->getFileName()));
152+
if ($globals['env'] && $this->env !== $globals['env']) {
153+
return $collection;
154+
}
155+
foreach ($class->getMethods() as $method) {
156+
$this->defaultRouteIndex = 0;
157+
foreach ($this->getAnnotations($method) as $annot) {
158+
$this->addRoute($collection, $annot, $globals, $class, $method);
159+
}
160+
}
161+
if (0 === $collection->count() && $class->hasMethod('__invoke')) {
162+
$globals = $this->resetGlobals();
163+
foreach ($this->getAnnotations($class) as $annot) {
164+
$this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke'));
165+
}
133166
}
134-
}
135167

136-
if (0 === $collection->count() && $class->hasMethod('__invoke')) {
137-
$globals = $this->resetGlobals();
138-
foreach ($this->getAnnotations($class) as $annot) {
139-
$this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke'));
168+
if ($this->hasDeprecatedAnnotations) {
169+
trigger_deprecation('symfony/routing', '6.3', 'Class "%s" uses Doctrine Annotations to configure routes, which is deprecated. Use PHP attributes instead.', $class->getName());
140170
}
171+
} finally {
172+
$this->hasDeprecatedAnnotations = false;
141173
}
142174

143175
return $collection;
@@ -263,7 +295,7 @@ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMetho
263295
}
264296

265297
/**
266-
* @return array
298+
* @return array<string, mixed>
267299
*/
268300
protected function getGlobals(\ReflectionClass $class)
269301
{
@@ -273,8 +305,8 @@ protected function getGlobals(\ReflectionClass $class)
273305
if ($attribute = $class->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
274306
$annot = $attribute->newInstance();
275307
}
276-
if (!$annot && $this->reader) {
277-
$annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass);
308+
if (!$annot && $annot = $this->reader?->getClassAnnotation($class, $this->routeAnnotationClass)) {
309+
$this->hasDeprecatedAnnotations = true;
278310
}
279311

280312
if ($annot) {
@@ -355,14 +387,15 @@ protected function createRoute(string $path, array $defaults, array $requirement
355387
return new Route($path, $defaults, $requirements, $options, $host, $schemes, $methods, $condition);
356388
}
357389

390+
/**
391+
* @return void
392+
*/
358393
abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot);
359394

360395
/**
361-
* @param \ReflectionClass|\ReflectionMethod $reflection
362-
*
363396
* @return iterable<int, RouteAnnotation>
364397
*/
365-
private function getAnnotations(object $reflection): iterable
398+
private function getAnnotations(\ReflectionClass|\ReflectionMethod $reflection): iterable
366399
{
367400
foreach ($reflection->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
368401
yield $attribute->newInstance();
@@ -378,6 +411,8 @@ private function getAnnotations(object $reflection): iterable
378411

379412
foreach ($annotations as $annotation) {
380413
if ($annotation instanceof $this->routeAnnotationClass) {
414+
$this->hasDeprecatedAnnotations = true;
415+
381416
yield $annotation;
382417
}
383418
}

src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,13 @@
1111

1212
namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses;
1313

14+
use Symfony\Component\Routing\Annotation\Route;
15+
1416
abstract class AbstractClass
1517
{
1618
abstract public function abstractRouteAction();
1719

20+
#[Route('/path/to/route')]
1821
public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3')
1922
{
2023
}

src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@
1111

1212
namespace Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses;
1313

14+
use Symfony\Component\Routing\Annotation\Route;
15+
1416
trait AnonymousClassInTrait
1517
{
1618
public function test()
1719
{
1820
return new class() {
21+
#[Route('/path/to/route')]
1922
public function foo()
2023
{
2124
}

src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/VariadicClass.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,11 @@
1111

1212
namespace Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses;
1313

14+
use Symfony\Component\Routing\Annotation\Route;
15+
1416
class VariadicClass
1517
{
18+
#[Route('/path/to/{id}')]
1619
public function routeAction(...$params)
1720
{
1821
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
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\Tests\Fixtures;
13+
14+
use Symfony\Component\Routing\Loader\AnnotationClassLoader;
15+
use Symfony\Component\Routing\Route;
16+
use Symfony\Component\Routing\RouteCollection;
17+
18+
final class TraceableAnnotationClassLoader extends AnnotationClassLoader
19+
{
20+
/** @var list<string> */
21+
public array $foundClasses = [];
22+
23+
public function load(mixed $class, string $type = null): RouteCollection
24+
{
25+
if (!is_string($class)) {
26+
throw new \InvalidArgumentException(sprintf('Expected string, got "%s"', get_debug_type($class)));
27+
}
28+
29+
$this->foundClasses[] = $class;
30+
31+
return parent::load($class, $type); // TODO: Change the autogenerated stub
32+
}
33+
34+
protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void
35+
{
36+
}
37+
}

src/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTestCase.php

Lines changed: 0 additions & 34 deletions
This file was deleted.

src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTestCase.php

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,7 @@
1717

1818
abstract class AnnotationClassLoaderTestCase extends TestCase
1919
{
20-
/**
21-
* @var AnnotationClassLoader
22-
*/
23-
protected $loader;
20+
protected AnnotationClassLoader $loader;
2421

2522
/**
2623
* @dataProvider provideTestSupportsChecksResource
@@ -30,7 +27,7 @@ public function testSupportsChecksResource($resource, $expectedSupports)
3027
$this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable');
3128
}
3229

33-
public function provideTestSupportsChecksResource()
30+
public function provideTestSupportsChecksResource(): array
3431
{
3532
return [
3633
['class', true],

src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,17 @@
1212
namespace Symfony\Component\Routing\Tests\Loader;
1313

1414
use Doctrine\Common\Annotations\AnnotationReader;
15-
use Symfony\Component\Routing\Loader\AnnotationClassLoader;
16-
use Symfony\Component\Routing\Route;
15+
use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader;
1716

17+
/**
18+
* @group legacy
19+
*/
1820
class AnnotationClassLoaderWithAnnotationsTest extends AnnotationClassLoaderTestCase
1921
{
2022
protected function setUp(string $env = null): void
2123
{
2224
$reader = new AnnotationReader();
23-
$this->loader = new class($reader, $env) extends AnnotationClassLoader {
24-
protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void
25-
{
26-
}
27-
};
25+
$this->loader = new TraceableAnnotationClassLoader($reader, $env);
2826
}
2927

3028
public function testDefaultRouteName()

src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAttributesTest.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,18 +11,13 @@
1111

1212
namespace Symfony\Component\Routing\Tests\Loader;
1313

14-
use Symfony\Component\Routing\Loader\AnnotationClassLoader;
15-
use Symfony\Component\Routing\Route;
14+
use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader;
1615

1716
class AnnotationClassLoaderWithAttributesTest extends AnnotationClassLoaderTestCase
1817
{
1918
protected function setUp(string $env = null): void
2019
{
21-
$this->loader = new class(null, $env) extends AnnotationClassLoader {
22-
protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void
23-
{
24-
}
25-
};
20+
$this->loader = new TraceableAnnotationClassLoader($env);
2621
}
2722

2823
public function testDefaultRouteName()

0 commit comments

Comments
 (0)