Skip to content Get in touch

Contact form

Writing code

Dependency injection in Drupal console commands

Most Drupal 8 developers make ordinary use of the built-in logger which is automatically available in every custom form that extends FormBase, like this:

$this->logger('my_channel')->notice('My message with some %variable', ['%variable' => $variable]);

(ref: Drupal API)

And the same holds true when you extend ControllerBase in your custom controller, where you can do something like:

$this->logger = $this->getLogger('my_channel');

(ref: Drupal API)

When you’re not extending any of those classes, though, you might have used the static call that is available thru the “magic” \Drupal object, like this:

\Drupal::logger('my_channel')->notice($my_message);

It works just fine, and you might be totally ok with it, unless… you want to do some linting (first step towards code quality 😉 ) and you start using phpcs with the DrupalPractice coding standard.

Then you would start getting complaints like this:

$ phpcs -sw --standard=DrupalPractice html/web/modules/custom/.../MyClass.php
FILE: .../modules/custom/.../MyClass.php
----------------------------------------------------------------------
FOUND 0 ERRORS AND 1 WARNING AFFECTING 1 LINE
----------------------------------------------------------------------
 32 | WARNING | \Drupal calls should be avoided in classes, use
    |         | dependency injection instead
    |         | (DrupalPractice.Objects.GlobalDrupal.GlobalDrupal)
----------------------------------------------------------------------

In particular, that happened to me in my Drupal console custom commands, and after some investigation I understood how to get the logger service available through dependency injection.

Here is what I’ve done:

  • in modules/custom/my_module/console.services.yml I added:

logger.channel.my_module:
parent: logger.channel_base
arguments: ['my_module']

  • and then I added the argument to the command, like:

my_module.handler:
class: Drupal\my_module\Handler\MyHandler
arguments: ['@logger.channel.my_module', ...]

  • next, in the class header:

use Drupal\Core\Logger\LoggerChannelInterface;

  • and in the declarations I added the new variable:

/**
* The logger interface needed to log messages on the Drupal log.
*
* @var Drupal\Core\Logger\LoggerChannelInterface
*/

protected $logger;

  • and added (where I did not have one yet) or adjusted the constructor, to look like this:

/**
* Constructs a new MyHandler.
*
* @param \Drupal\Core\Logger\LoggerChannelInterface $logger
*   The logger interface.
*/

public function __construct(LoggerChannelInterface $logger = NULL) {
  parent::__construct();
  if ($logger != NULL) {
    $this->logger = $logger;
  }
}

And that was it!

Finally, I could use the logger like this:

$this->logger->notice('My message');

 

Et voilà, no more complaints from the code sniffer and perhaps more importantly better quality code 🙂

Other thoughts

More thoughts