0

I have a custom route defined with a custom access check. Apart from some more checks one of the rules for accessing the path is that a specific custom entity exists. The access check does the following:

  public function access(AccountInterface $account) {
    if ($entity_does_not_exist) {
      return AccessResult::forbidden()->addCacheTags(['my_unique_cache_tag']);
    }
  }

In my custom entity class I defined the postSave and postDelete methods to invalidate this tag every time an entity is created or deleted:

  public static function postDelete(EntityStorageInterface $storage, array $entities) {
    parent::postDelete($storage, $entities);
    foreach ($entities as $entity) {
      \Drupal::cache('render')->invalidate('my_unique_cache_tag');
    }
  }

  public function postSave(EntityStorageInterface $storage, $update = TRUE) {
    parent::postSave($storage, $update);

    if (!$update) {
      \Drupal::cache('render')->invalidate(ParliamentPeriodCCController::getCacheTag('my_unique_cache_tag');
    }
  }

My problem is that my custom route is used as a secondary tab in my_module.links.task.yml. What I found out so far is that the tabs are rendered in a block which really gets my unique cache tag (as I see in cache_render table - this is why I defined \Drupal::cache('render') above - \Drupal::cache() did not work neither) but it seems it never gets invalidated. When I enter a page where the secondary tab was not created because no entity exists it is still not shown when I create the entity afterwards. But when I delete the entry for the block from cache_render it is rendered correctly.

1

Two suggestions to improve caching:

  1. Even if you don't want to make a decision to allow or deny access you can return a neutral result to add cache metadata.

  2. The custom cache tag can be replaced by the list tag ENTITY_TYPE_list, which is invalidated automatically when entities are added or deleted.

The resulting code:

  public function access(AccountInterface $account) {
    if ($entity_does_not_exist) {
      return AccessResult::forbidden()->addCacheTags(['my_entity_list']);
    }
    return AccessResult::neutral()->addCacheTags(['my_entity_list']);
  }

postDelete() and postSave() are no longer necessary.

1
  • Thank you very much - this is cool!!! – Tobias Krause Nov 27 '20 at 10:44

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.