-
-
Notifications
You must be signed in to change notification settings - Fork 9.6k
[FrameworkBundle] [DI] Automatically add "setLogger" method call. #24973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
enable by |
Belongs to monolog-bundle to me. |
Looks good to me in the FrameworkBundle, as we now have the default logger from HttpKernel registered as |
} | ||
|
||
$refl = new \ReflectionClass($definition->getClass()); | ||
if ($refl->implementsInterface(LoggerAwareInterface::class) && !$definition->hasMethodCall('setLogger')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe:
if ($definition->hasMethodCall('setLogger')) {
continue;
}
if (\in_array(LoggerAwareInterface::class, class_implements($definition->getClass()), true)) {
}
$reference = new Reference('logger'); | ||
|
||
foreach ($container->getDefinitions() as $definition) { | ||
if (!class_exists($definition->getClass()) || !$definition->isAutoconfigured()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|| $definition->hasMethodCall('setLogger')
here?
continue; | ||
} | ||
|
||
$refl = new \ReflectionClass($definition->getClass()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
$container->getReflectionClass()
i guess =/
class LoggerAwarePassTest extends TestCase | ||
{ | ||
/** | ||
* @covers \Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggerAwarePass::process() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dont think this is needed really.
$reference = new Reference('logger'); | ||
|
||
foreach ($container->getDefinitions() as $definition) { | ||
if (!class_exists($definition->getClass()) || !$definition->isAutoconfigured()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no reason to skip autoconfigured definitions. If we want autoconfigure
to leverage this, the compiler pass should only process definitions with a given tag, and that tag+LoggerAwareInterface should be registered for autoconfiguration (see https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L269).
continue; | ||
} | ||
|
||
$refl = new \ReflectionClass($definition->getClass()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should use $container->getReflectionClass()
and be done earlier, replacing the class_exists
check by !$refl
and probably throwing in case the check passes. See e.g. https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Console/DependencyInjection/AddConsoleCommandPass.php#L55
|
||
foreach ($container->getDefinitions() as $definition) { | ||
$class = $definition->getClass(); | ||
if (!class_exists($class) || !$definition->isAutoconfigured() || $definition->hasMethodCall('setLogger')) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want autoconfigure
to leverage this, the compiler pass should only process definitions with a given tag, and that tag+LoggerAwareInterface should be registered for autoconfiguration (see https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php#L269).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
!class_exists
should be replaced by !$refl
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
About autoconfiguration, should I add tag in Framework extension (like logger.aware
?) or skip this checking and add the method call anyway ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wait, we don't need that compiler pass at all.
If we want to provide the behavior when autoconfiguration is on, we should just call $container->registerForAutoconfiguration(LoggerAwareInterface::class)->addMethodCall('setLogger', array(new Reference(LoggerInterface::class)))
in some DI extension.
Shouldn't we check that method call ins't already called explicitly ? |
@nicolas-grekas Actually I think adding method calls to autoconfigure instanceofs is forbidden https://github.com/symfony/symfony/blob/master/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php#L37, isn't it? Should we remove that restriction? |
Calling a setter twice is not an issue to me so not really a pb. |
@GaryPEGEOT Can you replace the removed test by a new one ensuring that method calls are handled? |
@@ -315,6 +317,9 @@ public function load(array $configs, ContainerBuilder $container) | |||
$container->registerForAutoconfiguration(ObjectInitializerInterface::class) | |||
->addTag('validator.initializer'); | |||
|
|||
$container->registerForAutoconfiguration(LoggerAwareInterface::class) | |||
->addMethodCall('setLogger', array(new Reference(LoggerInterface::class))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Calling a setter twice is not an issue to me so not really a pb.
It would be a WTF no? (who's winning here?) Requires to move your definition outside the current file/context at least... not sure that justifies our technical implem, which is correct; we add a method call. But being a setter that messes things up.
Also not sure it justifies a addMethodCallOnce
feat., perhaps as 2nd arg?
@nicolas-grekas Actually autoconfigured calls seems not to be working out of the box (Or I'm missing something.): /**
* Test that autoconfigured calls are handled gracefully.
*/
public function testProcessForAutoconfiguredCalls()
{
$container = new ContainerBuilder(); $container->registerForAutoconfiguration(LoggerAwareInterface::class)->addMethodCall('setLogger')->addTag('foo');
$def = $container->register(\get_class($this->createMock(LoggerAwareInterface::class)));
$this->assertFalse($def->hasTag('foo'), 'Definition shouldn\'t have tags yet.'); // Passes
$this->assertFalse($def->hasMethodCall('setLogger'), 'Definition shouldn\'t have method call yet.'); // Passes
(new ResolveInstanceofConditionalsPass())->process($container);
$this->assertTrue($def->hasTag('foo'), 'Definition should have "foo" tag.'); // Passes
$this->assertTrue($def->hasMethodCall('setLogger'), 'Definition should have "setLogger" method call.'); // Fail
} And I see potential problems for calling set twice, if by example, method is overrided for any reason: /**
* Sets a logger instance on the object.
*
* @param LoggerInterface $logger
* @param string $channel Which channel to use
*
* @return void
*/
public function setLogger(LoggerInterface $logger, string $channel = null)
{
// TODO: Implement setLogger() method.
} Here second parameter will be called with default param, so not necessary the expected behavior. Compiler pass with tagged services seems to be the best option to me. |
06502f1
to
35404a9
Compare
I'm OK to agree with that. That makes me wonder we should make that work in fact. The current exception in place that prevents using setters was put in place exactly because we didn't bother fixing those topic at the time. But I would definitely prefer merging a PR that fixes that, which would provide high generality to the feature, vs merging a hardcoded adhoc alternative. The compiler pass as is could really well be part of a third party bundle meanwhile if you really want it. |
This makes sense. But this still requires the user to add the setLogger method. A better DX would be to add a new LoggerTrait with ‘@required’ above the setLogger method. |
There is already a LoggerAwareTrait part of the |
I made a separate MR #24996 to allow auto-configured method calls |
Closing in favor of #24996, thanks @GaryPEGEOT for taking over. |
Automatically add
setLogger
method call to any service that implementsPsr\Log\LoggerAwareInterface
.Not sure if this belong to FrameworkBundle or MonologBundle.