diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.xml index 786158dd89..fb0b99255a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.xml @@ -15,12 +15,13 @@ null - + null %debug.error_handler.throw_at% %kernel.debug% %kernel.debug% + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 55332ab60b..f175975896 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -425,7 +425,7 @@ abstract class FrameworkExtensionTest extends TestCase $container = $this->createContainerFromFile('php_errors_enabled'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertNull($definition->getArgument(2)); $this->assertSame(-1, $container->getParameter('debug.error_handler.throw_at')); } @@ -445,7 +445,7 @@ abstract class FrameworkExtensionTest extends TestCase $container = $this->createContainerFromFile('php_errors_log_level'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertSame(8, $definition->getArgument(2)); } diff --git a/src/Symfony/Component/HttpKernel/CHANGELOG.md b/src/Symfony/Component/HttpKernel/CHANGELOG.md index 2e12f8d434..0d4f81c4ea 100644 --- a/src/Symfony/Component/HttpKernel/CHANGELOG.md +++ b/src/Symfony/Component/HttpKernel/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +5.2.0 +----- + + * allowed to use a specific logger channel for deprecations + 5.1.0 ----- diff --git a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php index 9cecf164bc..44b1ddb187 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php @@ -32,6 +32,7 @@ class DebugHandlersListener implements EventSubscriberInterface { private $exceptionHandler; private $logger; + private $deprecationLogger; private $levels; private $throwAt; private $scream; @@ -48,7 +49,7 @@ class DebugHandlersListener implements EventSubscriberInterface * @param string|FileLinkFormatter|null $fileLinkFormat The format for links to source files * @param bool $scope Enables/disables scoping mode */ - public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, ?int $throwAt = E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true) + public function __construct(callable $exceptionHandler = null, LoggerInterface $logger = null, $levels = E_ALL, ?int $throwAt = E_ALL, bool $scream = true, $fileLinkFormat = null, bool $scope = true, LoggerInterface $deprecationLogger = null) { $this->exceptionHandler = $exceptionHandler; $this->logger = $logger; @@ -57,6 +58,7 @@ class DebugHandlersListener implements EventSubscriberInterface $this->scream = $scream; $this->fileLinkFormat = $fileLinkFormat; $this->scope = $scope; + $this->deprecationLogger = $deprecationLogger; } /** @@ -76,31 +78,30 @@ class DebugHandlersListener implements EventSubscriberInterface $handler = \is_array($handler) ? $handler[0] : null; restore_exception_handler(); - if ($this->logger || null !== $this->throwAt) { - if ($handler instanceof ErrorHandler) { - if ($this->logger) { - $handler->setDefaultLogger($this->logger, $this->levels); - if (\is_array($this->levels)) { - $levels = 0; - foreach ($this->levels as $type => $log) { - $levels |= $type; - } - } else { - $levels = $this->levels; + if ($handler instanceof ErrorHandler) { + if ($this->logger || $this->deprecationLogger) { + $this->setDefaultLoggers($handler); + if (\is_array($this->levels)) { + $levels = 0; + foreach ($this->levels as $type => $log) { + $levels |= $type; } - if ($this->scream) { - $handler->screamAt($levels); - } - if ($this->scope) { - $handler->scopeAt($levels & ~E_USER_DEPRECATED & ~E_DEPRECATED); - } else { - $handler->scopeAt(0, true); - } - $this->logger = $this->levels = null; + } else { + $levels = $this->levels; } - if (null !== $this->throwAt) { - $handler->throwAt($this->throwAt, true); + + if ($this->scream) { + $handler->screamAt($levels); } + if ($this->scope) { + $handler->scopeAt($levels & ~E_USER_DEPRECATED & ~E_DEPRECATED); + } else { + $handler->scopeAt(0, true); + } + $this->logger = $this->deprecationLogger = $this->levels = null; + } + if (null !== $this->throwAt) { + $handler->throwAt($this->throwAt, true); } } if (!$this->exceptionHandler) { @@ -135,6 +136,34 @@ class DebugHandlersListener implements EventSubscriberInterface } } + private function setDefaultLoggers(ErrorHandler $handler): void + { + if (\is_array($this->levels)) { + $levelsDeprecatedOnly = []; + $levelsWithoutDeprecated = []; + foreach ($this->levels as $type => $log) { + if (E_DEPRECATED == $type || E_USER_DEPRECATED == $type) { + $levelsDeprecatedOnly[$type] = $log; + } else { + $levelsWithoutDeprecated[$type] = $log; + } + } + } else { + $levelsDeprecatedOnly = $this->levels & (E_DEPRECATED | E_USER_DEPRECATED); + $levelsWithoutDeprecated = $this->levels & ~E_DEPRECATED & ~E_USER_DEPRECATED; + } + + $defaultLoggerLevels = $this->levels; + if ($this->deprecationLogger && $levelsDeprecatedOnly) { + $handler->setDefaultLogger($this->deprecationLogger, $levelsDeprecatedOnly); + $defaultLoggerLevels = $levelsWithoutDeprecated; + } + + if ($this->logger && $defaultLoggerLevels) { + $handler->setDefaultLogger($this->logger, $defaultLoggerLevels); + } + } + public static function getSubscribedEvents(): array { $events = [KernelEvents::REQUEST => ['configure', 2048]]; diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/DebugHandlersListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/DebugHandlersListenerTest.php index 6f04c0a4c6..abd202f381 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/DebugHandlersListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/DebugHandlersListenerTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Symfony\Component\Console\Application; use Symfony\Component\Console\Command\Command; @@ -150,4 +151,89 @@ class DebugHandlersListenerTest extends TestCase $this->assertSame($userHandler, $eHandler->setExceptionHandler('var_dump')); } + + public function provideLevelsAssignedToLoggers(): array + { + return [ + [false, false, '0', null, null], + [false, false, E_ALL, null, null], + [false, false, [], null, null], + [false, false, [E_WARNING => LogLevel::WARNING, E_USER_DEPRECATED => LogLevel::NOTICE], null, null], + + [true, false, E_ALL, E_ALL, null], + [true, false, E_DEPRECATED, E_DEPRECATED, null], + [true, false, [], null, null], + [true, false, [E_WARNING => LogLevel::WARNING, E_DEPRECATED => LogLevel::NOTICE], [E_WARNING => LogLevel::WARNING, E_DEPRECATED => LogLevel::NOTICE], null], + + [false, true, '0', null, null], + [false, true, E_ALL, null, E_DEPRECATED | E_USER_DEPRECATED], + [false, true, E_ERROR, null, null], + [false, true, [], null, null], + [false, true, [E_ERROR => LogLevel::ERROR, E_DEPRECATED => LogLevel::DEBUG], null, [E_DEPRECATED => LogLevel::DEBUG]], + + [true, true, '0', null, null], + [true, true, E_ALL, E_ALL & ~(E_DEPRECATED | E_USER_DEPRECATED), E_DEPRECATED | E_USER_DEPRECATED], + [true, true, E_ERROR, E_ERROR, null], + [true, true, E_USER_DEPRECATED, null, E_USER_DEPRECATED], + [true, true, [E_ERROR => LogLevel::ERROR, E_DEPRECATED => LogLevel::DEBUG], [E_ERROR => LogLevel::ERROR], [E_DEPRECATED => LogLevel::DEBUG]], + [true, true, [E_ERROR => LogLevel::ALERT], [E_ERROR => LogLevel::ALERT], null], + [true, true, [E_USER_DEPRECATED => LogLevel::NOTICE], null, [E_USER_DEPRECATED => LogLevel::NOTICE]], + ]; + } + + /** + * @dataProvider provideLevelsAssignedToLoggers + * + * @param array|string $levels + * @param array|string|null $expectedLoggerLevels + * @param array|string|null $expectedDeprecationLoggerLevels + */ + public function testLevelsAssignedToLoggers(bool $hasLogger, bool $hasDeprecationLogger, $levels, $expectedLoggerLevels, $expectedDeprecationLoggerLevels) + { + if (!class_exists(ErrorHandler::class)) { + $this->markTestSkipped('ErrorHandler component is required to run this test.'); + } + + $handler = $this->createMock(ErrorHandler::class); + + $expectedCalls = []; + $logger = null; + + $deprecationLogger = null; + if ($hasDeprecationLogger) { + $deprecationLogger = $this->createMock(LoggerInterface::class); + if (null !== $expectedDeprecationLoggerLevels) { + $expectedCalls[] = [$deprecationLogger, $expectedDeprecationLoggerLevels]; + } + } + + if ($hasLogger) { + $logger = $this->createMock(LoggerInterface::class); + if (null !== $expectedLoggerLevels) { + $expectedCalls[] = [$logger, $expectedLoggerLevels]; + } + } + + $handler + ->expects($this->exactly(\count($expectedCalls))) + ->method('setDefaultLogger') + ->withConsecutive(...$expectedCalls); + + $sut = new DebugHandlersListener(null, $logger, $levels, null, true, null, true, $deprecationLogger); + $prevHander = set_exception_handler([$handler, 'handleError']); + + try { + $handler + ->method('handleError') + ->willReturnCallback(function () use ($prevHander) { + $prevHander(...\func_get_args()); + }); + + $sut->configure(); + set_exception_handler($prevHander); + } catch (\Exception $e) { + set_exception_handler($prevHander); + throw $e; + } + } }