Uh oh!
There was an error while loading.Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork9.7k
[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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.
Already on GitHub?Sign in to your account
Uh oh!
There was an error while loading.Please reload this page.
Conversation
ro0NL commentedNov 15, 2017
enable by |
chalasr commentedNov 15, 2017
Belongs to monolog-bundle to me. |
ogizanagi commentedNov 15, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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 =newReference('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 LoggerAwarePassTestextends 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 =newReference('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 wantautoconfigure to leverage this, the compiler pass should only process definitions with a given tag, and that tag+LoggerAwareInterface should be registered for autoconfiguration (seehttps://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 theclass_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 wantautoconfigure to leverage this, the compiler pass should only process definitions with a given tag, and that tag+LoggerAwareInterface should be registered for autoconfiguration (seehttps://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 (likelogger.aware?) or skip this checking and add the method call anyway ?
nicolas-grekas left a comment• edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
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.
GaryPEGEOT commentedNov 15, 2017
Shouldn't we check that method call ins't already called explicitly ? |
chalasr commentedNov 15, 2017
@nicolas-grekas Actually I think adding method calls to autoconfigure instanceofs is forbiddenhttps://github.com/symfony/symfony/blob/master/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php#L37, isn't it? Should we remove that restriction? |
nicolas-grekas commentedNov 15, 2017
Calling a setter twice is not an issue to me so not really a pb. |
chalasr commentedNov 15, 2017
@GaryPEGEOT Can you replace the removed test by a new one ensuring that method calls are handled? |
| ->addTag('validator.initializer'); | ||
| $container->registerForAutoconfiguration(LoggerAwareInterface::class) | ||
| ->addMethodCall('setLogger',array(newReference(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; weadd a method call. But being a setter that messes things up.
Also not sure it justifies aaddMethodCallOnce feat., perhaps as 2nd arg?
GaryPEGEOT commentedNov 16, 2017
@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. */publicfunctiontestProcessForAutoconfiguredCalls() {$container =newContainerBuilder();$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 (newResolveInstanceofConditionalsPass())->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 */publicfunctionsetLogger(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. |
nicolas-grekas commentedNov 16, 2017
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. |
weaverryan commentedNov 16, 2017
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. |
ogizanagi commentedNov 16, 2017 • edited
Loading Uh oh!
There was an error while loading.Please reload this page.
edited
Uh oh!
There was an error while loading.Please reload this page.
There is already aLoggerAwareTrait part of the |
GaryPEGEOT commentedNov 16, 2017
I made a separate MR#24996 to allow auto-configured method calls |
nicolas-grekas commentedNov 19, 2017
Closing in favor of#24996, thanks@GaryPEGEOT for taking over. |
Uh oh!
There was an error while loading.Please reload this page.
Automatically add
setLoggermethod call to any service that implementsPsr\Log\LoggerAwareInterface.Not sure if this belong to FrameworkBundle or MonologBundle.