From 3de4699ba106c6b27be0e22c5e0ae29e745d5c6d Mon Sep 17 00:00:00 2001 From: Michel Chowanski Date: Fri, 7 Feb 2025 16:39:35 +0100 Subject: [PATCH] feature(annotation): #27 remove deprecated doctrine/annotations implementation --- CHANGELOG.md | 4 + composer.json | 1 - docs/annotation.md | 47 ----- docs/attribute.md | 2 +- docs/usage.md | 17 +- src/Annotations/Feature.php | 20 -- src/DependencyInjection/Configuration.php | 14 -- .../FlagceptionExtension.php | 5 - src/Listener/AnnotationSubscriber.php | 104 ---------- src/Listener/AttributeSubscriber.php | 2 +- src/Resources/config/services.yml | 10 - .../FlagceptionExtensionTest.php | 59 ------ tests/Fixtures/Helper/AnnotationTestClass.php | 43 ---- tests/Fixtures/Helper/AttributeTestClass.php | 2 +- tests/Listener/AnnotationSubscriberTest.php | 193 ------------------ tests/Listener/AttributeSubscriberTest.php | 3 +- 16 files changed, 13 insertions(+), 513 deletions(-) delete mode 100644 docs/annotation.md delete mode 100644 src/Annotations/Feature.php delete mode 100644 src/Listener/AnnotationSubscriber.php delete mode 100644 tests/Fixtures/Helper/AnnotationTestClass.php delete mode 100644 tests/Listener/AnnotationSubscriberTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index bd6f41f..0f3234f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## [x.x.x] +### Removed +- \#27 Remove deprecated `doctrine/annotations` implementation + ## [5.0.0] ### Added - \#3 Support for PHP8 attributes @axwel13 diff --git a/composer.json b/composer.json index 7cc9abb..4abf6cf 100644 --- a/composer.json +++ b/composer.json @@ -17,7 +17,6 @@ "symfony/config": "^4.4 | ^5.0 | ^6.0 | ^7.0", "symfony/http-kernel": "^4.4 | ^5.0 | ^6.0 | ^7.0", "twig/twig": "^1.18|^2.0|^3.0", - "doctrine/annotations": "^1.7 | ^2.0", "flagception/flagception": "^1.5" }, "require-dev": { diff --git a/docs/annotation.md b/docs/annotation.md deleted file mode 100644 index 5effbde..0000000 --- a/docs/annotation.md +++ /dev/null @@ -1,47 +0,0 @@ -Annotation -------------------------- -You can use annotations for checking the feature state in controllers. Just active this in your config: - -```yml -# config.yml - -flagception: - features: - feature_123: - default: true - - # Use annotation? (optional) - annotation: - - # Enable controller annotation (default: false) - enable: true -``` - - -We recommend to use the route attribute solution, because using annotations has performance issues. -A `NotFoundHttpException` will be thrown if you request an action or class with inactive feature flag. - - -```php -# FooController.php - -use Flagception\Bundle\FlagceptionBundle\Annotations\Feature; - -/** - * @Feature("feature_123") - */ -class FooController -{ - - /** - * @Feature("feature_789") - */ - public function barAction() - { - } - - public function fooAction() - { - } -} -``` diff --git a/docs/attribute.md b/docs/attribute.md index 104b1fe..27ba14e 100644 --- a/docs/attribute.md +++ b/docs/attribute.md @@ -1,6 +1,6 @@ Attribute ------------------------- -We recommend to use the route attribute solution, because using annotations has performance issues. +We recommend to use the route attribute solution. A `NotFoundHttpException` will be thrown if you request an action or class with inactive feature flag. diff --git a/docs/usage.md b/docs/usage.md index 5b36a5d..111f8eb 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -87,21 +87,16 @@ class BlogController extends Controller } ``` -##### Annotation usage +##### Attribute usage ```php # FooController.php -use Flagception\Bundle\FlagceptionBundle\Annotations\Feature; +use Flagception\Bundle\FlagceptionBundle\Attribute\Feature; -/** - * @Feature("feature_123") - */ +#[Feature("feature_123")] class FooController { - - /** - * @Feature("feature_789") - */ + #[Feature("feature_789")] public function barAction() { } @@ -112,9 +107,7 @@ class FooController } ``` -If you request an action with inactive feature flag, you will get a `NotFoundHttpException`. - -Take a look to the detail documentation for [Twig](twig.md), [Route](route.md) or [Annotation](annotation.md) usage. +Take a look to the detail documentation for [Twig](twig.md), [Route](route.md) or [Attribute](attribute.md) usage. ##### Feature names You can name your features as you like. But we recommend using [snake case](https://en.wikipedia.org/wiki/Snake_case). diff --git a/src/Annotations/Feature.php b/src/Annotations/Feature.php deleted file mode 100644 index 683a315..0000000 --- a/src/Annotations/Feature.php +++ /dev/null @@ -1,20 +0,0 @@ - - * @package Flagception\Bundle\FlagceptionBundle\Annotations - * @Annotation - */ -class Feature -{ - /** - * Name of feature - * - * @var string - */ - public $name; -} diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 06b32d8..755d997 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -69,20 +69,6 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->defaultValue([]) ->end() - ->arrayNode('annotation') - ->addDefaultsIfNotSet() - ->children() - ->booleanNode('enable') - ->beforeNormalization() - ->ifString() - ->then(function ($value) { - return filter_var($value, FILTER_VALIDATE_BOOLEAN); - }) - ->end() - ->defaultFalse() - ->end() - ->end() - ->end() ->arrayNode('routing_metadata') ->addDefaultsIfNotSet() ->children() diff --git a/src/DependencyInjection/FlagceptionExtension.php b/src/DependencyInjection/FlagceptionExtension.php index f81cd13..965d078 100644 --- a/src/DependencyInjection/FlagceptionExtension.php +++ b/src/DependencyInjection/FlagceptionExtension.php @@ -33,11 +33,6 @@ public function load(array $configs, ContainerBuilder $container): void $configuration = new Configuration($configurators); $config = $this->processConfiguration($configuration, $configs); - // Enable / disable annotation subscriber - if ($config['annotation']['enable'] === false) { - $container->removeDefinition('flagception.listener.annotation_subscriber'); - } - // Enable / disable routing metadata subscriber if ($config['routing_metadata']['enable'] === false) { $container->removeDefinition('flagception.listener.routing_metadata_subscriber'); diff --git a/src/Listener/AnnotationSubscriber.php b/src/Listener/AnnotationSubscriber.php deleted file mode 100644 index a1e4e98..0000000 --- a/src/Listener/AnnotationSubscriber.php +++ /dev/null @@ -1,104 +0,0 @@ - - * @package Flagception\Bundle\FlagceptionBundle\Listener - */ -class AnnotationSubscriber implements EventSubscriberInterface -{ - /** - * Annotation reader - * - * @var Reader - */ - private $reader; - - /** - * The feature manager - * - * @var FeatureManagerInterface - */ - private $manager; - - /** - * FeatureListener constructor. - * - * @param Reader $reader - * @param FeatureManagerInterface $manager - */ - public function __construct(Reader $reader, FeatureManagerInterface $manager) - { - $this->reader = $reader; - $this->manager = $manager; - } - - /** - * Filter on controller / method - * - * @param ControllerEvent $event - * - * @return void - * - * @throws NotFoundHttpException - * @throws ReflectionException - */ - public function onKernelController(ControllerEvent $event) - { - $eventController = $event->getController(); - - $controller = is_array($eventController) === false && method_exists($eventController, '__invoke') - ? [$eventController, '__invoke'] - : $eventController; - - /* - * $controller passed can be either a class or a Closure. - * This is not usual in Symfony2 but it may happen. - * If it is a class, it comes in array format - */ - if (!is_array($controller)) { - return; - } - - $object = new ReflectionClass($controller[0]); - foreach ($this->reader->getClassAnnotations($object) as $annotation) { - if ($annotation instanceof Feature) { - if (!$this->manager->isActive($annotation->name)) { - throw new NotFoundHttpException('Feature for this class is not active.'); - } - } - } - - $method = $object->getMethod($controller[1]); - foreach ($this->reader->getMethodAnnotations($method) as $annotation) { - if ($annotation instanceof Feature) { - if (!$this->manager->isActive($annotation->name)) { - throw new NotFoundHttpException('Feature for this method is not active.'); - } - } - } - } - - /** - * {@inheritdoc} - */ - public static function getSubscribedEvents(): array - { - return [ - KernelEvents::CONTROLLER => 'onKernelController', - ]; - } -} diff --git a/src/Listener/AttributeSubscriber.php b/src/Listener/AttributeSubscriber.php index b51f74e..c32afb8 100644 --- a/src/Listener/AttributeSubscriber.php +++ b/src/Listener/AttributeSubscriber.php @@ -13,7 +13,7 @@ use Symfony\Component\HttpKernel\KernelEvents; /** - * Class AnnotationSubscriber + * Class AttributeSubscriber * * @author Michel Chowanski * @package Flagception\Bundle\FlagceptionBundle\Listener diff --git a/src/Resources/config/services.yml b/src/Resources/config/services.yml index 8360b9e..cdece3c 100644 --- a/src/Resources/config/services.yml +++ b/src/Resources/config/services.yml @@ -63,16 +63,6 @@ services: class: Flagception\Decorator\ChainDecorator public: false - # Maybe removed by your configuration - flagception.listener.annotation_subscriber: - class: Flagception\Bundle\FlagceptionBundle\Listener\AnnotationSubscriber - arguments: - - '@annotations.reader' - - '@flagception.manager.feature_manager' - tags: - - { name: kernel.event_subscriber } - public: true - # Maybe removed by your configuration flagception.listener.routing_metadata_subscriber: class: Flagception\Bundle\FlagceptionBundle\Listener\RoutingMetadataSubscriber diff --git a/tests/DependencyInjection/FlagceptionExtensionTest.php b/tests/DependencyInjection/FlagceptionExtensionTest.php index 7ef46a9..3d78b7d 100644 --- a/tests/DependencyInjection/FlagceptionExtensionTest.php +++ b/tests/DependencyInjection/FlagceptionExtensionTest.php @@ -37,65 +37,6 @@ protected function setUp(): void $this->container = $container; } - /** - * Test that annotation subscriber is disabled - * - * @return void - */ - public function testAnnotationSubscriberDisabled() - { - $config = []; - - $extension = new FlagceptionExtension(); - $extension->load($config, $this->container); - - static::assertFalse($this->container->hasDefinition('flagception.listener.annotation_subscriber')); - } - - /** - * Test that annotation subscriber is enabled - * - * @return void - */ - public function testAnnotationSubscriberEnabled() - { - $config = [ - [ - 'annotation' => [ - 'enable' => true - ] - ] - ]; - - $extension = new FlagceptionExtension(); - $extension->load($config, $this->container); - - $definition = $this->container->getDefinition('flagception.listener.annotation_subscriber'); - static::assertTrue($definition->hasTag('kernel.event_subscriber')); - } - - /** - * Test that annotation subscriber is enabled by string - * - * @return void - */ - public function testAnnotationSubscriberEnabledByString() - { - $config = [ - [ - 'annotation' => [ - 'enable' => 'true' - ] - ] - ]; - - $extension = new FlagceptionExtension(); - $extension->load($config, $this->container); - - $definition = $this->container->getDefinition('flagception.listener.annotation_subscriber'); - static::assertTrue($definition->hasTag('kernel.event_subscriber')); - } - /** * Test that routing metadata subscriber is disabled * diff --git a/tests/Fixtures/Helper/AnnotationTestClass.php b/tests/Fixtures/Helper/AnnotationTestClass.php deleted file mode 100644 index 5bf435a..0000000 --- a/tests/Fixtures/Helper/AnnotationTestClass.php +++ /dev/null @@ -1,43 +0,0 @@ - - * @package Flagception\Tests\FlagceptionBundle\Fixtures\Helper - * - * @Feature("feature_abc") - */ -class AnnotationTestClass -{ - /** - * Normal test method - * - * @return void - */ - public function normalMethod() - { - } - - /** - * Valid test method - * - * @return void - */ - public function validMethod() - { - } - - /** - * Method with feature flag - * - * @Feature("feature_def") - */ - public function invalidMethod() - { - } -} diff --git a/tests/Fixtures/Helper/AttributeTestClass.php b/tests/Fixtures/Helper/AttributeTestClass.php index 75d3899..6b865b8 100644 --- a/tests/Fixtures/Helper/AttributeTestClass.php +++ b/tests/Fixtures/Helper/AttributeTestClass.php @@ -5,7 +5,7 @@ use Flagception\Bundle\FlagceptionBundle\Attribute\Feature; /** - * Class AnnotationTestClass + * Class AttributeTestClass * * @author Michel Chowanski * @package Flagception\Tests\FlagceptionBundle\Fixtures\Helper diff --git a/tests/Listener/AnnotationSubscriberTest.php b/tests/Listener/AnnotationSubscriberTest.php deleted file mode 100644 index 717eb09..0000000 --- a/tests/Listener/AnnotationSubscriberTest.php +++ /dev/null @@ -1,193 +0,0 @@ - - * @package Flagception\Tests\FlagceptionBundle\Listener - */ -class AnnotationSubscriberTest extends TestCase -{ - /** - * Test implement interface - * - * @return void - */ - public function testImplementInterface() - { - $manager = $this->createMock(FeatureManagerInterface::class); - $subscriber = new AnnotationSubscriber(new AnnotationReader(), $manager); - - static::assertInstanceOf(EventSubscriberInterface::class, $subscriber); - } - - /** - * Test subscribed events - * - * @return void - */ - public function testSubscribedEvents() - { - static::assertEquals( - [KernelEvents::CONTROLLER => 'onKernelController',], - AnnotationSubscriber::getSubscribedEvents() - ); - } - - /** - * Test controller is closure - * - * @return void - */ - public function testControllerIsClosure() - { - $manager = $this->createMock(FeatureManagerInterface::class); - $manager->expects(static::never())->method('isActive'); - - $event = $this->createControllerEvent( - function () { - } - ); - - $subscriber = new AnnotationSubscriber(new AnnotationReader(), $manager); - $subscriber->onKernelController($event); - } - - /** - * Test on class with active feature - * - * @return void - */ - public function testOnClassIsActive() - { - $calls = []; - $manager = $this->createMock(FeatureManagerInterface::class); - $manager->method('isActive')->willReturnCallback(function ($name) use (&$calls) { - switch ($name) { - case 'feature_abc': - $calls[] = $name; - return true; - default: - throw new \InvalidArgumentException('invalid feature call'); - } - }); - - $event = $this->createControllerEvent([ - new AnnotationTestClass(), - 'normalMethod' - ]); - - $subscriber = new AnnotationSubscriber(new AnnotationReader(), $manager); - $subscriber->onKernelController($event); - - self::assertEquals(['feature_abc'], $calls); - } - - /** - * Test on class with inactive feature - * - * @return void - */ - public function testOnClassIsInactive() - { - $this->expectException(NotFoundHttpException::class); - - $manager = $this->createMock(FeatureManagerInterface::class); - $manager->method('isActive')->with('feature_abc')->willReturn(false); - - $event = $this->createControllerEvent([ - new AnnotationTestClass(), - 'normalMethod' - ]); - - $subscriber = new AnnotationSubscriber(new AnnotationReader(), $manager); - $subscriber->onKernelController($event); - } - - /** - * Test on method with active feature - * - * @return void - */ - public function testOnMethodIsActive() - { - $calls = []; - - $manager = $this->createMock(FeatureManagerInterface::class); - $manager->method('isActive')->willReturnCallback(function ($name) use (&$calls) { - switch ($name) { - case 'feature_def': - case 'feature_abc': - $calls[] = $name; - return true; - default: - throw new \InvalidArgumentException('invalid feature call'); - } - }); - - $event = $this->createControllerEvent([ - new AnnotationTestClass(), - 'invalidMethod' - ]); - - $subscriber = new AnnotationSubscriber(new AnnotationReader(), $manager); - $subscriber->onKernelController($event); - - self::assertEquals(['feature_abc', 'feature_def'], $calls); - } - - /** - * Test on method with inactive feature - * - * @return void - */ - public function testOnMethodIsInactive() - { - $this->expectException(NotFoundHttpException::class); - - $manager = $this->createMock(FeatureManagerInterface::class); - $manager - ->method('isActive') - ->withConsecutive(['feature_abc'], ['feature_def']) - ->willReturnOnConsecutiveCalls(true, false); - - $event = $this->createControllerEvent([ - new AnnotationTestClass(), - 'invalidMethod' - ]); - - $subscriber = new AnnotationSubscriber(new AnnotationReader(), $manager); - $subscriber->onKernelController($event); - } - - /** - * Create ControllerEvent - * - * @param $controller - * - * @return ControllerEvent - */ - private function createControllerEvent($controller): ControllerEvent - { - return new ControllerEvent( - $this->createMock(HttpKernelInterface::class), - $controller, - new Request(), - 1 /* HttpKernelInterface::MAIN_REQUEST */ - ); - } -} diff --git a/tests/Listener/AttributeSubscriberTest.php b/tests/Listener/AttributeSubscriberTest.php index 4e10842..b56f00d 100644 --- a/tests/Listener/AttributeSubscriberTest.php +++ b/tests/Listener/AttributeSubscriberTest.php @@ -2,7 +2,6 @@ namespace Flagception\Tests\FlagceptionBundle\Listener; -use Doctrine\Common\Annotations\AnnotationReader; use Flagception\Bundle\FlagceptionBundle\Listener\AttributeSubscriber; use Flagception\Manager\FeatureManagerInterface; use Flagception\Tests\FlagceptionBundle\Fixtures\Helper\AttributeTestClass; @@ -15,7 +14,7 @@ use Symfony\Component\HttpKernel\KernelEvents; /** - * Class AnnotationSubscriberTest + * Class AttributeSubscriberTest * * @author Michel Chowanski * @package Flagception\Tests\FlagceptionBundle\Listener