Closed (fixed)
Project:
Drupal core
Version:
8.2.x-dev
Component:
other
Priority:
Normal
Category:
Task
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
19 May 2016 at 20:46 UTC
Updated:
10 Jul 2016 at 00:04 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #2
mile23Added
LoggerChannelTrait, used it inControllerBaseandFormBase.Comment #3
mile23Comment #4
mile23Comment #5
mile23Comment #7
mile23ControllerBasehadgetLogger().FormBasehadlogger().getLogger()wins for being more descriptive, soLoggerChannelTrait::getLogger()exists.FormBase::logger()now just callsLoggerChannelTrait::getLogger(), with a note in docs about how it's a compatibility shim.If this trait is desired by maintainers, we can go through and change calls to
logger()withgetLogger()and removeFormBase::logger()in a subsequent patch.Comment #9
neclimdulMissing return.
Comment #10
mile23Ewps.
Added
return. :-) Also added a@todo.Comment #11
neclimdulGood call however I think @todo's need to come with issue links now. I would be OK with deprecating this now actually targeted at 9.x removal but if you want to open a discussion I would open the issue and link it.
Comment #12
dawehnerGreat small patch!
It is weird that logger needs to be public now
Comment #13
mile23OK, I took out the @todo because I think the 'don't use this' is enough, and because this issue is really yak shaving for #2729625: Inject services into BookAdminEditForm and ultimately #2729597: [meta] Replace \Drupal with injected services where appropriate in core. We don't want to have to re-implement
logger()every time we decideFormBaseis bad. Which it is. :-) #2674508: Improve docs for how to properly add container injection into a class that extends FormBaseNice catch on public vs. protected.
Addressed here.
Comment #14
daffie commentedIt all looks good to me. @dawehner also likes this patch. The problems from comment #11 and #12 are fixed.
Comment #15
catchThe two implementations this replaces get the logger from the container directly. Can we also do that here, and just enforce that the classes that use it are container aware?
Comment #16
mile23Ab.
So.
Lutely.
I was following the example of the other service traits for consistency.
I would be more than happy to open follow-ups to modify the other traits in the same way. :-)
Comment #17
mile23Used assert() to enforce the existence of the service.
Since this was me learning assert(), there's also a test. :-)
Comment #19
mile23OK, so that list of failed tests is a nice list of action items for #2733703: [plan] Service traits should require IoC injection which I just created.
Converting back to
\Drupalfor now, and adding a @todo about #2733703: [plan] Service traits should require IoC injectionThe plan might be to use
\Drupaland then switch over to requiring the injected service once the classes which use the trait have been converted to IoC.Maintainers can of course have a differing idea. :-)
Comment #20
catchOK so that was worth a try, but also it wasn't what I suggested:
So we'd assume that classes using the trait are container aware, and access $this->container instead of using \Drupal.
Comment #21
mile23Yah, I didn't get what you meant, but the reason is that there's no
$this->container, or at least there shouldn't be. :-)The trait wraps a service that's already been injected, and if it's not there,
\Drupalis the backup. The problem with that is the service dependency becomes a magic one.So we might solve that by requiring a container, but then we lose the many benefits of inversion of control, mainly enabling SOLID in more places.
So if we want this trait to be strict about it's users having already injected the dependency, then we'd assert on the specific dependency, rather than the container. In this case, we don't care where the
LoggerChannelFactoryInterfacecame from, only that we have one.That means our trait only has one dependency:
LoggerChannelFactoryInterface.That's better than having one explicit but non-specific dependency (the container), plus a magic one.
Reworked the patch from #19 because I forgot to remove the assertion test.
Comment #22
mile23Erp... Wrong interdiff.
Comment #23
catchThis should only be used in application-level code that's already container aware though - as the two examples converting to it are. For injected logger service you're probably writing a service yourself, which can just inject directly.
For me the explicit container dependency is better than the \Drupal + container dependency. But we might need a third opinion here.
Comment #24
mile23You might want to research that.
There's no such thing as
ContainerAwareInterfacein Drupal, which is a good thing.FormBaseimplementsContainerInjectionInterface, and doesn't store the container and doesn't give you a way to access the container.https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Form%21Fo...
ControllerBasegives you an accessor for\Drupalwhich a) makes no sense because it's marked private and why don't those other methods just call\Drupal? And b) is not a part of any interface.So it's all magic voodoo. :-)
I am willing to do the work to untangle all this, as I have been doing.
But in order to start, I need a trait instead of re-implementing logger() all the time.
Comment #25
catchgrep -r "ContainerAwareInterface" *
It's from Symfony. Lots of our classes implement it.
But you're right, not these two.
https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Controlle... is the offending method for anyone following along.
So yes that's weird, and this patch doesn't introduce any more \Drupal calls than we already have.
Comment #26
mile23Yes indeedy
ContainerAwareInterface: 21 files implement it. Then we have 22 files with 'use ContainerAwareTrait'. Take a look atEntityTypeManager::createHandlerInstance(), where we check for the existence of trait methods. That's the kind of code smell I'm talking about, and why we should do things like assert that the dependency is already discovered as per #17.Anyway...
So what we have in patch #21 is similar to the other service traits, in that if the user didn't initialize the service (bad user, bad!), the trait will grab it from
\Drupal. As the todo points out, this is a halfway measure and we might potentially replace that with an assertion or with something else entirely.We also use the trait in two base classes,
ControllerBaseandFormBase, which seems like a good place to start. We re-implementFormBase::logger()to use the trait'sgetLogger().Once this is in we can then re-roll #2729625: Inject services into BookAdminEditForm for the log service, and move forward on something like #2729597: [meta] Replace \Drupal with injected services where appropriate in core without re-implementing logger discovery in every class that uses it.
The patch in #21 contains a @todo pointing to this issue: #2733703: [plan] Service traits should require IoC injection which is where we really should have had the conversation starting in #20. :-)
Plus contrib can now use the logger trait. :-)
Anyone care to review?
Comment #27
jibranShould we add tests for it?
This is not applicable any more.
Comment #28
daffie commented@jibran: The todo is just what needs to be done to fix the problem with the injected services. We are now using
Drupal::service('something')and that needs to be replaced.The patch is the same as the one from comment #13 with two small comments added about container injection and the todo. The problem that @catch has with the container injection are to be addressed in the followup (#2733703: [plan] Service traits should require IoC injection). So for me it is back to RTBC.
Comment #29
jibranHow about we should add a
LoggerChannelInterfaceas well? Just likeContainerAwareTraitandContainerAwareInterfaceand it would look like this.Now every class which uses
LoggerChannelTraithas to implementLoggerChannelInterfaceand we don't have to set logger in getter.Comment #30
mile23@jibran: It's a different thing. We want to emulate traits like
StringTranslationTraitandLinkGeneratorTrait. These do not supply interfaces.ContainerAwareTraitexists so you have a default way of implementingContainerAwareInterface, so that you can store the container. We don't want to supply a default method for injecting specific dependencies (in this case, logger factory) for controllers or forms. We only want a way to avoid re-implementing boilerplate for *using* those dependencies.Comment #31
daffie commented@jibran: Mile23 has responded to your remark 20 days ago. And he explained why he did not did it the way you would like it. I think that you had enough time to respond. so I will put the status back to RTBC.
Comment #32
alexpottCommitted f7b235c and pushed to 8.2.x. Thanks!
The trait is the same namespace so the use is not necessary.
Comment #33
mile23Clicking on that cgit link... http://cgit.drupalcode.org/drupal/commit/?id=f7b235c
"Bad object id: f7b235c"
Not pushed yet?
Comment #35
mile23Awesome. Thanks. :-)