8

I am trying to implement a KernelEvents::REQUEST event subscriber to perform some action on page load.

I need this event to fire regardless of whether the requested page exists in the Drupal cache - it seems that KernelEvents::REQUEST does not fire when Drupal serves something from the cache.

Is there an event I can use to achieve this, or must I implement my requirements as some form of middleware?

  • 1
    The REQUEST event HAS to be triggered, otherwise there would be no response. IMHO your ES has bad weight and the http_middleware.page_cache(or the dynamic page cache) service is stopping the propagation of the event further, hence your ES won't get triggered. – user21641 May 17 '16 at 10:20
  • ES weight / priority is set to 20 – BrynJ May 17 '16 at 12:32
  • As 4k4 wrote, page_cache for anonymous users is a middleware and happens long before the REQUEST event. You could write your own middleware that comes earlier, but you might want to reconsider your appraoch. What exactly needs to happen so early? Keep in mind that anonymous page caching might even happen in varnish other other external software or even the browsers themself. Have a look at how the core statistics module tracks page visits: With javascript that pings the server when a user executes it. – Berdir May 17 '16 at 14:12
  • @Berdir It's to provide http authentication for a site, similar to the Shield module - so I think this does represent a valid example of something that needs to be handled as early as possible in the request. (I'm aware there is D8 Shield module patch implemented as middleware - I'm assuming because of this limitation). – BrynJ May 18 '16 at 8:55
10

The dynamic cache subscribes an event with priority 27. If you want that your code runs before that you have to use a priority >27:

  public static function getSubscribedEvents() {
    $events = [];

    // Run after AuthenticationSubscriber (necessary for the 'user' cache
    // context; priority 300) and MaintenanceModeSubscriber (Dynamic Page Cache
    // should not be polluted by maintenance mode-specific behavior; priority
    // 30), but before ContentControllerSubscriber (updates _controller, but
    // that is a no-op when Dynamic Page Cache runs; priority 25).
    $events[KernelEvents::REQUEST][] = ['onRouteMatch', 27];

More details:

https://api.drupal.org/api/drupal/core!modules!config!tests!config_events_test!src!EventSubscriber.php/function/EventSubscriber%3A%3AgetSubscribedEvents/8.2.x

  • The priority is set to 20 – BrynJ May 17 '16 at 12:34
  • I think the problem you have is with the event from the dynamic cache, I edited my answer. – 4k4 May 17 '16 at 13:36
  • thanks @4k4, but even with priority set to 30 it still behaves the same (I reinstalled module and cleared all caches after making change). Any other ideas? – BrynJ May 17 '16 at 13:47
  • There are two caches. Now that you have priority over the dynamic cache there is still the page cache. The page cache is executed before the main kernel. You can uninstall this module and test if the performance is OK without it. – 4k4 May 17 '16 at 13:59
  • I can confirm that this worked for me. I had a redirect that only would happen once - before the page was cached. When I added a priority ['checkForRediret', 30]; then it worked as expected. – Cyclonecode Aug 16 '17 at 12:28
6

Drupal 8 has two level cache, page cache and dynamic page cache.

Yes you can intercept the dynamic page cache as what @4k4 mentioned. The issue you are having is more likely to intercept the page cache. The key is in here.

There are a few solutions for this:

  1. Add new class which implements 'HttpKernelInterface' and register 'http_middleware' with higher priority than 200 (280 will do). See 'PageCache' class and implementations for references.

  2. Create new class to alter the existing 'PageCache' by extending from 'ServiceProviderBase'. Check this out for references here. Then, create new class to extends the 'PageCache'.

Here is code references:

This is StaticCacheServiceProvider.php:

/**
 * Modifies the language manager service.
 */
class StaticCacheServiceProvider extends ServiceProviderBase
{
  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container)
  {
    // Overrides language_manager class to test domain language negotiation.
    $definition = $container->getDefinition('http_middleware.page_cache');
    $definition->setClass('Drupal\your_module\StackMiddleware\StaticCache');
  }
}

This is StaticCache.php:

/**
 * Executes the page caching before the main kernel takes over the request.
 */
class StaticCache extends PageCache
{
  /**
   * {@inheritdoc}
   */
  public function handle(Request $request, $type = self::MASTER_REQUEST, $catch = true)
  {
    // do special logic here.

    $response = parent::handle($request, $type, $catch);

    return $response;
  }
}

Hope helps.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.