This course is archived!
This tutorial is built using Drupal 8.0. The fundamental concepts of Drupal 8 - like services & routing - are still valid, but newer versions of Drupal *do* have major differences.
Event Arguments and the Request
Keep on Learning!
If you liked what you've learned so far, dive in! Subscribe to get access to this tutorial plus video, code and script downloads.
With a Subscription, click any sentence in the script to jump to that part of the video!
Login SubscribeWe now know that when you listen to this event, it passes you an event object called GetResponseEvent
. Type-hint the argument to enjoy auto-completion:
// ... lines 1 - 5 | |
use Symfony\Component\HttpKernel\Event\GetResponseEvent; | |
// ... lines 7 - 8 | |
class DinoListener implements EventSubscriberInterface | |
{ | |
public function onKernelRequest(GetResponseEvent $event) | |
{ | |
// ... lines 13 - 18 | |
} | |
// ... lines 20 - 27 | |
} |
Using the Event Argument
This event object has a getRequest()
method, use that to set a new $request
variable:
// ... lines 1 - 10 | |
public function onKernelRequest(GetResponseEvent $event) | |
{ | |
$request = $event->getRequest(); | |
// ... lines 14 - 18 | |
} | |
// ... lines 20 - 28 |
This is Drupal's - and Symfony's - Request object. If you want to read some GET params, POST params, headers or session stuff, this is your friend. You can of course get the Request object inside a controller.
Here's the goal: if the URL has a ?roar=1
on it, then I want to log a message. If not, we'll do nothing. Make a new variable called $shouldRoar
. To access the GET, or query parameters on the request, use $request->query->get('roar')
:
// ... lines 1 - 10 | |
public function onKernelRequest(GetResponseEvent $event) | |
{ | |
$request = $event->getRequest(); | |
$shouldRoar = $request->query->get('roar'); | |
// ... lines 15 - 18 | |
} | |
// ... lines 20 - 28 |
If it's not there, this returns null
:
Next, if ($shouldRoar)
, just var_dump('ROOOOAR')
and die to test things:
// ... lines 1 - 10 | |
public function onKernelRequest(GetResponseEvent $event) | |
{ | |
// ... lines 13 - 15 | |
if ($shouldRoar) { | |
var_dump('ROOOOOOOOAR');die; | |
} | |
} | |
// ... lines 20 - 28 |
Since we didn't touch any configuration, we can refresh without clearing anything.
Page not found! We're on the profiler page for a past request, and this information is stored in the cache... which we just cleared. So go find a real page. Ok, it works perfectly. Now add ?roar=1
. It hits! And this will work on any page.
Dependency Inject All the Things
How can we log something? We faced this problem earlier when we wanted to use the keyvalue
store inside RoarGenerator
. We solved it with dependency injection: create a __construct()
method, pass in what you need, and set it on a property. This is no different.
Add public function __construct()
. Look for the logger in container:debug
:
drupal container:debug | grep log
The logger.factory
is an instance of LoggerChannelFactory
. Type-hint using that. And like with other stuff, this has an interface, which is a trendier option. I'll hit option+enter to add the property and set it:
// ... lines 1 - 4 | |
use Drupal\Core\Logger\LoggerChannelFactoryInterface; | |
// ... lines 6 - 9 | |
class DinoListener implements EventSubscriberInterface | |
{ | |
private $loggerChannel; | |
public function __construct(LoggerChannelFactoryInterface $loggerChannel) | |
{ | |
$this->loggerChannel = $loggerChannel; | |
} | |
// ... lines 18 - 36 | |
} |
Below, if you wanna roar, do it! $this->loggerFactory->get()
- and use the default
channel. Then add a debug
message: 'Roar requested: ROOOOOAR':
// ... lines 1 - 9 | |
class DinoListener implements EventSubscriberInterface | |
{ | |
// ... lines 12 - 18 | |
public function onKernelRequest(GetResponseEvent $event) | |
{ | |
// ... lines 21 - 23 | |
if ($shouldRoar) { | |
$channel = $this->loggerChannel->get('default') | |
->debug('ROOOOOOOOAR'); | |
} | |
} | |
// ... lines 29 - 36 | |
} |
That's it guys! We didn't touch any config, so just refresh. Oh no, an error:
Argument 1 passed to DinoListener::__construct() must implement LoggerChannelFactoryInterface, none given.
Can you spot the problem? We saw this once before. We forgot to tell the container about the new argument. In dino_roar.services.yml
, add @logger.factory
:
// ... lines 1 - 3 | |
services: | |
// ... lines 5 - 10 | |
dino_roar.dino_listener: | |
// ... line 12 | |
arguments: ['@logger.factory'] | |
// ... lines 14 - 16 |
This is a single-line YAML-equivalent to what I did for the other service.
Rebuild the cache:
drupal cache:rebuild
Refresh. No error! Head into "Reports" and then "Recent Log Messages". There's the "Roar Requested".
You're now an event listener pro. We listened to the kernel.reqeust
event, but you can add a listener to any event that Drupal or a third-party module exposes.
Hello weaverryan,
It's an interesting topic here, and thank you for explaining this dangerous skills in event subscribe thingy.
I have 1 question, which I tried myself but I am still blur on this.
I have a webform, which I want to subscribe the even when any webform submission edited (as approved) by me.
I don't know which exact listener to put actually. I tried with
KernelEvents::FINISH_REQUEST
I can see the params to manipulate, in the dump, but when I tried to use it, it returns null as cannot access it in the class.
Well, the strugle is quite overkill now, May I know if there any easier to workout with putting subscriber for specific event like webform update or node update?
Or do we have to use hook instead..