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() + { + } +} 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