5

I'm using the Groups module (http://dgo.to/group) to set up groups on a SaaS project I'm working on. I've set up a domain field on the groups, allowing groups to have vanity domain. As such, groups can have custom front pages, which are shown at site route. The front page is set as a field on the Group entity. For example, group 1 may set their front page path as /page/1 and group 2 may set it as /page/2.

To show this front page, I'm using inbound URL processing, showing the different paths on the different domains. To get the different paths to cache independently, I've overridden Drupal\Core\Routing\RouteProviderRouteProvider::getRouteCollectionCacheId():

  /**
   * {@inheritdoc}
   */
  protected function getRouteCollectionCacheId(Request $request) {
    $cache_id = parent::getRouteCollectionCacheId($request);

    // Get the current domain.
    $domain = $this->currentPath->getRequestStack()->getCurrentRequest()->getHost();

    $cache_id .= ':' . $domain;

    return $cache_id;
  }

I've got this all working, however I ran into an issue in that when the path to the front page of a group is updated, the page content doesn't update until the router is rebuild.

I did find a solution, rebuilding the router in hook_entity_update() using \Drupal::service('router.builder')->rebuild(). This works, but it seems very heavy handed.

I tried finding a way to invalidate the cache tags for the route using the cache tags invalidator, but I could not figure out which cache tags to pass.

So my questions are:

  1. Is there a way to partially rebuild the router, rather than rebuilding the whole thing? Or...

  2. Is there a way to invalidate the cache for a route?

  • 1
    This sounds like the cacheable metadata from the content on the route isn't being set properly, or something is smashing it. – mpdonadio Nov 15 at 19:18
  • Routes don't have cache metadata, only path processing. Since you probably don't add a new controller for each group you don't need a new route either. So this should be possible in path processing, but without knowing the details it's impossible to tell. – 4k4 Nov 15 at 20:25
  • I've updated my question with additional information on how I'm handling the path processing now, as well as caching. Hopefully that can add some insight. Thanks for the comments guys. – Jaypan Nov 15 at 21:58
5

Instead of \Drupal::service('router.builder')->rebuild() you can invalidate route matches:

Cache::invalidateTags(['route_match']);

You don't need to rebuild the router table, because the static routes don't change. What you need to clear are route matches, which are calculated on the processed path and then stored for the unprocessed path. And this is the relation which changes in your case.

The router builder invalidates the route matches because after a route rebuild there might be routes missing which are still in route match collections.

To be more selective you can add a second cache tag for the frontpage in RouteProviderRouteProvider::getRouteCollectionForRequest and then only invalidate this tag.

Of course you also need to invalidate entries of the front page stored in page caches, but the front page has probably already a specific cache tag you can target.

  • That's awesome, exactly what I was looking for. I figured there must be some gentler method of achieving my goal, and that's it right there! Thanks 4k4. – Jaypan Nov 16 at 0:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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