From d425367b86a96feeff49c21fe7278c32422bb219 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Sat, 21 Oct 2023 21:59:25 +0200 Subject: [PATCH] Drop Support for Symfony 4 --- .github/workflows/ci.yaml | 1 - .../Compiler/LoggerChannelPass.php | 53 ++++++----------- DependencyInjection/Configuration.php | 27 +-------- DependencyInjection/MonologExtension.php | 50 ++++++---------- MonologBundle.php | 7 ++- .../Compiler/LoggerChannelPassTest.php | 16 ------ .../FixtureMonologExtensionTest.php | 44 +------------- .../MonologExtensionTest.php | 57 +++---------------- composer.json | 18 +++--- 9 files changed, 60 insertions(+), 213 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5d3ac1e4..ca077dcf 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -14,7 +14,6 @@ jobs: php: [ '7.2', '7.3', '7.4', '8.0', '8.1' ] monolog: [ '1.*', '2.*' ] include: - - php: '7.1' - php: '7.4' deps: lowest deprecations: max[self]=0 diff --git a/DependencyInjection/Compiler/LoggerChannelPass.php b/DependencyInjection/Compiler/LoggerChannelPass.php index d10d41a2..88793665 100644 --- a/DependencyInjection/Compiler/LoggerChannelPass.php +++ b/DependencyInjection/Compiler/LoggerChannelPass.php @@ -66,19 +66,17 @@ public function process(ContainerBuilder $container) } $definition->setMethodCalls($calls); - if (\method_exists($definition, 'getBindings')) { - $binding = new BoundArgument(new Reference($loggerId)); - - // Mark the binding as used already, to avoid reporting it as unused if the service does not use a - // logger injected through the LoggerInterface alias. - $values = $binding->getValues(); - $values[2] = true; - $binding->setValues($values); - - $bindings = $definition->getBindings(); - $bindings['Psr\Log\LoggerInterface'] = $binding; - $definition->setBindings($bindings); - } + $binding = new BoundArgument(new Reference($loggerId)); + + // Mark the binding as used already, to avoid reporting it as unused if the service does not use a + // logger injected through the LoggerInterface alias. + $values = $binding->getValues(); + $values[2] = true; + $binding->setValues($values); + + $bindings = $definition->getBindings(); + $bindings['Psr\Log\LoggerInterface'] = $binding; + $definition->setBindings($bindings); } } @@ -117,11 +115,9 @@ public function getChannels() } /** - * @param array $configuration - * * @return array */ - protected function processChannels($configuration) + protected function processChannels(?array $configuration) { if (null === $configuration) { return $this->channels; @@ -137,11 +133,9 @@ protected function processChannels($configuration) /** * Create new logger from the monolog.logger_prototype * - * @param string $channel - * @param string $loggerId - * @param ContainerBuilder $container + * @return void */ - protected function createLogger($channel, $loggerId, ContainerBuilder $container) + protected function createLogger(string $channel, string $loggerId, ContainerBuilder $container) { if (!in_array($channel, $this->channels)) { $logger = new ChildDefinition('monolog.logger_prototype'); @@ -150,29 +144,16 @@ protected function createLogger($channel, $loggerId, ContainerBuilder $container $this->channels[] = $channel; } - // Allows only for Symfony 4.2+ - if (\method_exists($container, 'registerAliasForArgument')) { - $parameterName = $channel . 'Logger'; + $parameterName = $channel . 'Logger'; - $container->registerAliasForArgument($loggerId, LoggerInterface::class, $parameterName); - } + $container->registerAliasForArgument($loggerId, LoggerInterface::class, $parameterName); } /** * Creates a copy of a reference and alters the service ID. - * - * @param Reference $reference - * @param string $serviceId - * - * @return Reference */ - private function changeReference(Reference $reference, $serviceId) + private function changeReference(Reference $reference, string $serviceId): Reference { - if (method_exists($reference, 'isStrict')) { - // Stay compatible with Symfony 2 - return new Reference($serviceId, $reference->getInvalidBehavior(), $reference->isStrict(false)); - } - return new Reference($serviceId, $reference->getInvalidBehavior()); } } diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php index c91d5b56..c89ef434 100644 --- a/DependencyInjection/Configuration.php +++ b/DependencyInjection/Configuration.php @@ -379,7 +379,7 @@ class Configuration implements ConfigurationInterface public function getConfigTreeBuilder(): TreeBuilder { $treeBuilder = new TreeBuilder('monolog'); - $rootNode = method_exists(TreeBuilder::class, 'getRootNode') ? $treeBuilder->getRootNode() : $treeBuilder->root('monolog'); + $rootNode = $treeBuilder->getRootNode(); $handlers = $rootNode ->fixXmlConfig('channel') @@ -602,7 +602,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() // console ->variableNode('console_formater_options') - ->setDeprecated(...$this->getDeprecationMsg('"%path%.%node%" is deprecated, use "%path%.console_formatter_options" instead.', 3.7)) + ->setDeprecated('symfony/monolog-bundle', 3.7, '"%path%.%node%" is deprecated, use "%path%.console_formatter_options" instead.') ->validate() ->ifTrue(function ($v) { return !is_array($v); @@ -1135,27 +1135,4 @@ private function addChannelsSection(ArrayNodeDefinition $handerNode) ->end() ; } - - /** - * Returns the correct deprecation param's as an array for setDeprecated. - * - * Symfony/Config v5.1 introduces a deprecation notice when calling - * setDeprecation() with less than 3 args and the getDeprecation method was - * introduced at the same time. By checking if getDeprecation() exists, - * we can determine the correct param count to use when calling setDeprecated. - * - * @return array{0:string}|array{0:string, 1: numeric-string, string} - */ - private function getDeprecationMsg(string $message, string $version): array - { - if (method_exists(BaseNode::class, 'getDeprecation')) { - return [ - 'symfony/monolog-bundle', - $version, - $message, - ]; - } - - return [$message]; - } } diff --git a/DependencyInjection/MonologExtension.php b/DependencyInjection/MonologExtension.php index ce114a23..5d14c430 100644 --- a/DependencyInjection/MonologExtension.php +++ b/DependencyInjection/MonologExtension.php @@ -32,7 +32,6 @@ use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\HttpKernel\Kernel; use Symfony\Component\HttpKernel\Log\DebugLoggerConfigurator; use Symfony\Contracts\HttpClient\HttpClientInterface; @@ -56,10 +55,6 @@ class MonologExtension extends Extension */ public function load(array $configs, ContainerBuilder $container) { - if (class_exists(FullStack::class) && Kernel::MAJOR_VERSION < 5 && Logger::API >= 2) { - throw new \RuntimeException('Symfony 5 is required for Monolog 2 support. Please downgrade Monolog to version 1.'); - } - $configuration = $this->getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); @@ -107,29 +102,27 @@ public function load(array $configs, ContainerBuilder $container) $container->setParameter('monolog.additional_channels', isset($config['channels']) ? $config['channels'] : []); - if (method_exists($container, 'registerForAutoconfiguration')) { - if (interface_exists(ProcessorInterface::class)) { - $container->registerForAutoconfiguration(ProcessorInterface::class) - ->addTag('monolog.processor'); - } else { - $container->registerForAutoconfiguration(WebProcessor::class) - ->addTag('monolog.processor'); - } - if (interface_exists(ResettableInterface::class)) { - $container->registerForAutoconfiguration(ResettableInterface::class) - ->addTag('kernel.reset', ['method' => 'reset']); - } - $container->registerForAutoconfiguration(TokenProcessor::class) + if (interface_exists(ProcessorInterface::class)) { + $container->registerForAutoconfiguration(ProcessorInterface::class) ->addTag('monolog.processor'); - if (interface_exists(HttpClientInterface::class)) { - $handlerAutoconfiguration = $container->registerForAutoconfiguration(HandlerInterface::class); - $handlerAutoconfiguration->setBindings($handlerAutoconfiguration->getBindings() + [ - HttpClientInterface::class => new BoundArgument(new Reference('monolog.http_client'), false), - ]); - } + } else { + $container->registerForAutoconfiguration(WebProcessor::class) + ->addTag('monolog.processor'); + } + if (interface_exists(ResettableInterface::class)) { + $container->registerForAutoconfiguration(ResettableInterface::class) + ->addTag('kernel.reset', ['method' => 'reset']); + } + $container->registerForAutoconfiguration(TokenProcessor::class) + ->addTag('monolog.processor'); + if (interface_exists(HttpClientInterface::class)) { + $handlerAutoconfiguration = $container->registerForAutoconfiguration(HandlerInterface::class); + $handlerAutoconfiguration->setBindings($handlerAutoconfiguration->getBindings() + [ + HttpClientInterface::class => new BoundArgument(new Reference('monolog.http_client'), false), + ]); } - if (80000 <= \PHP_VERSION_ID && method_exists($container, 'registerAttributeForAutoconfiguration')) { + if (80000 <= \PHP_VERSION_ID) { $container->registerAttributeForAutoconfiguration(AsMonologProcessor::class, static function (ChildDefinition $definition, AsMonologProcessor $attribute, \Reflector $reflector): void { $tagAttributes = get_object_vars($attribute); if ($reflector instanceof \ReflectionMethod) { @@ -431,9 +424,6 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler $container->setDefinition($handlerId.'.not_found_strategy', $activationDef); $activation = new Reference($handlerId.'.not_found_strategy'); } elseif (!empty($handler['excluded_http_codes'])) { - if (!class_exists('Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy')) { - throw new \LogicException('"excluded_http_codes" cannot be used as your version of Monolog bridge does not support it.'); - } $activationDef = new Definition('Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy', [ new Reference('request_stack'), $handler['excluded_http_codes'], @@ -888,10 +878,6 @@ private function buildHandler(ContainerBuilder $container, $name, array $handler ]); break; case 'server_log': - if (!class_exists('Symfony\Bridge\Monolog\Handler\ServerLogHandler')) { - throw new \RuntimeException('The ServerLogHandler is not available. Please update "symfony/monolog-bridge" to 3.3.'); - } - $definition->setArguments([ $handler['host'], $handler['level'], diff --git a/MonologBundle.php b/MonologBundle.php index 12e0cb67..baf39e6f 100644 --- a/MonologBundle.php +++ b/MonologBundle.php @@ -27,14 +27,14 @@ */ class MonologBundle extends Bundle { + /** + * @return void + */ public function build(ContainerBuilder $container) { parent::build($container); $container->addCompilerPass($channelPass = new LoggerChannelPass()); - if (!class_exists('Symfony\Bridge\Monolog\Processor\DebugProcessor') || !class_exists('Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass')) { - $container->addCompilerPass(new DebugHandlerPass($channelPass)); - } $container->addCompilerPass(new FixEmptyLoggerPass($channelPass)); $container->addCompilerPass(new AddProcessorsPass()); $container->addCompilerPass(new AddSwiftMailerTransportPass()); @@ -42,6 +42,7 @@ public function build(ContainerBuilder $container) /** * @internal + * @return void */ public static function includeStacktraces(HandlerInterface $handler) { diff --git a/Tests/DependencyInjection/Compiler/LoggerChannelPassTest.php b/Tests/DependencyInjection/Compiler/LoggerChannelPassTest.php index 7cc7323c..7ed07452 100644 --- a/Tests/DependencyInjection/Compiler/LoggerChannelPassTest.php +++ b/Tests/DependencyInjection/Compiler/LoggerChannelPassTest.php @@ -56,10 +56,6 @@ public function testProcess() public function testTypeHintedAliasesExistForEachChannel() { - if (!\method_exists(ContainerBuilder::class, 'registerAliasForArgument')) { - $this->markTestSkipped('Need DependencyInjection 4.2+ to register type-hinted aliases for channels.'); - } - $container = $this->getContainer(); $expectedChannels = ['test', 'foo', 'bar', 'additional']; @@ -81,10 +77,6 @@ public function testProcessSetters() public function testAutowiredLoggerArgumentsAreReplacedWithChannelLogger() { - if (!\method_exists('Symfony\Component\DependencyInjection\Definition', 'getBindings')) { - $this->markTestSkipped('Need DependencyInjection 3.4+ to autowire channel logger.'); - } - $container = $this->getFunctionalContainer(); $dummyService = $container->register('dummy_service', 'Symfony\Bundle\MonologBundle\Tests\DependencyInjection\Compiler\DummyService') @@ -99,10 +91,6 @@ public function testAutowiredLoggerArgumentsAreReplacedWithChannelLogger() public function testAutowiredLoggerArgumentsAreReplacedWithChannelLoggerWhenAutoconfigured() { - if (!\method_exists('Symfony\Component\DependencyInjection\Definition', 'getBindings')) { - $this->markTestSkipped('Need DependencyInjection 3.4+ to autowire channel logger.'); - } - $container = $this->getFunctionalContainer(); $container->registerForAutoconfiguration('Symfony\Bundle\MonologBundle\Tests\DependencyInjection\Compiler\DummyService') @@ -121,10 +109,6 @@ public function testAutowiredLoggerArgumentsAreReplacedWithChannelLoggerWhenAuto public function testAutowiredLoggerArgumentsAreNotReplacedWithChannelLoggerIfLoggerArgumentIsConfiguredExplicitly() { - if (!\method_exists('Symfony\Component\DependencyInjection\Definition', 'getBindings')) { - $this->markTestSkipped('Need DependencyInjection 3.4+ to autowire channel logger.'); - } - $container = $this->getFunctionalContainer(); $dummyService = $container->register('dummy_service', 'Symfony\Bundle\MonologBundle\Tests\DependencyInjection\Compiler\DummyService') diff --git a/Tests/DependencyInjection/FixtureMonologExtensionTest.php b/Tests/DependencyInjection/FixtureMonologExtensionTest.php index 6b617b96..72bc46c5 100644 --- a/Tests/DependencyInjection/FixtureMonologExtensionTest.php +++ b/Tests/DependencyInjection/FixtureMonologExtensionTest.php @@ -22,27 +22,9 @@ abstract class FixtureMonologExtensionTest extends DependencyInjectionTest { - /** @group legacy */ - public function testLegacyLoadWithSeveralHandlers() - { - if (class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge < 5.2 is needed.'); - } - - $this->doTestLoadWithSeveralHandlers('ERROR'); - } - public function testLoadWithSeveralHandlers() { - if (!class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge >= 5.2 is needed.'); - } - - $this->doTestLoadWithSeveralHandlers(new Definition(ErrorLevelActivationStrategy::class, ['ERROR'])); - } - - private function doTestLoadWithSeveralHandlers($activation) - { + $activation = new Definition(ErrorLevelActivationStrategy::class, ['ERROR']); $container = $this->getContainer('multiple_handlers'); $this->assertTrue($container->hasDefinition('monolog.logger')); @@ -70,27 +52,9 @@ private function doTestLoadWithSeveralHandlers($activation) $this->assertDICConstructorArguments($handler, [new Reference('monolog.handler.nested2'), ['WARNING', 'ERROR'], 'EMERGENCY', true]); } - /** @group legacy */ - public function testLegacyLoadWithOverwriting() - { - if (class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge < 5.2 is needed.'); - } - - $this->doTestLoadWithOverwriting('ERROR'); - } - public function testLoadWithOverwriting() { - if (!class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge >= 5.2 is needed.'); - } - - $this->doTestLoadWithOverwriting(new Definition(ErrorLevelActivationStrategy::class, ['ERROR'])); - } - - private function doTestLoadWithOverwriting($activation) - { + $activation = new Definition(ErrorLevelActivationStrategy::class, ['ERROR']); $container = $this->getContainer('overwriting'); $this->assertTrue($container->hasDefinition('monolog.logger')); @@ -202,10 +166,6 @@ public function testSingleEmailRecipient() public function testServerLog() { - if (!class_exists('Symfony\Bridge\Monolog\Handler\ServerLogHandler')) { - $this->markTestSkipped('The ServerLogHandler is not available.'); - } - $container = $this->getContainer('server_log'); $this->assertEquals([ diff --git a/Tests/DependencyInjection/MonologExtensionTest.php b/Tests/DependencyInjection/MonologExtensionTest.php index e63ce79e..29ef6a15 100644 --- a/Tests/DependencyInjection/MonologExtensionTest.php +++ b/Tests/DependencyInjection/MonologExtensionTest.php @@ -543,28 +543,10 @@ public function testLogglyHandler() $this->assertDICDefinitionMethodCallAt(1, $handler, 'setTag', ['foo,bar']); } - /** @group legacy */ - public function testLegacyFingersCrossedHandlerWhenExcluded404sAreSpecified() - { - if (class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge < 5.2 is needed.'); - } - - $this->doTestFingersCrossedHandlerWhenExcluded404sAreSpecified('WARNING'); - } - /** @group legacy */ public function testFingersCrossedHandlerWhenExcluded404sAreSpecified() { - if (!class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge >= 5.2 is needed.'); - } - - $this->doTestFingersCrossedHandlerWhenExcluded404sAreSpecified(new Definition(ErrorLevelActivationStrategy::class, ['WARNING'])); - } - - private function doTestFingersCrossedHandlerWhenExcluded404sAreSpecified($activation) - { + $activation = new Definition(ErrorLevelActivationStrategy::class, ['WARNING']); $container = $this->getContainer([['handlers' => [ 'main' => ['type' => 'fingers_crossed', 'handler' => 'nested', 'excluded_404s' => ['^/foo', '^/bar']], 'nested' => ['type' => 'stream', 'path' => '/tmp/symfony.log'] @@ -588,30 +570,9 @@ private function doTestFingersCrossedHandlerWhenExcluded404sAreSpecified($activa $this->assertDICConstructorArguments($handler, [new Reference('monolog.handler.nested'), new Reference('monolog.handler.main.not_found_strategy'), 0, true, true, null]); } - /** @group legacy */ - public function testLegacyFingersCrossedHandlerWhenExcludedHttpCodesAreSpecified() - { - if (class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge < 5.2 is needed.'); - } - - $this->doTestFingersCrossedHandlerWhenExcludedHttpCodesAreSpecified('WARNING'); - } - public function testFingersCrossedHandlerWhenExcludedHttpCodesAreSpecified() { - if (!class_exists(SwitchUserTokenProcessor::class)) { - $this->markTestSkipped('Symfony MonologBridge >= 5.2 is needed.'); - } - - $this->doTestFingersCrossedHandlerWhenExcludedHttpCodesAreSpecified(new Definition(ErrorLevelActivationStrategy::class, ['WARNING'])); - } - - private function doTestFingersCrossedHandlerWhenExcludedHttpCodesAreSpecified($activation) - { - if (!class_exists('Symfony\Bridge\Monolog\Handler\FingersCrossed\HttpCodeActivationStrategy')) { - $this->markTestSkipped('Symfony Monolog 4.1+ is needed.'); - } + $activation = new Definition(ErrorLevelActivationStrategy::class, ['WARNING']); $container = $this->getContainer([['handlers' => [ 'main' => [ @@ -649,10 +610,9 @@ private function doTestFingersCrossedHandlerWhenExcludedHttpCodesAreSpecified($a } /** - * @param array $handlerOptions * @dataProvider v2RemovedDataProvider */ - public function testV2Removed($handlerOptions) + public function testV2Removed(array $handlerOptions) { if (Logger::API === 1) { $this->markTestSkipped('Not valid for V1'); @@ -669,7 +629,7 @@ public function testV2Removed($handlerOptions) $loader->load([['handlers' => ['main' => $handlerOptions]]], $container); } - public function v2RemovedDataProvider() + public function v2RemovedDataProvider(): array { return [ [['type' => 'hipchat', 'token' => 'abc123', 'room' => 'foo']], @@ -679,10 +639,9 @@ public function v2RemovedDataProvider() } /** - * @param string $handlerType * @dataProvider v1AddedDataProvider */ - public function testV2AddedOnV1($handlerType) + public function testV2AddedOnV1(string $handlerType) { if (Logger::API !== 1) { $this->markTestSkipped('Only valid on Monolog V1'); @@ -701,7 +660,7 @@ public function testV2AddedOnV1($handlerType) $loader->load([['handlers' => ['main' => ['type' => $handlerType]]]], $container); } - public function v1AddedDataProvider() + public function v1AddedDataProvider(): array { return [ ['fallbackgroup'], @@ -726,7 +685,7 @@ public function testLogLevelfromParameter(array $parameters, array $config, $exp $this->assertDICConstructorArguments($definition, $expectedArgs); } - public function provideLoglevelParameterConfig() + public function provideLoglevelParameterConfig(): array { return [ 'browser console with parameter level' => [ @@ -878,7 +837,7 @@ public function testAsMonologProcessorAutoconfigurationWithPriority(): void ], $container->getDefinition(FooProcessorWithPriority::class)->getTag('monolog.processor')); } - protected function getContainer(array $config = [], array $thirdPartyDefinitions = []) + protected function getContainer(array $config = [], array $thirdPartyDefinitions = []): ContainerBuilder { $container = new ContainerBuilder(new EnvPlaceholderParameterBag()); foreach ($thirdPartyDefinitions as $id => $definition) { diff --git a/composer.json b/composer.json index 623982cb..369d086e 100644 --- a/composer.json +++ b/composer.json @@ -16,17 +16,17 @@ } ], "require": { - "php": ">=7.1.3", - "symfony/monolog-bridge": "~4.4 || ^5.0 || ^6.0 || ^7.0", - "symfony/dependency-injection": "^4.4 || ^5.0 || ^6.0 || ^7.0", - "symfony/config": "~4.4 || ^5.0 || ^6.0 || ^7.0", - "symfony/http-kernel": "~4.4 || ^5.0 || ^6.0 || ^7.0", - "monolog/monolog": "^1.22 || ^2.0 || ^3.0" + "php": ">=7.2.5", + "symfony/monolog-bridge": "^5.4 || ^6.0 || ^7.0", + "symfony/dependency-injection": "^5.4 || ^6.0 || ^7.0", + "symfony/config": "^5.4 || ^6.0 || ^7.0", + "symfony/http-kernel": "^5.4 || ^6.0 || ^7.0", + "monolog/monolog": "^1.25.1 || ^2.0 || ^3.0" }, "require-dev": { - "symfony/yaml": "~4.4 || ^5.0 || ^6.0 || ^7.0", - "symfony/console": "~4.4 || ^5.0 || ^6.0 || ^7.0", - "symfony/phpunit-bridge": "^5.2 || ^6.0 || ^7.0" + "symfony/yaml": "^5.4 || ^6.0 || ^7.0", + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/phpunit-bridge": "^6.3 || ^7.0" }, "autoload": { "psr-4": { "Symfony\\Bundle\\MonologBundle\\": "" },