Score:1

How to invalidate custom block which use Cache Tags and Cache contexts for authenticated user?

pe flag

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?

cn flag
The system already knows how to make a render array depend on an entity for cache, you don't need to create tags - see https://www.drupal.org/docs/drupal-apis/render-api/cacheability-of-render-arrays#concrete-example for a good example
pe flag
You're right. I redid the tests and I don't need to create tags. Thanks for the link, very interesting.
Score:2
cn flag

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.

pe flag
If I add the context within the annotation, I don't need to add to the render array `'contexts' => ['user']`?
cn flag
@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.
mangohost

Post an answer

Most people don’t grasp that asking a lot of questions unlocks learning and improves interpersonal bonding. In Alison’s studies, for example, though people could accurately recall how many questions had been asked in their conversations, they didn’t intuit the link between questions and liking. Across four studies, in which participants were engaged in conversations themselves or read transcripts of others’ conversations, people tended not to realize that question asking would influence—or had influenced—the level of amity between the conversationalists.