diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/LoggerAwarePass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/LoggerAwarePass.php new file mode 100644 index 0000000000000..59292bc98dcc1 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/LoggerAwarePass.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Psr\Log\LoggerAwareInterface; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * Automatically add setLogger method call to any service that implements Psr\Log\LoggerAwareInterface. + * + * @see http://www.php-fig.org/psr/psr-3/ + * + * @author Gary PEGEOT + */ +class LoggerAwarePass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('logger') && !$container->hasAlias('logger')) { + return; + } + + $reference = new Reference('logger'); + + foreach (\array_keys($container->findTaggedServiceIds('logger.aware')) as $id) { + $definition = $container->findDefinition($id); + $class = $container->getReflectionClass($definition->getClass()); + + if (!$definition->hasMethodCall('setLogger') && $class && $class->implementsInterface(LoggerAwareInterface::class)) { + $definition->addMethodCall('setLogger', array($reference)); + } + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 1dcf47d9330a7..3966bd65e1a77 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection; use Doctrine\Common\Annotations\Reader; +use Psr\Log\LoggerAwareInterface; use Symfony\Bridge\Monolog\Processor\DebugProcessor; use Symfony\Bundle\FrameworkBundle\Command\RouterDebugCommand; use Symfony\Bundle\FrameworkBundle\Command\RouterMatchCommand; @@ -294,6 +295,8 @@ public function load(array $configs, ContainerBuilder $container) ->addTag('kernel.event_subscriber'); $container->registerForAutoconfiguration(ResettableInterface::class) ->addTag('kernel.reset', array('method' => 'reset')); + $container->registerForAutoconfiguration(LoggerAwareInterface::class) + ->addTag('logger.aware'); $container->registerForAutoconfiguration(PropertyListExtractorInterface::class) ->addTag('property_info.list_extractor'); $container->registerForAutoconfiguration(PropertyTypeExtractorInterface::class) diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 0cebbc3f49ae0..fbf791e52569b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -18,6 +18,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolClearerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPrunerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggerAwarePass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TemplatingPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass; @@ -114,6 +115,7 @@ public function build(ContainerBuilder $container) $this->addCompilerPassIfExists($container, FormPass::class); $container->addCompilerPass(new WorkflowGuardListenerPass()); $container->addCompilerPass(new ResettableServicePass()); + $container->addCompilerPass(new LoggerAwarePass()); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LoggerAwarePassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LoggerAwarePassTest.php new file mode 100644 index 0000000000000..f1a89992845aa --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/LoggerAwarePassTest.php @@ -0,0 +1,59 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\Compiler; + +use PHPUnit\Framework\TestCase; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerInterface; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggerAwarePass; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * Unit tests for Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggerAwarePass. + * + * @author Gary PEGEOT + */ +class LoggerAwarePassTest extends TestCase +{ + /** + * @covers \Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggerAwarePass::process() + */ + public function testProcess() + { + $container = new ContainerBuilder(); + $container->register('logger', LoggerInterface::class); + + $definition = $container->register('foo', get_class($this->createMock(LoggerAwareInterface::class))) + ->addTag('logger.aware'); + + $container->register('bar', 'stdClass'); + $container->register('not.autowired', LoggerInterface::class); + $this->assertFalse( + $definition->hasMethodCall('setLogger'), + 'Service should not have "setLogger" method call yet.' + ); + + (new LoggerAwarePass())->process($container); + + $this->assertTrue($definition->hasMethodCall('setLogger'), 'Service should have "setLogger" method call.'); + + $this->assertFalse( + $container->findDefinition('bar')->hasMethodCall('setLogger'), + '"bar" service should not be affected' + ); + + $this->assertFalse( + $container->findDefinition('not.autowired')->hasMethodCall('setLogger'), + 'Not autoconfigured service should not be affected.' + ); + } +}