1

I'm working on an application where authenticated user data mostly comes from an API. Performance is significantly better since I'm using the API cache. Before, to be sure to have up-to-date information, I used '#cache' => ['max-age' => 0,] but it's really not ideal.

I have a question, however, about the custom block cache for authenticated users.

If I add user context and tag it works fine for authenticated users.

return [
            '#theme' => 'lorem',
            '#datas' => $datas,
            '#cache' => [
                'contexts' => ['user'],
                'tags' => ['user:' . \Drupal::currentUser()->id(), 'lorem_custom_block:' . \Drupal::currentUser()->id(), 'lorem_custom_block_user:' . \Drupal::currentUser()->id()]
            ],
        ];

But one of my clients to test the application uses his Drupal account (therefore always the same Drupal user id) and changes a value of a custom field in his profile (an external id which is used to retrieve information with the API). In this case, I use a hook_user_presave and invalidate the custom block cache like this :

Cache::invalidateTags(['lorem_custom_block_user:' . $user_id]);

In this case, it does not work. The information displayed in the block is not up to date. I have to remove the context user on the block and it works.

return [
            '#theme' => 'lorem',
            '#datas' => $datas,
            '#cache' => [
                'tags' => ['user:' . \Drupal::currentUser()->id(), 'lorem_custom_block:' . \Drupal::currentUser()->id(), 'lorem_custom_block_user:' . \Drupal::currentUser()->id()]
            ],
        ];

Is this the normal behavior? it's as if there is a conflict between the context and the tag.

I thought invalidating the tag would be enough.

Maybe it doesn't make sense to use a context in my case. Can you give me your opinion?

2
  • 2
    The system already knows how to make a render array depend on an entity for cache, you don't need to create tags - see drupal.org/docs/drupal-apis/render-api/… for a good example
    – Clive
    May 18, 2023 at 12:54
  • You're right. I redid the tests and I don't need to create tags. Thanks for the link, very interesting. May 18, 2023 at 21:11

1 Answer 1

2

Blocks are plugins in Drupal, and plugins can be context aware. The key is that you add the context within the annotation:

/**
 * @Block(
 *  id = "mymodule_block1",
 *  label = "Block 1",
 *  admin_label = @Translation("Block 1"),
 *  context_definitions = {
 *    "current_user" = @ContextDefinition("entity:user"),
 *  }
 * )
 */

You can then retrieve the context in your code for the block.

$user = $this->getContextValue('current_user');

This should vary your block per user - and invalidate itself when the user changes. You can read more about "context aware plugins" where it explains how everything works behind the scenes, create your own, etc.

2
  • If I add the context within the annotation, I don't need to add to the render array 'contexts' => ['user']? May 18, 2023 at 21:19
  • @SébastienGicquel I would comment out all of your custom cache code, and then just use the annotation. In theory, none of it should be needed once you tie the entity and the plugin together. May 19, 2023 at 13:16

Your Answer

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

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