diff --git a/UPGRADE-6.4.md b/UPGRADE-6.4.md index 4bb687b19ac14..a534b3beeeb22 100644 --- a/UPGRADE-6.4.md +++ b/UPGRADE-6.4.md @@ -64,6 +64,8 @@ Routing ------- * Add native return type to `AnnotationClassLoader::setResolver()` + * Deprecate Doctrine annotations support in favor of native attributes + * Change the constructor signature of `AnnotationClassLoader` to `__construct(?string $env = null)`, passing an annotation reader as first argument is deprecated Security -------- diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 846639ebda2ac..696cf9093d6be 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -144,6 +144,7 @@ use Symfony\Component\RateLimiter\Storage\CacheStorage; use Symfony\Component\RemoteEvent\Attribute\AsRemoteEventConsumer; use Symfony\Component\RemoteEvent\RemoteEvent; +use Symfony\Component\Routing\Loader\AnnotationClassLoader; use Symfony\Component\Routing\Loader\Psr4DirectoryLoader; use Symfony\Component\Scheduler\Attribute\AsSchedule; use Symfony\Component\Scheduler\Messenger\SchedulerTransportFactory; @@ -1179,6 +1180,13 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co if (!class_exists(Psr4DirectoryLoader::class)) { $container->removeDefinition('routing.loader.psr4'); } + + if ($this->isInitializedConfigEnabled('annotations') && (new \ReflectionClass(AnnotationClassLoader::class))->hasProperty('reader')) { + $container->getDefinition('routing.loader.annotation')->setArguments([ + new Reference('annotation_reader'), + '%kernel.environment%', + ]); + } } private function registerSessionConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader): void diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.php index 86a7cf874629c..10745b225e684 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing.php @@ -94,7 +94,6 @@ ->set('routing.loader.annotation', AnnotatedRouteControllerLoader::class) ->args([ - service('annotation_reader')->nullOnInvalid(), '%kernel.environment%', ]) ->tag('routing.loader', ['priority' => -10]) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index b0fac1a188e58..ba0096cfc52a8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -30,7 +30,7 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "^5.4|^6.0|^7.0", "symfony/finder": "^5.4|^6.0|^7.0", - "symfony/routing": "^6.1|^7.0" + "symfony/routing": "^6.4|^7.0" }, "require-dev": { "doctrine/annotations": "^1.13.1|^2", diff --git a/src/Symfony/Component/Routing/CHANGELOG.md b/src/Symfony/Component/Routing/CHANGELOG.md index 570e09421ab60..c0685780955a3 100644 --- a/src/Symfony/Component/Routing/CHANGELOG.md +++ b/src/Symfony/Component/Routing/CHANGELOG.md @@ -6,6 +6,8 @@ CHANGELOG * Add FQCN and FQCN::method aliases for routes loaded from attributes/annotations when applicable * Add native return type to `AnnotationClassLoader::setResolver()` + * Deprecate Doctrine annotations support in favor of native attributes + * Change the constructor signature of `AnnotationClassLoader` to `__construct(?string $env = null)`, passing an annotation reader as first argument is deprecated 6.2 --- diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index ca12eb8399c82..1af0b1b1f36a1 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -26,33 +26,14 @@ * time, this method should define some PHP callable to be called for the route * (a controller in MVC speak). * - * The @Route annotation can be set on the class (for global parameters), + * The #[Route] attribute can be set on the class (for global parameters), * and on each method. * - * The @Route annotation main value is the route path. The annotation also + * The #[Route] attribute main value is the route path. The attribute also * recognizes several parameters: requirements, options, defaults, schemes, * methods, host, and name. The name parameter is mandatory. * Here is an example of how you should be able to use it: - * /** - * * @Route("/Blog") - * * / - * class Blog - * { - * /** - * * @Route("/", name="blog_index") - * * / - * public function index() - * { - * } - * /** - * * @Route("/{id}", name="blog_post", requirements = {"id" = "\d+"}) - * * / - * public function show() - * { - * } - * } * - * On PHP 8, the annotation class can be used as an attribute as well: * #[Route('/Blog')] * class Blog * { @@ -71,7 +52,16 @@ */ abstract class AnnotationClassLoader implements LoaderInterface { + /** + * @var Reader|null + * + * @deprecated in Symfony 6.4, this property will be removed in Symfony 7. + */ protected $reader; + + /** + * @var string|null + */ protected $env; /** @@ -84,10 +74,27 @@ abstract class AnnotationClassLoader implements LoaderInterface */ protected $defaultRouteIndex = 0; - public function __construct(Reader $reader = null, string $env = null) + private bool $hasDeprecatedAnnotations = false; + + /** + * @param string|null $env + */ + public function __construct($env = null) { - $this->reader = $reader; - $this->env = $env; + if ($env instanceof Reader || null === $env && \func_num_args() > 1 && null !== func_get_arg(1)) { + 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__); + + $this->reader = $env; + $env = \func_num_args() > 1 ? func_get_arg(1) : null; + } + + if (\is_string($env) || null === $env) { + $this->env = $env; + } elseif ($env instanceof \Stringable || \is_scalar($env)) { + $this->env = (string) $env; + } else { + throw new \TypeError(__METHOD__.sprintf(': Parameter $env was expected to be a string or null, "%s" given.', get_debug_type($env))); + } } /** @@ -116,43 +123,48 @@ public function load(mixed $class, string $type = null): RouteCollection throw new \InvalidArgumentException(sprintf('Annotations from class "%s" cannot be read as it is abstract.', $class->getName())); } - $globals = $this->getGlobals($class); + $this->hasDeprecatedAnnotations = false; - $collection = new RouteCollection(); - $collection->addResource(new FileResource($class->getFileName())); - - if ($globals['env'] && $this->env !== $globals['env']) { - return $collection; - } + try { + $globals = $this->getGlobals($class); + $collection = new RouteCollection(); + $collection->addResource(new FileResource($class->getFileName())); + if ($globals['env'] && $this->env !== $globals['env']) { + return $collection; + } + $fqcnAlias = false; + foreach ($class->getMethods() as $method) { + $this->defaultRouteIndex = 0; + $routeNamesBefore = array_keys($collection->all()); + foreach ($this->getAnnotations($method) as $annot) { + $this->addRoute($collection, $annot, $globals, $class, $method); + if ('__invoke' === $method->name) { + $fqcnAlias = true; + } + } - $fqcnAlias = false; - foreach ($class->getMethods() as $method) { - $this->defaultRouteIndex = 0; - $routeNamesBefore = array_keys($collection->all()); - foreach ($this->getAnnotations($method) as $annot) { - $this->addRoute($collection, $annot, $globals, $class, $method); - if ('__invoke' === $method->name) { + if (1 === $collection->count() - \count($routeNamesBefore)) { + $newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore)); + $collection->addAlias(sprintf('%s::%s', $class->name, $method->name), $newRouteName); + } + } + if (0 === $collection->count() && $class->hasMethod('__invoke')) { + $globals = $this->resetGlobals(); + foreach ($this->getAnnotations($class) as $annot) { + $this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke')); $fqcnAlias = true; } } - - if (1 === $collection->count() - \count($routeNamesBefore)) { - $newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore)); - $collection->addAlias(sprintf('%s::%s', $class->name, $method->name), $newRouteName); + if ($fqcnAlias && 1 === $collection->count()) { + $collection->addAlias($class->name, $invokeRouteName = key($collection->all())); + $collection->addAlias(sprintf('%s::__invoke', $class->name), $invokeRouteName); } - } - if (0 === $collection->count() && $class->hasMethod('__invoke')) { - $globals = $this->resetGlobals(); - foreach ($this->getAnnotations($class) as $annot) { - $this->addRoute($collection, $annot, $globals, $class, $class->getMethod('__invoke')); - $fqcnAlias = true; + if ($this->hasDeprecatedAnnotations) { + trigger_deprecation('symfony/routing', '6.4', 'Class "%s" uses Doctrine Annotations to configure routes, which is deprecated. Use PHP attributes instead.', $class->getName()); } - } - - if ($fqcnAlias && 1 === $collection->count()) { - $collection->addAlias($class->name, $invokeRouteName = key($collection->all())); - $collection->addAlias(sprintf('%s::__invoke', $class->name), $invokeRouteName); + } finally { + $this->hasDeprecatedAnnotations = false; } return $collection; @@ -279,7 +291,7 @@ protected function getDefaultRouteName(\ReflectionClass $class, \ReflectionMetho } /** - * @return array + * @return array */ protected function getGlobals(\ReflectionClass $class) { @@ -289,8 +301,8 @@ protected function getGlobals(\ReflectionClass $class) if ($attribute = $class->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF)[0] ?? null) { $annot = $attribute->newInstance(); } - if (!$annot && $this->reader) { - $annot = $this->reader->getClassAnnotation($class, $this->routeAnnotationClass); + if (!$annot && $annot = $this->reader?->getClassAnnotation($class, $this->routeAnnotationClass)) { + $this->hasDeprecatedAnnotations = true; } if ($annot) { @@ -377,11 +389,9 @@ protected function createRoute(string $path, array $defaults, array $requirement abstract protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot); /** - * @param \ReflectionClass|\ReflectionMethod $reflection - * * @return iterable */ - private function getAnnotations(object $reflection): iterable + private function getAnnotations(\ReflectionClass|\ReflectionMethod $reflection): iterable { foreach ($reflection->getAttributes($this->routeAnnotationClass, \ReflectionAttribute::IS_INSTANCEOF) as $attribute) { yield $attribute->newInstance(); @@ -397,6 +407,8 @@ private function getAnnotations(object $reflection): iterable foreach ($annotations as $annotation) { if ($annotation instanceof $this->routeAnnotationClass) { + $this->hasDeprecatedAnnotations = true; + yield $annotation; } } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php index bd7ea962c144c..c6de0161aac9b 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/AbstractClass.php @@ -11,10 +11,13 @@ namespace Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses; +use Symfony\Component\Routing\Annotation\Route; + abstract class AbstractClass { abstract public function abstractRouteAction(); + #[Route('/path/to/route/{arg1}')] public function routeAction($arg1, $arg2 = 'defaultValue2', $arg3 = 'defaultValue3') { } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/VariadicClass.php b/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/VariadicClass.php index 729c9b4d07b38..01c14ed658294 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/VariadicClass.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/OtherAnnotatedClasses/VariadicClass.php @@ -11,8 +11,11 @@ namespace Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses; +use Symfony\Component\Routing\Annotation\Route; + class VariadicClass { + #[Route('/path/to/{id}')] public function routeAction(...$params) { } diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/TraceableAnnotationClassLoader.php b/src/Symfony/Component/Routing/Tests/Fixtures/TraceableAnnotationClassLoader.php new file mode 100644 index 0000000000000..ebc37c840bb19 --- /dev/null +++ b/src/Symfony/Component/Routing/Tests/Fixtures/TraceableAnnotationClassLoader.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Routing\Tests\Fixtures; + +use Symfony\Component\Routing\Loader\AnnotationClassLoader; +use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\RouteCollection; + +final class TraceableAnnotationClassLoader extends AnnotationClassLoader +{ + /** @var list */ + public array $foundClasses = []; + + public function load(mixed $class, string $type = null): RouteCollection + { + if (!is_string($class)) { + throw new \InvalidArgumentException(sprintf('Expected string, got "%s"', get_debug_type($class))); + } + + $this->foundClasses[] = $class; + + return parent::load($class, $type); + } + + protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void + { + } +} diff --git a/src/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTestCase.php b/src/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTestCase.php deleted file mode 100644 index e743ef2e35d50..0000000000000 --- a/src/Symfony/Component/Routing/Tests/Loader/AbstractAnnotationLoaderTestCase.php +++ /dev/null @@ -1,34 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Routing\Tests\Loader; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Routing\Loader\AnnotationClassLoader; - -abstract class AbstractAnnotationLoaderTestCase extends TestCase -{ - public function getReader() - { - return $this->getMockBuilder(\Doctrine\Common\Annotations\Reader::class) - ->disableOriginalConstructor() - ->getMock() - ; - } - - public function getClassLoader($reader) - { - return $this->getMockBuilder(AnnotationClassLoader::class) - ->setConstructorArgs([$reader]) - ->getMockForAbstractClass() - ; - } -} diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTestCase.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTestCase.php index 75589835e48f9..f8e54d6a75da6 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTestCase.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTestCase.php @@ -18,10 +18,7 @@ abstract class AnnotationClassLoaderTestCase extends TestCase { - /** - * @var AnnotationClassLoader - */ - protected $loader; + protected AnnotationClassLoader $loader; /** * @dataProvider provideTestSupportsChecksResource @@ -31,7 +28,7 @@ public function testSupportsChecksResource($resource, $expectedSupports) $this->assertSame($expectedSupports, $this->loader->supports($resource), '->supports() returns true if the resource is loadable'); } - public static function provideTestSupportsChecksResource() + public static function provideTestSupportsChecksResource(): array { return [ ['class', true], diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php index 3988d4354a0d2..f53e4e3ef3baf 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php @@ -12,19 +12,17 @@ namespace Symfony\Component\Routing\Tests\Loader; use Doctrine\Common\Annotations\AnnotationReader; -use Symfony\Component\Routing\Loader\AnnotationClassLoader; -use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader; +/** + * @group legacy + */ class AnnotationClassLoaderWithAnnotationsTest extends AnnotationClassLoaderTestCase { protected function setUp(string $env = null): void { $reader = new AnnotationReader(); - $this->loader = new class($reader, $env) extends AnnotationClassLoader { - protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void - { - } - }; + $this->loader = new TraceableAnnotationClassLoader($reader, $env); } public function testDefaultRouteName() diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAttributesTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAttributesTest.php index d613ba09b298b..2fe0f903189fd 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAttributesTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAttributesTest.php @@ -11,18 +11,13 @@ namespace Symfony\Component\Routing\Tests\Loader; -use Symfony\Component\Routing\Loader\AnnotationClassLoader; -use Symfony\Component\Routing\Route; +use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader; class AnnotationClassLoaderWithAttributesTest extends AnnotationClassLoaderTestCase { protected function setUp(string $env = null): void { - $this->loader = new class(null, $env) extends AnnotationClassLoader { - protected function configureRoute(Route $route, \ReflectionClass $class, \ReflectionMethod $method, object $annot): void - { - } - }; + $this->loader = new TraceableAnnotationClassLoader($env); } public function testDefaultRouteName() diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php index 5a7bc8cbbda53..a7c7f957dfc36 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationDirectoryLoaderTest.php @@ -11,63 +11,38 @@ namespace Symfony\Component\Routing\Tests\Loader; +use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader; +use Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass; +use Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass; +use Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass; +use Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\FooClass; +use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader; -class AnnotationDirectoryLoaderTest extends AbstractAnnotationLoaderTestCase +class AnnotationDirectoryLoaderTest extends TestCase { - protected $loader; - protected $reader; + private AnnotationDirectoryLoader $loader; + private TraceableAnnotationClassLoader $classLoader; protected function setUp(): void { parent::setUp(); - $this->reader = $this->getReader(); - $this->loader = new AnnotationDirectoryLoader(new FileLocator(), $this->getClassLoader($this->reader)); + $this->classLoader = new TraceableAnnotationClassLoader(); + $this->loader = new AnnotationDirectoryLoader(new FileLocator(), $this->classLoader); } public function testLoad() { - $this->reader->expects($this->exactly(4))->method('getClassAnnotation'); - - $this->reader - ->expects($this->any()) - ->method('getMethodAnnotations') - ->willReturn([]) - ; - - $this->reader - ->expects($this->any()) - ->method('getClassAnnotations') - ->willReturn([]) - ; - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses'); - } - - public function testLoadIgnoresHiddenDirectories() - { - $this->expectAnnotationsToBeReadFrom([ - 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BarClass', - 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\BazClass', - 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\FooClass', - 'Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\EncodingClass', - ]); - - $this->reader - ->expects($this->any()) - ->method('getMethodAnnotations') - ->willReturn([]) - ; - - $this->reader - ->expects($this->any()) - ->method('getClassAnnotations') - ->willReturn([]) - ; - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses'); + self::assertSame([ + BarClass::class, + BazClass::class, + EncodingClass::class, + FooClass::class, + ], $this->classLoader->foundClasses); } public function testSupports() @@ -89,29 +64,13 @@ public function testItSupportsAnyAnnotation() public function testLoadFileIfLocatedResourceIsFile() { - $this->reader->expects($this->exactly(1))->method('getClassAnnotation'); - - $this->reader - ->expects($this->any()) - ->method('getMethodAnnotations') - ->willReturn([]) - ; - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php'); + self::assertSame([FooClass::class], $this->classLoader->foundClasses); } public function testLoadAbstractClass() { - $this->reader->expects($this->never())->method('getClassAnnotation'); - $this->reader->expects($this->never())->method('getMethodAnnotations'); - - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/AbstractClass.php'); - } - - private function expectAnnotationsToBeReadFrom(array $classes) - { - $this->reader->expects($this->exactly(\count($classes))) - ->method('getClassAnnotation') - ->with($this->callback(fn (\ReflectionClass $class) => \in_array($class->getName(), $classes))); + self::assertNull($this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/AbstractClass.php')); + self::assertSame([], $this->classLoader->foundClasses); } } diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php index 473368156382f..d92760ae729cb 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationFileLoaderTest.php @@ -11,35 +11,45 @@ namespace Symfony\Component\Routing\Tests\Loader; +use Doctrine\Common\Annotations\AnnotationReader; +use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; -use Symfony\Component\Routing\Annotation\Route; use Symfony\Component\Routing\Loader\AnnotationFileLoader; - -class AnnotationFileLoaderTest extends AbstractAnnotationLoaderTestCase +use Symfony\Component\Routing\Tests\Fixtures\AnnotatedClasses\FooClass; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamAfterCommaController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamAfterParenthesisController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamInlineAfterCommaController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamInlineAfterParenthesisController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamInlineQuotedAfterCommaController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamInlineQuotedAfterParenthesisController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamQuotedAfterCommaController; +use Symfony\Component\Routing\Tests\Fixtures\AttributesFixtures\AttributesClassParamQuotedAfterParenthesisController; +use Symfony\Component\Routing\Tests\Fixtures\OtherAnnotatedClasses\VariadicClass; +use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader; + +class AnnotationFileLoaderTest extends TestCase { - protected $loader; - protected $reader; + private AnnotationFileLoader $loader; + private TraceableAnnotationClassLoader $classLoader; protected function setUp(): void { parent::setUp(); - $this->reader = $this->getReader(); - $this->loader = new AnnotationFileLoader(new FileLocator(), $this->getClassLoader($this->reader)); + $this->classLoader = new TraceableAnnotationClassLoader(); + $this->loader = new AnnotationFileLoader(new FileLocator(), $this->classLoader); } public function testLoad() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooClass.php')); + self::assertSame([FooClass::class], $this->classLoader->foundClasses); } public function testLoadTraitWithClassConstant() { - $this->reader->expects($this->never())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooTrait.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/FooTrait.php')); + self::assertSame([], $this->classLoader->foundClasses); } public function testLoadFileWithoutStartTag() @@ -51,28 +61,26 @@ public function testLoadFileWithoutStartTag() public function testLoadVariadic() { - $route = new Route('/path/to/{id}'); - $this->reader->expects($this->once())->method('getClassAnnotation'); - $this->reader->expects($this->once())->method('getMethodAnnotations') - ->willReturn([$route]); - - $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/VariadicClass.php'); + self::assertCount(1, $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/VariadicClass.php')); + self::assertSame([VariadicClass::class], $this->classLoader->foundClasses); } + /** + * @group legacy + */ public function testLoadAnonymousClass() { - $this->reader->expects($this->never())->method('getClassAnnotation'); - $this->reader->expects($this->never())->method('getMethodAnnotations'); + $this->classLoader = new TraceableAnnotationClassLoader(new AnnotationReader()); + $this->loader = new AnnotationFileLoader(new FileLocator(), $this->classLoader); - $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/OtherAnnotatedClasses/AnonymousClassInTrait.php')); + self::assertSame([], $this->classLoader->foundClasses); } public function testLoadAbstractClass() { - $this->reader->expects($this->never())->method('getClassAnnotation'); - $this->reader->expects($this->never())->method('getMethodAnnotations'); - - $this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/AbstractClass.php'); + self::assertNull($this->loader->load(__DIR__.'/../Fixtures/AnnotatedClasses/AbstractClass.php')); + self::assertSame([], $this->classLoader->foundClasses); } public function testSupports() @@ -89,57 +97,49 @@ public function testSupports() public function testLoadAttributesClassAfterComma() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamAfterCommaController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamAfterCommaController.php')); + self::assertSame([AttributesClassParamAfterCommaController::class], $this->classLoader->foundClasses); } public function testLoadAttributesInlineClassAfterComma() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineAfterCommaController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineAfterCommaController.php')); + self::assertSame([AttributesClassParamInlineAfterCommaController::class], $this->classLoader->foundClasses); } public function testLoadAttributesQuotedClassAfterComma() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamQuotedAfterCommaController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamQuotedAfterCommaController.php')); + self::assertSame([AttributesClassParamQuotedAfterCommaController::class], $this->classLoader->foundClasses); } public function testLoadAttributesInlineQuotedClassAfterComma() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterCommaController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterCommaController.php')); + self::assertSame([AttributesClassParamInlineQuotedAfterCommaController::class], $this->classLoader->foundClasses); } public function testLoadAttributesClassAfterParenthesis() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamAfterParenthesisController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamAfterParenthesisController.php')); + self::assertSame([AttributesClassParamAfterParenthesisController::class], $this->classLoader->foundClasses); } public function testLoadAttributesInlineClassAfterParenthesis() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineAfterParenthesisController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineAfterParenthesisController.php')); + self::assertSame([AttributesClassParamInlineAfterParenthesisController::class], $this->classLoader->foundClasses); } public function testLoadAttributesQuotedClassAfterParenthesis() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamQuotedAfterParenthesisController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamQuotedAfterParenthesisController.php')); + self::assertSame([AttributesClassParamQuotedAfterParenthesisController::class], $this->classLoader->foundClasses); } public function testLoadAttributesInlineQuotedClassAfterParenthesis() { - $this->reader->expects($this->once())->method('getClassAnnotation'); - - $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterParenthesisController.php'); + self::assertCount(0, $this->loader->load(__DIR__.'/../Fixtures/AttributesFixtures/AttributesClassParamInlineQuotedAfterParenthesisController.php')); + self::assertSame([AttributesClassParamInlineQuotedAfterParenthesisController::class], $this->classLoader->foundClasses); } } diff --git a/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php index d4f2fd3263b48..b78874195cc8e 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/DirectoryLoaderTest.php @@ -11,28 +11,28 @@ namespace Symfony\Component\Routing\Tests\Loader; +use PHPUnit\Framework\TestCase; use Symfony\Component\Config\FileLocator; use Symfony\Component\Config\Loader\LoaderResolver; use Symfony\Component\Routing\Loader\AnnotationFileLoader; use Symfony\Component\Routing\Loader\DirectoryLoader; use Symfony\Component\Routing\Loader\YamlFileLoader; use Symfony\Component\Routing\RouteCollection; +use Symfony\Component\Routing\Tests\Fixtures\TraceableAnnotationClassLoader; -class DirectoryLoaderTest extends AbstractAnnotationLoaderTestCase +class DirectoryLoaderTest extends TestCase { - private $loader; - private $reader; + private DirectoryLoader $loader; protected function setUp(): void { parent::setUp(); $locator = new FileLocator(); - $this->reader = $this->getReader(); $this->loader = new DirectoryLoader($locator); $resolver = new LoaderResolver([ new YamlFileLoader($locator), - new AnnotationFileLoader($locator, $this->getClassLoader($this->reader)), + new AnnotationFileLoader($locator, new TraceableAnnotationClassLoader()), $this->loader, ]); $this->loader->setResolver($resolver); 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