diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index ee63320..41c94bb 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -79,6 +79,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->defaultTrue() ->end() ->arrayNode('http_client') + ->addDefaultsIfNotSet() ->children() ->booleanNode('enabled') ->info('Whether or not to enable the trace id aware http client') diff --git a/src/DependencyInjection/SymfonyTraceExtension.php b/src/DependencyInjection/SymfonyTraceExtension.php index a242d6c..57ac188 100644 --- a/src/DependencyInjection/SymfonyTraceExtension.php +++ b/src/DependencyInjection/SymfonyTraceExtension.php @@ -29,6 +29,26 @@ use Twig\Extension\AbstractExtension; /** + * @phpstan-type Options array{ + * traceMode: 'tracecontext'|'traceid', + * traceid: array{ + * request_header: string, + * response_header: string, + * generator_service: ?string, + * }, + * trust_request_header: bool, + * send_response_header: bool, + * storage_service: ?string, + * enable_monolog: bool, + * enable_console: bool, + * enable_messenger: bool, + * enable_twig: bool, + * http_client: array{ + * enabled: bool, + * tag_default_client: bool, + * header: string + * } + * } * @codeCoverageIgnore - This is a configuration class, tested by the functional test * @internal */ @@ -37,62 +57,75 @@ final class SymfonyTraceExtension extends ConfigurableExtension public const PARAMETER_KEY = 'digital_revolution.symfony_trace'; /** - * @param array{ - * traceMode: 'tracecontext'|'traceid', - * traceid: array{ - * request_header: string, - * response_header: string, - * generator_service: ?string, - * }, - * trust_request_header: bool, - * send_response_header: bool, - * storage_service: ?string, - * enable_monolog: bool, - * enable_console: bool, - * enable_messenger: bool, - * enable_twig: bool, - * http_client: array{ - * enabled: bool, - * tag_default_client: bool, - * header: string - * } - * } $mergedConfig + * @phpstan-param Options $mergedConfig */ protected function loadInternal(array $mergedConfig, ContainerBuilder $container): void { $container->register(TraceStorage::class)->setPublic(false); - $storeId = $mergedConfig['storage_service'] ?? TraceStorage::class; + $storeId = $mergedConfig['storage_service'] ?? TraceStorage::class; + $generatorId = $this->configureGeneratorId($mergedConfig, $container); + $serviceId = $this->configureTraceServiceId($mergedConfig, $container, $generatorId); + + $container->setAlias(TraceServiceInterface::class, $serviceId)->setPublic(false); + $container->setAlias(TraceStorageInterface::class, $storeId)->setPublic(true); + $container->setAlias(TraceIdGeneratorInterface::class, $generatorId)->setPublic(true); + + $container->register(TraceSubscriber::class) + ->setArguments( + [ + $mergedConfig['trust_request_header'], + $mergedConfig['send_response_header'], + new Reference($serviceId), + new Reference($storeId) + ] + ) + ->setPublic(false) + ->addTag('kernel.event_subscriber'); + + $this->configureMonolog($mergedConfig, $container, $storeId); + $this->configureConsole($mergedConfig, $container, $storeId, $serviceId); + $this->configureMessenger($mergedConfig, $container, $storeId, $generatorId); + $this->configureTwig($mergedConfig, $container, $storeId); + $this->configureHttpClient($mergedConfig, $container); + } + + /** + * @phpstan-param Options $mergedConfig + */ + private function configureGeneratorId(array $mergedConfig, ContainerBuilder $container): string + { // configure generator service if ($mergedConfig['traceMode'] === Configuration::TRACEMODE_TRACECONTEXT) { $generatorId = TraceContextIdGenerator::class; + $container->register(TraceContextIdGenerator::class)->setPublic(false); } elseif (isset($mergedConfig['traceid']['generator_service'])) { $generatorId = $mergedConfig['traceid']['generator_service']; } elseif (RamseyUuid4Generator::isSupported()) { $generatorId = RamseyUuid4Generator::class; + $container->register(RamseyUuid4Generator::class)->setPublic(false); } elseif (SymfonyUuid4Generator::isSupported()) { $generatorId = SymfonyUuid4Generator::class; + $container->register(SymfonyUuid4Generator::class)->setPublic(false); } else { throw new RuntimeException('No generator service found. Please install symfony/uid or ramsey/uuid'); } - $container->register(TraceContextIdGenerator::class)->setPublic(false); - if ($generatorId === RamseyUuid4Generator::class) { - $container->register(RamseyUuid4Generator::class)->setPublic(false); - } elseif ($generatorId === SymfonyUuid4Generator::class) { - $container->register(SymfonyUuid4Generator::class)->setPublic(false); - } + return $generatorId; + } - if ($mergedConfig['traceMode'] === Configuration::TRACEMODE_TRACEID) { - $serviceId = TraceIdService::class; - } else { - $serviceId = TraceContextService::class; - } + /** + * @phpstan-param Options $mergedConfig + */ + private function configureTraceServiceId(array $mergedConfig, ContainerBuilder $container, string $generatorId): string + { + if ($mergedConfig['traceMode'] === Configuration::TRACEMODE_TRACECONTEXT) { + $container->register(TraceContextService::class) + ->setArguments([new Reference(TraceContextIdGenerator::class)]) + ->setPublic(false); - $container->setAlias(TraceServiceInterface::class, $serviceId)->setPublic(false); - $container->register(TraceContextService::class) - ->setArguments([new Reference(TraceContextIdGenerator::class)]) - ->setPublic(false); + return TraceContextService::class; + } $container->register(TraceIdService::class) ->setArguments( @@ -105,68 +138,89 @@ protected function loadInternal(array $mergedConfig, ContainerBuilder $container ) ->setPublic(false); - $container->setAlias(TraceStorageInterface::class, $storeId)->setPublic(true); - $container->setAlias(TraceIdGeneratorInterface::class, $generatorId)->setPublic(true); + return TraceIdService::class; + } - $container->register(TraceSubscriber::class) - ->setArguments( - [ - $mergedConfig['trust_request_header'], - $mergedConfig['send_response_header'], - new Reference($serviceId), - new Reference($storeId) - ] - ) + /** + * @phpstan-param Options $mergedConfig + */ + private function configureMonolog(array $mergedConfig, ContainerBuilder $container, string $storeId): void + { + if ($mergedConfig['enable_monolog'] === false) { + return; + } + $container->register(TraceProcessor::class) + ->addArgument(new Reference($storeId)) ->setPublic(false) - ->addTag('kernel.event_subscriber'); + ->addTag('monolog.processor'); + } - if ($mergedConfig['enable_monolog']) { - $container->register(TraceProcessor::class) - ->addArgument(new Reference($storeId)) - ->setPublic(false) - ->addTag('monolog.processor'); + /** + * @phpstan-param Options $mergedConfig + */ + private function configureConsole(array $mergedConfig, ContainerBuilder $container, string $storeId, string $serviceId): void + { + if (class_exists(Application::class) === false || $mergedConfig['enable_console'] === false) { + return; } + $container->register(CommandSubscriber::class) + ->setArguments([new Reference($storeId), new Reference($serviceId)]) + ->setPublic(false) + ->addTag('kernel.event_subscriber'); + } - if (class_exists(Application::class) && $mergedConfig['enable_console']) { - $container->register(CommandSubscriber::class) - ->setArguments([new Reference($storeId), new Reference($serviceId)]) - ->setPublic(false) - ->addTag('kernel.event_subscriber'); + /** + * @phpstan-param Options $mergedConfig + */ + private function configureMessenger(array $mergedConfig, ContainerBuilder $container, string $storeId, string $generatorId): void + { + if ($mergedConfig['enable_messenger'] === false) { + return; } - - if ($mergedConfig['enable_messenger']) { - if (interface_exists(MessageBusInterface::class) === false) { - throw new LogicException( - 'Messenger support cannot be enabled as the Messenger component is not installed. ' . - 'Try running "composer require symfony/messenger".' - ); - } - - $container->register(MessageBusSubscriber::class) - ->setArguments([new Reference($storeId), new Reference($generatorId)]) - ->setPublic(false) - ->addTag('kernel.event_subscriber'); + if (interface_exists(MessageBusInterface::class) === false) { + throw new LogicException( + 'Messenger support cannot be enabled as the Messenger component is not installed. ' . + 'Try running "composer require symfony/messenger".' + ); } + $container->register(MessageBusSubscriber::class) + ->setArguments([new Reference($storeId), new Reference($generatorId)]) + ->setPublic(false) + ->addTag('kernel.event_subscriber'); + } - if (class_exists(AbstractExtension::class) && $mergedConfig['enable_twig']) { - $container->register(TraceExtension::class) - ->addArgument(new Reference($storeId)) - ->setPublic(false) - ->addTag('twig.extension'); + /** + * @phpstan-param Options $mergedConfig + */ + private function configureTwig(array $mergedConfig, ContainerBuilder $container, string $storeId): void + { + if (class_exists(AbstractExtension::class) === false || $mergedConfig['enable_twig'] === false) { + return; } - $container->setParameter(self::PARAMETER_KEY . '.http_client.enabled', false); - if (isset($mergedConfig['http_client']) && $mergedConfig['http_client']['enabled']) { - if (interface_exists(HttpClientInterface::class) === false) { - throw new LogicException( - 'HttpClient support cannot be enabled as the HttpClient component is not installed. ' . - 'Try running "composer require symfony/http-client".' - ); - } - - $container->setParameter(self::PARAMETER_KEY . '.http_client.enabled', $mergedConfig['http_client']['enabled']); - $container->setParameter(self::PARAMETER_KEY . '.http_client.tag_default_client', $mergedConfig['http_client']['tag_default_client']); - $container->setParameter(self::PARAMETER_KEY . '.http_client.header', $mergedConfig['http_client']['header']); + $container->register(TraceExtension::class) + ->addArgument(new Reference($storeId)) + ->setPublic(false) + ->addTag('twig.extension'); + } + + /** + * @phpstan-param Options $mergedConfig + */ + private function configureHttpClient(array $mergedConfig, ContainerBuilder $container): void + { + $container->setParameter(self::PARAMETER_KEY . '.http_client.enabled', $mergedConfig['http_client']['enabled']); + if ($mergedConfig['http_client']['enabled'] === false) { + return; } + if (interface_exists(HttpClientInterface::class) === false) { + throw new LogicException( + 'HttpClient support cannot be enabled as the HttpClient component is not installed. ' . + 'Try running "composer require symfony/http-client".' + ); + } + + $container->setParameter(self::PARAMETER_KEY . '.http_client.tag_default_client', $mergedConfig['http_client']['tag_default_client']); + $container->setParameter(self::PARAMETER_KEY . '.http_client.header', $mergedConfig['http_client']['header']); } }