I struggle with getting a custom block cached correctly:
- we have a custom entity "Politician"
- For that entity we have several routes where we want to render a "politician header" with some basic information about the politician
- the politician header is a custom template which is rendered in a custom block
- the problem is: when caching is activated the block always shows the politician data from the first politician which was rendered.
Here is the code for the block plugin - to keep it simple I do not copy the method getPoliticianFromUrl() here:
/**
* Provides a block with the profile header for a politician. We do not render
* it on the public edit form path
*
* @Block(
* id = "aw_frontend_politician_header",
* admin_label = @Translation("Politician profile header"),
* category = "Abgeordnetenwatch"
* )
*/
class PoliticianProfileHeader extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
$politician = $this->getPoliticianFromUrl();
if ($politician == NULL) {
return [];
}
return array(
'#theme' => 'politician_header',
'#politician' => $politician,
'#cache' => [
'keys' => ['politician', $politician->id()]
]
);
}
public function getCacheContexts() {
$politician = $this->getPoliticianFromUrl();
if ($politician != NULL) {
return Cache::mergeContexts(parent::getCacheContexts(), $politician->getCacheContexts());
}
return parent::getCacheContexts();
}
public function getCacheTags() {
$politician = $this->getPoliticianFromUrl();
if ($politician != NULL) {
return Cache::mergeTags(parent::getCacheTags(), $politician->getCacheTags());
}
return parent::getCacheTags();
}
}
Then I render the politician header - again I just put in interesting parts:
function template_preprocess_politician_header(&$variables) {
/** @var \Drupal\pw_basic\Entity\Politician $politician */
$politician = $variables['politician'];
/** @var \Drupal\Core\Render\Renderer $renderer */
$renderer = \Drupal::service('renderer');
$renderer->addCacheableDependency($variables, $politician);
$variables["#cache"]["contexts"][] = 'user.roles';
$variables['#cache']['keys'] = ['politician_header', $politician->id()];
}
I thought when I define cache keys this ensures that different versions of the render array are cached. This does not happen - not for the custom politician header template (for which I do not find any cached data in cache_render tanle - is this just cached with Twig caching?) and not for the block.
My idea was to create a custom cache context based on my Politician entity but as far as I understand cache contexts they depend on more global circumstances such as the active theme, the current user and things like that. I hoped the Entity API would generate such a context in a magical way so I tried $politician->getCacheContexts() but nothing.
What do I miss?
url.path
.