With Drupal 8 and the implementation of a service container comes the concept of dependency injection. Dependency injection is a software design concept, and at its base level, it provides a means to use a class without having to directly reference it. In our example, we retrieve services multiple times using the global static class \Drupal. This is bad practice within services, and can make testing more difficult.
To implement dependency injection, first, we will add a constructor to our class that accepts the services used (current_route_match and current_user) and matches protected properties to store them:
/**
* The route match.
*
* @var \Drupal\Core\Routing\RouteMatchInterface
*/
protected $routeMatch;
/**
* Account proxy.
*
* @var \Drupal\Core\Session\AccountProxyInterface
*/
protected $accountProxy;
/**
* Creates a new RequestSubscriber object.
*
* @param \Drupal\Core\Routing\RouteMatchInterface $route_match
* The route match.
* @param \Drupal\Core\Session\AccountProxyInterface $account_proxy
* The current user.
*/
public function __construct(RouteMatchInterface $route_match, AccountProxyInterface $account_proxy) {
$this->routeMatch = $route_match;
$this->accountProxy = $account_proxy;
}
We can then replace any calls to \Drupal:: with $this->:
/**
* Redirects all anonymous users to the login page.
*
* @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
* The event.
*/
public function doAnonymousRedirect(GetResponseEvent $event) {
// Make sure we are not on the user login route.
if ($this->routeMatch->getRouteName() == 'user.login') {
return;
}
// Check if the current user is logged in.
if ($this->accountProxy->isAnonymous()) {
// If they are not logged in, create a redirect response.
$url = Url::fromRoute('user.login')->toString();
$redirect = new RedirectResponse($url);
// Set the redirect response on the event, cancelling default response.
$event->setResponse($redirect);
}
}
Finally, we will update mymodule.services.yml to specify our constructor arguments so that they will be injected when the container runs our event subscriber:
services:
mymodule.request_subscriber:
class: Drupal\mymodule\EventSubscriber\RequestSubscriber
arguments: ['@current_route_match', '@current_user']
tags:
- { name: event_subscriber }
Dependency injection feels and seems magical at first. However, with use and practice, it will begin to make more sense and become second nature when developing with Drupal 8.