From 172e1c9760f229cce3f68074d7cd2742bd7619fa Mon Sep 17 00:00:00 2001 From: Philipp Fritsche Date: Wed, 12 May 2021 13:37:57 +0200 Subject: [PATCH] fix: remove dependency on SensioFrameworkExtraBundle --- README.md | 6 +- composer.json | 8 +- composer.lock | 80 +------------------ src/Configuration/ConfigurationAnnotation.php | 41 +++++++--- src/EventSubscriber/ControllerSubscriber.php | 26 +++++- .../ConfigurationAnnotationTest.php | 11 --- .../ControllerSubscriberTest.php | 47 ++++++++++- 7 files changed, 104 insertions(+), 115 deletions(-) diff --git a/README.md b/README.md index e496a8f..7046716 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ pitch_adr: - { value: Bar, not: BadBar } ``` -If [SensioFrameworkExtraBundle](https://symfony.com/doc/current/bundles/SensioFrameworkExtraBundle/index.html) is installed, +If [Doctrine Annotations](https://github.com/doctrine/annotations/) is installed, you can define extra rules for your controller methods per annotation: ```php namespace App\Controller; @@ -80,8 +80,8 @@ use Pitch\AdrBundle\Configuration\Graceful; class MyController { /** - * @Graceful(not={LocallyBadException}) - * @Graceful(LocallyGoodException, not={ButNotThisOne, OrThatOne}) + * @Graceful(not={LocallyBadException::class}) + * @Graceful(LocallyGoodException::class, not={ButNotThisOne::class, OrThatOne::class}) */ public function __invoke( Request $request diff --git a/composer.json b/composer.json index 66a38fe..38d51d1 100644 --- a/composer.json +++ b/composer.json @@ -28,13 +28,11 @@ }, "require-dev": { "phpunit/phpunit": "^9", - "sensio/framework-extra-bundle": "^6", + "symfony/framework-bundle": "^5", "squizlabs/php_codesniffer": "^3.2", "symfony/yaml": "^5", - "mikey179/vfsstream": "^1.6" - }, - "suggest": { - "sensio/framework-extra-bundle": "^6" + "mikey179/vfsstream": "^1.6", + "doctrine/annotations": "^1.12" }, "scripts": { "lint": "phpcs --standard=ruleset.xml src test", diff --git a/composer.lock b/composer.lock index 1e9870f..b11e8fd 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "b263a1305ff204531aeb4710afa9b917", + "content-hash": "48c317fea0321573d4731d2ec5c66c69", "packages": [ { "name": "composer/ca-bundle", @@ -4667,84 +4667,6 @@ ], "time": "2020-09-28T06:39:44+00:00" }, - { - "name": "sensio/framework-extra-bundle", - "version": "v6.1.2", - "source": { - "type": "git", - "url": "https://github.com/sensiolabs/SensioFrameworkExtraBundle.git", - "reference": "676262b7a65a1033befbcf59e180d072df7504b6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/sensiolabs/SensioFrameworkExtraBundle/zipball/676262b7a65a1033befbcf59e180d072df7504b6", - "reference": "676262b7a65a1033befbcf59e180d072df7504b6", - "shasum": "" - }, - "require": { - "doctrine/annotations": "^1.0", - "php": ">=7.2.5", - "symfony/config": "^4.4|^5.0", - "symfony/dependency-injection": "^4.4|^5.0", - "symfony/framework-bundle": "^4.4|^5.0", - "symfony/http-kernel": "^4.4|^5.0" - }, - "conflict": { - "doctrine/doctrine-cache-bundle": "<1.3.1", - "doctrine/persistence": "<1.3" - }, - "require-dev": { - "doctrine/dbal": "^2.10|^3.0", - "doctrine/doctrine-bundle": "^1.11|^2.0", - "doctrine/orm": "^2.5", - "symfony/browser-kit": "^4.4|^5.0", - "symfony/doctrine-bridge": "^4.4|^5.0", - "symfony/dom-crawler": "^4.4|^5.0", - "symfony/expression-language": "^4.4|^5.0", - "symfony/finder": "^4.4|^5.0", - "symfony/monolog-bridge": "^4.0|^5.0", - "symfony/monolog-bundle": "^3.2", - "symfony/phpunit-bridge": "^4.4.9|^5.0.9", - "symfony/security-bundle": "^4.4|^5.0", - "symfony/twig-bundle": "^4.4|^5.0", - "symfony/yaml": "^4.4|^5.0", - "twig/twig": "^1.34|^2.4|^3.0" - }, - "type": "symfony-bundle", - "extra": { - "branch-alias": { - "dev-master": "6.1.x-dev" - } - }, - "autoload": { - "psr-4": { - "Sensio\\Bundle\\FrameworkExtraBundle\\": "src/" - }, - "exclude-from-classmap": [ - "/tests/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Fabien Potencier", - "email": "fabien@symfony.com" - } - ], - "description": "This bundle provides a way to configure your controllers with annotations", - "keywords": [ - "annotations", - "controllers" - ], - "support": { - "issues": "https://github.com/sensiolabs/SensioFrameworkExtraBundle/issues", - "source": "https://github.com/sensiolabs/SensioFrameworkExtraBundle/tree/v6.1.2" - }, - "time": "2021-04-09T16:14:11+00:00" - }, { "name": "squizlabs/php_codesniffer", "version": "3.6.0", diff --git a/src/Configuration/ConfigurationAnnotation.php b/src/Configuration/ConfigurationAnnotation.php index 685bea1..7c39a2e 100644 --- a/src/Configuration/ConfigurationAnnotation.php +++ b/src/Configuration/ConfigurationAnnotation.php @@ -1,22 +1,35 @@ $v) { $setterName = 'set' . \ucwords($propertyName); if (\method_exists($this, $setterName)) { + $reflMethod = new ReflectionMethod($this, $setterName); + + $this->typecast( + $v, + $reflMethod->getNumberOfParameters() >= 1 + ? $reflMethod->getParameters()[0]->getType() + : null, + ); + $this->$setterName($v); } elseif (\property_exists($this, $propertyName)) { + $reflProp = new ReflectionProperty($this, $propertyName); + + $this->typecast($v, $reflProp->getType()); + $this->$propertyName = $v; } else { throw new RuntimeException(\sprintf( @@ -28,13 +41,15 @@ public function __construct( } } - public function allowArray(): bool - { - return static::ALLOW_ARRAY; - } - - public function getAliasName(): ?string - { - return static::ALIAS_NAME; + private function typecast( + &$value, + ?ReflectionType $type, + ) { + if ($type instanceof ReflectionNamedType + && gettype($value) !== $type->getName() + && !is_a($value, $type->getName()) + ) { + settype($value, $type->getName()); + } } } diff --git a/src/EventSubscriber/ControllerSubscriber.php b/src/EventSubscriber/ControllerSubscriber.php index 680f2dd..894e4b0 100644 --- a/src/EventSubscriber/ControllerSubscriber.php +++ b/src/EventSubscriber/ControllerSubscriber.php @@ -1,19 +1,25 @@ reader = $reader; $this->globalGraceful = \array_map(fn($g) => new Graceful($g), (array) $globalGraceful); } @@ -24,9 +30,27 @@ public static function getSubscribedEvents() ]; } + public function onKernelController(ControllerEvent $event) + { + $controller = $event->getController(); + + if (\is_object($controller)) { + $controller = [$controller, '__invoke']; + } + + $reflMethod = new ReflectionMethod($controller[0], $controller[1]); + + $annotations = $this->reader + ? $this->reader->getMethodAnnotations($reflMethod) + : []; + + $event->getRequest()->attributes->set('_' . Graceful::class, $annotations); + } + public function onKernelControllerArguments(ControllerArgumentsEvent $event) { - $graceful = (array) $event->getRequest()->attributes->get('_' . Graceful::ALIAS_NAME); + + $graceful = (array) $event->getRequest()->attributes->get('_' . Graceful::class); if (\count($this->globalGraceful) === 0 && \count($graceful) === 0) { return; diff --git a/test/Configuration/ConfigurationAnnotationTest.php b/test/Configuration/ConfigurationAnnotationTest.php index 410a774..8290800 100644 --- a/test/Configuration/ConfigurationAnnotationTest.php +++ b/test/Configuration/ConfigurationAnnotationTest.php @@ -5,17 +5,6 @@ class ConfigurationAnnotationTest extends \PHPUnit\Framework\TestCase { - public function testConfigurationInterface() - { - $testClass = new class() extends ConfigurationAnnotation { - const ALIAS_NAME = 'foo'; - const ALLOW_ARRAY = true; - }; - - $this->assertEquals($testClass::ALIAS_NAME, $testClass->getAliasName()); - $this->assertEquals($testClass::ALLOW_ARRAY, $testClass->allowArray()); - } - public function testConstructWithProperty() { $testClass = new class([ diff --git a/test/EventSubscriber/ControllerSubscriberTest.php b/test/EventSubscriber/ControllerSubscriberTest.php index e68058a..02d2383 100644 --- a/test/EventSubscriber/ControllerSubscriberTest.php +++ b/test/EventSubscriber/ControllerSubscriberTest.php @@ -1,14 +1,40 @@ getControllerEvent(new class { + /** + * @Graceful("Foo") + * @Graceful("Bar", not={"Baz"}) + */ + public function __invoke() + { + } + }); + + // without Doctrine Annotations + $this->getSubscriberObject([], false)->onKernelController($event); + $this->assertEquals([], $event->getRequest()->attributes->get('_' . Graceful::class)); + + // with Doctrine Annotations + $this->getSubscriberObject([], true)->onKernelController($event); + $this->assertEquals([ + new Graceful(['value' => 'Foo']), + new Graceful(['value' => 'Bar', 'not' => 'Baz']), + ], $event->getRequest()->attributes->get('_' . Graceful::class)); + } + public function provideGraceful(): array { return [ @@ -81,6 +107,17 @@ protected function getGracefulForArray( return \array_map(fn($g) => new Graceful($g), $gracefulList); } + protected function getControllerEvent( + callable $controller, + ): ControllerEvent { + return new ControllerEvent( + $this->createMock(HttpKernelInterface::class), + $controller, + new Request(), + HttpKernelInterface::MASTER_REQUEST, + ); + } + /** * @param Graceful[] $controllerGraceful */ @@ -88,7 +125,7 @@ protected function getControllerArgumentsEvent( array $controllerGraceful ): ControllerArgumentsEvent { $request = new Request(); - $request->attributes->set('_' . Graceful::ALIAS_NAME, $controllerGraceful); + $request->attributes->set('_' . Graceful::class, $controllerGraceful); return new ControllerArgumentsEvent( $this->createMock(HttpKernelInterface::class), @@ -101,8 +138,12 @@ function () { } protected function getSubscriberObject( - array $globalGraceful = [] + array $globalGraceful = [], + bool $reader = false, ): ControllerSubscriber { - return new ControllerSubscriber($globalGraceful); + return new ControllerSubscriber( + $reader ? new AnnotationReader() : null, + $globalGraceful, + ); } }