From 06c1e11fafbcd3624ec727bee48409983cac0acf Mon Sep 17 00:00:00 2001 From: Nicolas Mugnier <6680190+NicolasMugnier@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:30:23 +0200 Subject: [PATCH 1/2] chore(startup-interceptor): Use cache warmer --- .../StartupInterceptorCacheWarmer.php} | 31 +++++++++---------- .../Symfony/Config/services.php | 8 ++--- 2 files changed, 17 insertions(+), 22 deletions(-) rename src/FrameworkBridge/Symfony/{Subscriber/ServiceProxySubscriber.php => CacheWarmer/StartupInterceptorCacheWarmer.php} (77%) diff --git a/src/FrameworkBridge/Symfony/Subscriber/ServiceProxySubscriber.php b/src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php similarity index 77% rename from src/FrameworkBridge/Symfony/Subscriber/ServiceProxySubscriber.php rename to src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php index 1129550..b9f872d 100644 --- a/src/FrameworkBridge/Symfony/Subscriber/ServiceProxySubscriber.php +++ b/src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\Subscriber; +namespace OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\CacheWarmer; use Doctrine\Common\Annotations\AnnotationReader; use Doctrine\Common\Annotations\Reader; @@ -10,10 +10,9 @@ use OpenClassrooms\ServiceProxy\Model\Request\Instance; use OpenClassrooms\ServiceProxy\Model\Request\Method; use ProxyManager\Proxy\ValueHolderInterface; -use Symfony\Component\EventDispatcher\EventSubscriberInterface; -use Symfony\Component\HttpKernel\Event\RequestEvent; +use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; -final class ServiceProxySubscriber implements EventSubscriberInterface +final class StartupInterceptorCacheWarmer implements CacheWarmerInterface { /** * @var array @@ -23,15 +22,16 @@ final class ServiceProxySubscriber implements EventSubscriberInterface private Reader $annotationReader; /** + * @param iterable $proxies * @param iterable $startUpInterceptors - * @param iterable $proxies + * @param Reader|null $annotationReader * * @throws \Doctrine\Common\Annotations\AnnotationException */ public function __construct( private readonly iterable $proxies, - iterable $startUpInterceptors, - Reader|null $annotationReader = null, + iterable $startUpInterceptors, + Reader|null $annotationReader = null, ) { if (!\is_array($startUpInterceptors)) { $this->startUpInterceptors = iterator_to_array($startUpInterceptors); @@ -40,20 +40,15 @@ public function __construct( $this->annotationReader = $annotationReader ?? new AnnotationReader(); } - /** - * @return array - */ - public static function getSubscribedEvents(): array + public function isOptional(): bool { - return [ - 'kernel.request' => 'startUp', - ]; + return false; } - public function startUp(RequestEvent $event): void + public function warmUp(string $cacheDir): array { if (\count($this->startUpInterceptors) === 0) { - return; + return []; } usort( @@ -70,12 +65,14 @@ public function startUp(RequestEvent $event): void } } } + + return []; } /** * @return iterable */ - public function getInstances(): iterable + private function getInstances(): iterable { foreach ($this->proxies as $proxy) { $object = $proxy; diff --git a/src/FrameworkBridge/Symfony/Config/services.php b/src/FrameworkBridge/Symfony/Config/services.php index 338854d..5d02ea6 100644 --- a/src/FrameworkBridge/Symfony/Config/services.php +++ b/src/FrameworkBridge/Symfony/Config/services.php @@ -3,7 +3,7 @@ declare(strict_types=1); use OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\Messenger\Transport\Serialization\MessageSerializer; -use OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\Subscriber\ServiceProxySubscriber; +use OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\CacheWarmer\StartupInterceptorCacheWarmer; use OpenClassrooms\ServiceProxy\Handler\Impl\Cache\SymfonyCacheHandler; use OpenClassrooms\ServiceProxy\Invoker\Impl\AggregateMethodInvoker; use OpenClassrooms\ServiceProxy\ProxyFactory; @@ -66,12 +66,10 @@ ->autoconfigure() ; - $services->set(ServiceProxySubscriber::class) - ->public() + $services->set(StartupInterceptorCacheWarmer::class) ->args([ tagged_iterator('openclassrooms.service_proxy'), tagged_iterator('openclassrooms.service_proxy.start_up_interceptor'), service('annotation_reader')->nullOnInvalid(), - ]) - ->tag('kernel.event_subscriber'); + ]); }; From d896c273619b3d94599f749cd9d497f8756b8a5a Mon Sep 17 00:00:00 2001 From: Nicolas Mugnier <6680190+NicolasMugnier@users.noreply.github.com> Date: Wed, 18 Sep 2024 19:18:07 +0200 Subject: [PATCH 2/2] feat(listen-attribute): Use CompilerPass --- .../StartupInterceptorCacheWarmer.php | 101 ------------------ .../Symfony/Config/services.php | 8 -- .../Compiler/ServiceProxyPass.php | 58 ++++++++++ 3 files changed, 58 insertions(+), 109 deletions(-) delete mode 100644 src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php diff --git a/src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php b/src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php deleted file mode 100644 index b9f872d..0000000 --- a/src/FrameworkBridge/Symfony/CacheWarmer/StartupInterceptorCacheWarmer.php +++ /dev/null @@ -1,101 +0,0 @@ - - */ - private array $startUpInterceptors; - - private Reader $annotationReader; - - /** - * @param iterable $proxies - * @param iterable $startUpInterceptors - * @param Reader|null $annotationReader - * - * @throws \Doctrine\Common\Annotations\AnnotationException - */ - public function __construct( - private readonly iterable $proxies, - iterable $startUpInterceptors, - Reader|null $annotationReader = null, - ) { - if (!\is_array($startUpInterceptors)) { - $this->startUpInterceptors = iterator_to_array($startUpInterceptors); - } - - $this->annotationReader = $annotationReader ?? new AnnotationReader(); - } - - public function isOptional(): bool - { - return false; - } - - public function warmUp(string $cacheDir): array - { - if (\count($this->startUpInterceptors) === 0) { - return []; - } - - usort( - $this->startUpInterceptors, - static fn ( - StartUpInterceptor $a, - StartUpInterceptor $b - ) => $a->getStartUpPriority() <=> $b->getStartUpPriority() - ); - foreach ($this->getInstances() as $instance) { - foreach ($this->startUpInterceptors as $interceptor) { - if ($interceptor->supportsStartUp($instance)) { - $interceptor->startUp($instance); - } - } - } - - return []; - } - - /** - * @return iterable - */ - private function getInstances(): iterable - { - foreach ($this->proxies as $proxy) { - $object = $proxy; - if ($proxy instanceof ValueHolderInterface) { - $object = $proxy->getWrappedValueHolderValue(); - if ($object === null) { - continue; - } - } - $instanceRef = new \ReflectionObject($object); - $methods = $instanceRef->getMethods(\ReflectionMethod::IS_PUBLIC); - foreach ($methods as $methodRef) { - $methodAnnotations = $this->annotationReader->getMethodAnnotations($methodRef); - $instance = Instance::create( - $proxy, - $instanceRef, - Method::create( - $methodRef, - $methodAnnotations, - ) - ); - yield $instance; - } - } - } -} diff --git a/src/FrameworkBridge/Symfony/Config/services.php b/src/FrameworkBridge/Symfony/Config/services.php index 5d02ea6..3954ad7 100644 --- a/src/FrameworkBridge/Symfony/Config/services.php +++ b/src/FrameworkBridge/Symfony/Config/services.php @@ -3,7 +3,6 @@ declare(strict_types=1); use OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\Messenger\Transport\Serialization\MessageSerializer; -use OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\CacheWarmer\StartupInterceptorCacheWarmer; use OpenClassrooms\ServiceProxy\Handler\Impl\Cache\SymfonyCacheHandler; use OpenClassrooms\ServiceProxy\Invoker\Impl\AggregateMethodInvoker; use OpenClassrooms\ServiceProxy\ProxyFactory; @@ -65,11 +64,4 @@ ->autowire() ->autoconfigure() ; - - $services->set(StartupInterceptorCacheWarmer::class) - ->args([ - tagged_iterator('openclassrooms.service_proxy'), - tagged_iterator('openclassrooms.service_proxy.start_up_interceptor'), - service('annotation_reader')->nullOnInvalid(), - ]); }; diff --git a/src/FrameworkBridge/Symfony/DependencyInjection/Compiler/ServiceProxyPass.php b/src/FrameworkBridge/Symfony/DependencyInjection/Compiler/ServiceProxyPass.php index 4c066c3..2c18302 100644 --- a/src/FrameworkBridge/Symfony/DependencyInjection/Compiler/ServiceProxyPass.php +++ b/src/FrameworkBridge/Symfony/DependencyInjection/Compiler/ServiceProxyPass.php @@ -4,6 +4,10 @@ namespace OpenClassrooms\ServiceProxy\FrameworkBridge\Symfony\DependencyInjection\Compiler; +use Doctrine\Common\Annotations\AnnotationException; +use Doctrine\Common\Annotations\AnnotationReader; +use OpenClassrooms\ServiceProxy\Attribute\Event\Listen; +use OpenClassrooms\ServiceProxy\Model\Request\Method; use OpenClassrooms\ServiceProxy\ProxyFactory; use Symfony\Component\DependencyInjection\Compiler\Compiler; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; @@ -23,6 +27,7 @@ public function process(ContainerBuilder $container): void $this->compiler = $container->getCompiler(); $this->buildServiceProxies(); + $this->addStartupListeners(); } private function buildServiceProxies(): void @@ -49,4 +54,57 @@ private function buildServiceProxyFactoryDefinition(string $taggedServiceName): $factoryDefinition->setLazy($definition->isLazy()); $factoryDefinition->setTags($definition->getTags()); } + + private function addStartupListeners(): void + { + if (!$this->container->findDefinition('event_dispatcher')) { + return; + } + + $eventDispatcherDefinition = $this->container->findDefinition('event_dispatcher'); + $proxies = $this->container->findTaggedServiceIds('openclassrooms.service_proxy'); + + foreach (\array_keys($proxies) as $proxy) { + $definition = $this->container->findDefinition($proxy); + $class = $definition->getClass(); + $instanceRef = new \ReflectionClass($class); + $methods = $instanceRef->getMethods(\ReflectionMethod::IS_PUBLIC); + foreach ($methods as $methodRef) { + + try { + $methodAnnotations = (new AnnotationReader())->getMethodAnnotations($methodRef); + } catch (AnnotationException) { + continue; + } + + $method = Method::create( + $methodRef, + $methodAnnotations, + ); + + if ($method->hasAttribute(Listen::class)) { + $attributes = $method->getAttributesInstances(Listen::class); + + foreach ($attributes as $attribute) { + /** + * @var Listen $attribute + */ + $name = $attribute->name; + $transport = $attribute->transport; + + if ($transport !== null) { + $name .= '.' . $transport->value; + } + + $eventDispatcherDefinition->addMethodCall('addListener', [ + $name, + [new Reference($proxy), $method->getName()], + $attribute->priority + ]); + } + + } + } + } + } }