From d83270d2083778206a45ebc070aa1561900edc3f Mon Sep 17 00:00:00 2001 From: Tim Goudriaan Date: Wed, 16 Feb 2022 00:50:03 +0100 Subject: [PATCH 1/2] Refactor fixtures of ArgumentMetadata tests --- .../ArgumentMetadataFactoryTest.php | 16 ++++++++-------- .../ControllerMetadata/ArgumentMetadataTest.php | 6 +++--- .../Fixtures/Attribute/{Foo.php => FooParam.php} | 2 +- ...oller.php => ArgumentAttributeController.php} | 10 +++++----- 4 files changed, 17 insertions(+), 17 deletions(-) rename src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/{Foo.php => FooParam.php} (96%) rename src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/{AttributeController.php => ArgumentAttributeController.php} (51%) diff --git a/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php b/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php index ec5a55243fb07..f22664eea99dd 100644 --- a/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php @@ -15,8 +15,8 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactory; -use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\Foo; -use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\AttributeController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooParam; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ArgumentAttributeController; use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\BasicTypesController; use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\NullableController; use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\VariadicController; @@ -121,24 +121,24 @@ public function testNullableTypesSignature() public function testAttributeSignature() { - $arguments = $this->factory->createArgumentMetadata([new AttributeController(), 'action']); + $arguments = $this->factory->createArgumentMetadata([new ArgumentAttributeController(), 'action']); $this->assertEquals([ - new ArgumentMetadata('baz', 'string', false, false, null, false, [new Foo('bar')]), + new ArgumentMetadata('baz', 'string', false, false, null, false, [new FooParam('bar')]), ], $arguments); } public function testMultipleAttributes() { - $this->factory->createArgumentMetadata([new AttributeController(), 'multiAttributeArg']); - $this->assertCount(1, $this->factory->createArgumentMetadata([new AttributeController(), 'multiAttributeArg'])[0]->getAttributes()); + $this->factory->createArgumentMetadata([new ArgumentAttributeController(), 'multiAttributeArg']); + $this->assertCount(1, $this->factory->createArgumentMetadata([new ArgumentAttributeController(), 'multiAttributeArg'])[0]->getAttributes()); } public function testIssue41478() { - $arguments = $this->factory->createArgumentMetadata([new AttributeController(), 'issue41478']); + $arguments = $this->factory->createArgumentMetadata([new ArgumentAttributeController(), 'issue41478']); $this->assertEquals([ - new ArgumentMetadata('baz', 'string', false, false, null, false, [new Foo('bar')]), + new ArgumentMetadata('baz', 'string', false, false, null, false, [new FooParam('bar')]), new ArgumentMetadata('bat', 'string', false, false, null, false, []), ], $arguments); } diff --git a/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataTest.php b/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataTest.php index 8ef1fe678ecf1..bb83d41c8591d 100644 --- a/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataTest.php @@ -13,7 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata; -use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\Foo; +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooParam; class ArgumentMetadataTest extends TestCase { @@ -45,7 +45,7 @@ public function testDefaultValueUnavailable() public function testGetAttributes() { - $argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true, [new Foo('bar')]); - $this->assertEquals([new Foo('bar')], $argument->getAttributes()); + $argument = new ArgumentMetadata('foo', 'string', false, true, 'default value', true, [new FooParam('bar')]); + $this->assertEquals([new FooParam('bar')], $argument->getAttributes()); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/Foo.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooParam.php similarity index 96% rename from src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/Foo.php rename to src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooParam.php index 1089c81bf2685..054fc5c9455e2 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/Foo.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooParam.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\Fixtures\Attribute; #[\Attribute(\Attribute::TARGET_PARAMETER)] -class Foo +class FooParam { private $foo; diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/AttributeController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ArgumentAttributeController.php similarity index 51% rename from src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/AttributeController.php rename to src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ArgumentAttributeController.php index 92e54f400d014..410904d0ec7e1 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/AttributeController.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ArgumentAttributeController.php @@ -11,19 +11,19 @@ namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; -use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\Foo; +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooParam; -class AttributeController +class ArgumentAttributeController { - public function action(#[Foo('bar')] string $baz) + public function action(#[FooParam('bar')] string $baz) { } - public function multiAttributeArg(#[Foo('bar'), Undefined('bar')] string $baz) + public function multiAttributeArg(#[FooParam('bar'), Undefined('bar')] string $baz) { } - public function issue41478(#[Foo('bar')] string $baz, string $bat) + public function issue41478(#[FooParam('bar')] string $baz, string $bat) { } } From 27a2403c633d93d9137d31012a14cc89af9f9b32 Mon Sep 17 00:00:00 2001 From: Tim Goudriaan Date: Thu, 17 Feb 2022 11:50:44 +0100 Subject: [PATCH 2/2] Add ControllerAttributeListener --- .../Resources/config/controller.php | 21 ++ .../ControllerAttributeInterface.php | 10 + .../ControllerAttributeListener.php | 82 ++++++++ .../ControllerAttributeListenerTest.php | 185 ++++++++++++++++++ .../Fixtures/Attribute/FooController.php | 13 ++ .../Attribute/RepeatableFooController.php | 13 ++ ...lerAttributeAtClassAndMethodController.php | 27 +++ .../ControllerAttributeAtClassController.php | 22 +++ .../ControllerAttributeAtMethodController.php | 22 +++ ...lerAttributeAtClassAndMethodController.php | 29 +++ ...leControllerAttributeAtClassController.php | 23 +++ ...eControllerAttributeAtMethodController.php | 23 +++ 12 files changed, 470 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Resources/config/controller.php create mode 100644 src/Symfony/Component/HttpKernel/Attribute/ControllerAttributeInterface.php create mode 100644 src/Symfony/Component/HttpKernel/EventListener/ControllerAttributeListener.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/EventListener/ControllerAttributeListenerTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/RepeatableFooController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtClassAndMethodController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtClassController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtMethodController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassAndMethodController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassController.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtMethodController.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/controller.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/controller.php new file mode 100644 index 0000000000000..66a9c09260de4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/controller.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\DependencyInjection\Loader\Configurator; + +use Symfony\Component\HttpKernel\EventListener\ControllerAttributeListener; + +return static function (ContainerConfigurator $container) { + $container->services() + ->set('controller_attribute_listener', ControllerAttributeListener::class) + ->tag('kernel.event_subscriber') + ; +}; diff --git a/src/Symfony/Component/HttpKernel/Attribute/ControllerAttributeInterface.php b/src/Symfony/Component/HttpKernel/Attribute/ControllerAttributeInterface.php new file mode 100644 index 0000000000000..f57ba89414ef6 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Attribute/ControllerAttributeInterface.php @@ -0,0 +1,10 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\EventListener; + +use Doctrine\Persistence\Proxy; +use Symfony\Component\EventDispatcher\EventSubscriberInterface; +use Symfony\Component\HttpKernel\Attribute\ControllerAttributeInterface; +use Symfony\Component\HttpKernel\Event\ControllerEvent; +use Symfony\Component\HttpKernel\KernelEvents; + +/** + * The ControllerAttributeListener class parses attributes marked + * as controller attributes in controllers. + * + * @author Fabien Potencier + * @author Tim Goudriaan + */ +class ControllerAttributeListener implements EventSubscriberInterface +{ + public function onKernelController(ControllerEvent $event) + { + $controller = $event->getController(); + + if (!\is_array($controller) && method_exists($controller, '__invoke')) { + $controller = [$controller, '__invoke']; + } + + if (!\is_array($controller)) { + return; + } + + $className = self::getRealClass(\get_class($controller[0])); + $object = new \ReflectionClass($className); + $method = $object->getMethod($controller[1]); + + $classAttributes = $object->getAttributes(ControllerAttributeInterface::class, \ReflectionAttribute::IS_INSTANCEOF); + $methodAttributes = $method->getAttributes(ControllerAttributeInterface::class, \ReflectionAttribute::IS_INSTANCEOF); + + $attributes = []; + foreach (array_merge($classAttributes, $methodAttributes) as $attribute) { + if ($attribute->isRepeated()) { + $attributes[$attribute->getName()][] = $attribute->newInstance(); + } else { + // method attribute overrides class attribute + $attributes[$attribute->getName()] = $attribute->newInstance(); + } + } + + $request = $event->getRequest(); + $request->attributes->set('_controller_attributes', $attributes); + } + + /** + * {@inheritdoc} + */ + public static function getSubscribedEvents(): array + { + return [KernelEvents::CONTROLLER => 'onKernelController']; + } + + private static function getRealClass(string $class): string + { + if (class_exists(Proxy::class)) { + if (false === $pos = strrpos($class, '\\'.Proxy::MARKER.'\\')) { + return $class; + } + + return substr($class, $pos + Proxy::MARKER_LENGTH + 2); + } + + return $class; + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ControllerAttributeListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ControllerAttributeListenerTest.php new file mode 100644 index 0000000000000..89016fda2f1de --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ControllerAttributeListenerTest.php @@ -0,0 +1,185 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\EventListener; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Event\ControllerEvent; +use Symfony\Component\HttpKernel\EventListener\ControllerAttributeListener; +use Symfony\Component\HttpKernel\HttpKernelInterface; +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\RepeatableFooController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ControllerAttributeAtClassAndMethodController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ControllerAttributeAtClassController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\ControllerAttributeAtMethodController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\RepeatableControllerAttributeAtClassAndMethodController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\RepeatableControllerAttributeAtClassController; +use Symfony\Component\HttpKernel\Tests\Fixtures\Controller\RepeatableControllerAttributeAtMethodController; + +class ControllerAttributeListenerTest extends TestCase +{ + public function testAttributeAtClass() + { + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new ControllerAttributeAtClassController(), 'foo'], + $request, + null + ); + + $listener = new ControllerAttributeListener(); + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertEquals('class', $attributes[FooController::class]->bar); + } + + public function testAttributeAtMethod() + { + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new ControllerAttributeAtMethodController(), 'foo'], + $request, + null + ); + + $listener = new ControllerAttributeListener(); + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertEquals('method', $attributes[FooController::class]->bar); + } + + public function testAttributeAtClassAndMethod() + { + $listener = new ControllerAttributeListener(); + + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new ControllerAttributeAtClassAndMethodController(), 'foo'], + $request, + null + ); + + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertEquals('method', $attributes[FooController::class]->bar); + + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new ControllerAttributeAtClassAndMethodController(), 'bar'], + $request, + null + ); + + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertEquals('class', $attributes[FooController::class]->bar); + } + + public function testRepeatableAttributeAtClass() + { + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new RepeatableControllerAttributeAtClassController(), 'foo'], + $request, + null + ); + + $listener = new ControllerAttributeListener(); + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertCount(2, $attributes[RepeatableFooController::class]); + $this->assertEquals('class1', $attributes[RepeatableFooController::class][0]->bar); + $this->assertEquals('class2', $attributes[RepeatableFooController::class][1]->bar); + } + + public function testRepeatableAttributeAtMethod() + { + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new RepeatableControllerAttributeAtMethodController(), 'foo'], + $request, + null + ); + + $listener = new ControllerAttributeListener(); + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertCount(2, $attributes[RepeatableFooController::class]); + $this->assertEquals('method1', $attributes[RepeatableFooController::class][0]->bar); + $this->assertEquals('method2', $attributes[RepeatableFooController::class][1]->bar); + } + + public function testRepeatableAttributeAtClassAndMethod() + { + $listener = new ControllerAttributeListener(); + + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new RepeatableControllerAttributeAtClassAndMethodController(), 'foo'], + $request, + null + ); + + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertCount(4, $attributes[RepeatableFooController::class]); + $this->assertEquals('class1', $attributes[RepeatableFooController::class][0]->bar); + $this->assertEquals('class2', $attributes[RepeatableFooController::class][1]->bar); + $this->assertEquals('method1', $attributes[RepeatableFooController::class][2]->bar); + $this->assertEquals('method2', $attributes[RepeatableFooController::class][3]->bar); + + $request = new Request(); + + $event = new ControllerEvent( + $this->getMockBuilder(HttpKernelInterface::class)->getMock(), + [new RepeatableControllerAttributeAtClassAndMethodController(), 'bar'], + $request, + null + ); + + $listener->onKernelController($event); + + $this->assertNotNull($attributes = $request->attributes->get('_controller_attributes')); + $this->assertCount(1, $attributes); + $this->assertCount(2, $attributes[RepeatableFooController::class]); + $this->assertEquals('class1', $attributes[RepeatableFooController::class][0]->bar); + $this->assertEquals('class2', $attributes[RepeatableFooController::class][1]->bar); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooController.php new file mode 100644 index 0000000000000..b1194f8401f0c --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Attribute/FooController.php @@ -0,0 +1,13 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooController; + +#[FooController(bar: 'class')] +class ControllerAttributeAtClassAndMethodController +{ + #[FooController(bar: 'method')] + public function foo() + { + } + + public function bar() + { + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtClassController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtClassController.php new file mode 100644 index 0000000000000..35b07fc85244d --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtClassController.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooController; + +#[FooController(bar: 'class')] +class ControllerAttributeAtClassController +{ + public function foo() + { + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtMethodController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtMethodController.php new file mode 100644 index 0000000000000..ea0d2589fc68b --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/ControllerAttributeAtMethodController.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\FooController; + +class ControllerAttributeAtMethodController +{ + #[FooController(bar: 'method')] + public function foo() + { + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassAndMethodController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassAndMethodController.php new file mode 100644 index 0000000000000..857c9399e25b2 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassAndMethodController.php @@ -0,0 +1,29 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\RepeatableFooController; + +#[RepeatableFooController(bar: 'class1')] +#[RepeatableFooController(bar: 'class2')] +class RepeatableControllerAttributeAtClassAndMethodController +{ + #[RepeatableFooController(bar: 'method1')] + #[RepeatableFooController(bar: 'method2')] + public function foo() + { + } + + public function bar() + { + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassController.php new file mode 100644 index 0000000000000..71cc53fc96723 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtClassController.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\RepeatableFooController; + +#[RepeatableFooController(bar: 'class1')] +#[RepeatableFooController(bar: 'class2')] +class RepeatableControllerAttributeAtClassController +{ + public function foo() + { + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtMethodController.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtMethodController.php new file mode 100644 index 0000000000000..0d6be4c250ca9 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/Controller/RepeatableControllerAttributeAtMethodController.php @@ -0,0 +1,23 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\Controller; + +use Symfony\Component\HttpKernel\Tests\Fixtures\Attribute\RepeatableFooController; + +class RepeatableControllerAttributeAtMethodController +{ + #[RepeatableFooController(bar: 'method1')] + #[RepeatableFooController(bar: 'method2')] + public function foo() + { + } +}