17

I need to implement an event subscriber to perform some actions when the page is loaded. The event should be fired whether the requested page exists in the Drupal cache or not. It seems that the KernelEvents::REQUEST event doesn't fire when Drupal serves something from the cache.

Is there an event I can use to achieve this, or should I implement some form of middleware?

1
  • 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
    Commented May 17, 2016 at 14:12

3 Answers 3

17

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][] = ['onRequest', 27];

Which runs DynamicPageCacheSubscriber::onRequest..

0
9

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.

1
  • This was very helpfull thankyou, I solved the problem by implementing solution 1. Commented Nov 18, 2019 at 10:46
0

In addition to the 2 methods mentioned by @kororo, you can also try to solve it in the following way.

Since the PageCache uses requestPolicy to determine whether to return the page cache or not

Drupal\page_cache\StackMiddleware\PageCache::handle()

$this->requestPolicy->check($request) === RequestPolicyInterface::ALLOW

So, you can also solve this by implementing a RequestCheckPolicy, which can be found at

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.