Skip to content

Commit 9a27bae

Browse files
committed
[Routing] Remove Doctrine annotations support
1 parent badd6e4 commit 9a27bae

39 files changed

+123
-908
lines changed

UPGRADE-7.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ Routing
198198
-------
199199

200200
* Add argument `$routeParameters` to `UrlMatcher::handleRouteRequirements()`
201+
* Remove Doctrine annotations support in favor of native attributes
202+
* Change the constructor signature of `AnnotationClassLoader` to `__construct(?string $env = null)`, passing an annotation reader as first argument is not supported anymore
201203

202204
Security
203205
--------

src/Symfony/Component/Routing/Annotation/Route.php

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,6 @@
1212
namespace Symfony\Component\Routing\Annotation;
1313

1414
/**
15-
* Annotation class for @Route().
16-
*
17-
* @Annotation
18-
* @NamedArgumentConstructor
19-
* @Target({"CLASS", "METHOD"})
20-
*
2115
* @author Fabien Potencier <fabien@symfony.com>
2216
* @author Alexander M. Turek <me@derrabus.de>
2317
*/

src/Symfony/Component/Routing/CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ CHANGELOG
55
---
66

77
* Add argument `$routeParameters` to `UrlMatcher::handleRouteRequirements()`
8+
* Remove Doctrine annotations support in favor of native attributes
9+
* Change the constructor signature of `AnnotationClassLoader` to `__construct(?string $env = null)`, passing an annotation reader as first argument is not supported anymore
810

911
6.4
1012
---

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

Lines changed: 32 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
namespace Symfony\Component\Routing\Loader;
1313

14-
use Doctrine\Common\Annotations\Reader;
1514
use Symfony\Component\Config\Loader\LoaderInterface;
1615
use Symfony\Component\Config\Loader\LoaderResolverInterface;
1716
use Symfony\Component\Config\Resource\FileResource;
@@ -52,49 +51,12 @@
5251
*/
5352
abstract class AnnotationClassLoader implements LoaderInterface
5453
{
55-
/**
56-
* @var Reader|null
57-
*
58-
* @deprecated in Symfony 6.4, this property will be removed in Symfony 7.
59-
*/
60-
protected $reader;
61-
62-
/**
63-
* @var string|null
64-
*/
65-
protected $env;
66-
67-
/**
68-
* @var string
69-
*/
70-
protected $routeAnnotationClass = RouteAnnotation::class;
71-
72-
/**
73-
* @var int
74-
*/
75-
protected $defaultRouteIndex = 0;
76-
77-
private bool $hasDeprecatedAnnotations = false;
78-
79-
/**
80-
* @param string|null $env
81-
*/
82-
public function __construct($env = null)
83-
{
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__);
54+
protected string $routeAnnotationClass = RouteAnnotation::class;
55+
protected int $defaultRouteIndex = 0;
8656

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-
}
57+
public function __construct(
58+
protected readonly ?string $env = null,
59+
) {
9860
}
9961

10062
/**
@@ -121,48 +83,38 @@ public function load(mixed $class, string $type = null): RouteCollection
12183
throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName()));
12284
}
12385

124-
$this->hasDeprecatedAnnotations = false;
125-
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-
}
143-
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'));
86+
$globals = $this->getGlobals($class);
87+
$collection = new RouteCollection();
88+
$collection->addResource(new FileResource($class->getFileName()));
89+
if ($globals['env'] && $this->env !== $globals['env']) {
90+
return $collection;
91+
}
92+
$fqcnAlias = false;
93+
foreach ($class->getMethods() as $method) {
94+
$this->defaultRouteIndex = 0;
95+
$routeNamesBefore = array_keys($collection->all());
96+
foreach ($this->getAnnotations($method) as $annot) {
97+
$this->addRoute($collection, $annot, $globals, $class, $method);
98+
if ('__invoke' === $method->name) {
15399
$fqcnAlias = true;
154100
}
155101
}
156-
if ($fqcnAlias && 1 === $collection->count()) {
157-
$collection->addAlias($class->name, $invokeRouteName = key($collection->all()));
158-
$collection->addAlias(sprintf('%s::__invoke', $class->name), $invokeRouteName);
159-
}
160102

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());
103+
if (1 === $collection->count() - \count($routeNamesBefore)) {
104+
$newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore));
105+
$collection->addAlias(sprintf('%s::%s', $class->name, $method->name), $newRouteName);
163106
}
164-
} finally {
165-
$this->hasDeprecatedAnnotations = false;
107+
}
108+
if (0 === $collection->count() && $class->hasMethod('__invoke')) {
109+
$globals = $this->resetGlobals();
110+
foreach ($this->getAnnotations($class) as $annot) {
111+
$this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke'));
112+
$fqcnAlias = true;
113+
}
114+
}
115+
if ($fqcnAlias && 1 === $collection->count()) {
116+
$collection->addAlias($class->name, $invokeRouteName = key($collection->all()));
117+
$collection->addAlias(sprintf('%s::__invoke', $class->name), $invokeRouteName);
166118
}
167119

168120
return $collection;
@@ -291,15 +243,9 @@ protected function getGlobals(\ReflectionClass $class): array
291243
{
292244
$globals = $this->resetGlobals();
293245

294-
$annot = null;
295246
if ($attribute = $class->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) {
296247
$annot = $attribute->newInstance();
297-
}
298-
if (!$annot && $annot = $this->reader?->getClassAnnotation($class, $this->routeAnnotationClass)) {
299-
$this->hasDeprecatedAnnotations = true;
300-
}
301248

302-
if ($annot) {
303249
if (null !== $annot->getName()) {
304250
$globals['name'] = $annot->getName();
305251
}
@@ -387,21 +333,5 @@ private function getAnnotations(\ReflectionClass|\ReflectionMethod $reflection):
387333
foreach ($reflection->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) {
388334
yield $attribute->newInstance();
389335
}
390-
391-
if (!$this->reader) {
392-
return;
393-
}
394-
395-
$annotations = $reflection instanceof \ReflectionClass
396-
? $this->reader->getClassAnnotations($reflection)
397-
: $this->reader->getMethodAnnotations($reflection);
398-
399-
foreach ($annotations as $annotation) {
400-
if ($annotation instanceof $this->routeAnnotationClass) {
401-
$this->hasDeprecatedAnnotations = true;
402-
403-
yield $annotation;
404-
}
405-
}
406336
}
407337
}

src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php

Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -11,49 +11,19 @@
1111

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

14-
use Doctrine\Common\Annotations\AnnotationReader;
1514
use PHPUnit\Framework\TestCase;
1615
use Symfony\Component\Routing\Annotation\Route;
17-
use Symfony\Component\Routing\Tests\Fixtures\AnnotationFixtures\FooController;
18-
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\FooController as FooAttributesController;
16+
use Symfony\Component\Routing\Tests\Fixtures\AttributeFixtures\FooController;
1917

2018
class RouteTest extends TestCase
2119
{
22-
private function getMethodAnnotation(string $method, bool $attributes): Route
23-
{
24-
$class = $attributes ? FooAttributesController::class : FooController::class;
25-
$reflection = new \ReflectionMethod($class, $method);
26-
27-
if ($attributes) {
28-
$attributes = $reflection->getAttributes(Route::class);
29-
$route = $attributes[0]->newInstance();
30-
} else {
31-
$reader = new AnnotationReader();
32-
$route = $reader->getMethodAnnotation($reflection, Route::class);
33-
}
34-
35-
if (!$route instanceof Route) {
36-
throw new \Exception('Can\'t parse annotation');
37-
}
38-
39-
return $route;
40-
}
41-
4220
/**
4321
* @dataProvider getValidParameters
4422
*/
45-
public function testLoadFromAttribute(string $methodName, string $getter, $expectedReturn)
23+
public function testLoadFromAttribute(string $methodName, string $getter, mixed $expectedReturn)
4624
{
47-
$route = $this->getMethodAnnotation($methodName, true);
48-
$this->assertEquals($route->$getter(), $expectedReturn);
49-
}
25+
$route = (new \ReflectionMethod(FooController::class, $methodName))->getAttributes(Route::class)[0]->newInstance();
5026

51-
/**
52-
* @dataProvider getValidParameters
53-
*/
54-
public function testLoadFromDoctrineAnnotation(string $methodName, string $getter, $expectedReturn)
55-
{
56-
$route = $this->getMethodAnnotation($methodName, false);
5727
$this->assertEquals($route->$getter(), $expectedReturn);
5828
}
5929

src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/AbstractClassController.php

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

src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/ActionPathController.php

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

src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/BazClass.php

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

src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/DefaultValueController.php

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

src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/EncodingClass.php

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

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy