Problem/Motivation
Follow-up to #2729643-15: Create LoggerChannelTrait
Creating a new trait for logger service discovery has led us to a problem:
If we want to require that the service trait use an injected service object, we end up breaking various callers.
Existing code which relies on, for instance, ControllerBase::getLogger()
, but which does not properly use the ContainerInjectionInterface
pattern, might break when the logger service wasn't previously injected.
This leads to a chicken/egg scenario where we have to figure out what to break and what to fix first. Some classes that use a service location trait will use the service setter of the trait during the factory method or during construction in order to inject the service. Others won't, which necessitates using \Drupal
within the trait in order to discover the service. If we enforce the injection of the service by not using \Drupal
in the getter, we then allow for poor Inversion of Control (IoC) practices. If we enforce IoC practices, however, we break existing code.
Proposed resolution
Note that this is a proposed resolution. :-)
Ensure that all service discovery traits have a setter for the service and make it clear that it's the best practice to use the setter in the class' factory method to perform injection.
Continue to use the \Drupal
service pattern in these traits until classes which use them have been converted to the 'proper' IoC injection pattern. This means that traits will continue to have service accessors, and those accessors will use \Drupal
to discover the service if it hasn't happened already.
Once those classes have been converted, have service traits enforce the IoC pattern. This means altering the behavior of the service accessors so that they don't use \Drupal
, and instead fail if the service hasn't already been injected.