Hooks de preprocesamiento de Drupal: Por qué el contexto de caché `url.path` es importante
Cuando modificas la salida en un hook de preprocesamiento basándote en la ruta o el camino actual, también necesitas indicarle a la caché de renderizado de Drupal qué elementos varían en esa salida. De lo contrario, el primer resultado renderizado podría ser almacenado en caché y reutilizado en todas partes.
La situación
Considera un preprocesamiento personalizado para el bloque de marca que muestra un nombre de sitio diferente en los nodos del blog:
getRouteName();
// Comprueba si estamos en una página de blog
if ($route_name === 'entity.node.canonical') {
$node = $route_match->getParameter('node');
if ($node && $node->bundle() === 'blog') {
// En las páginas de blog, modifica el nombre del sitio para mostrar "HELLO WORLD"
$variables['site_name'] = 'HELLO WORLD';
}
}
// En la página de inicio y otras páginas, mantén el nombre del sitio original
}
Sin la línea que añade el contexto de caché ($variables['#cache']['contexts'][] = 'url.path';
), Drupal podría almacenar en caché la primera versión que renderiza (por ejemplo, la versión del blog) y reutilizarla en todas las páginas. Por eso viste el mismo texto en todas partes.
Por qué sucede esto
- Caché de renderizado: Drupal almacena en caché los arrays de renderizado para mejorar el rendimiento.
- Salida variable: Si la salida cambia según la ruta o el camino, la clave de caché debe incluir esa variabilidad.
- Contextos de caché: Añadir
url.path
(o un contexto más específico) le indica a Drupal que mantenga variaciones de caché separadas por cada ruta.
¿Es esto cierto para todos los hooks de preprocesamiento?
Sí, la regla se aplica a cualquier salida renderizable que varíe. Los hooks de preprocesamiento a menudo modifican arrays de renderizado o variables de plantilla que forman parte de la caché de renderizado. Si tu lógica varía según:
- Ruta o camino → añade
url.path
oroute
- Usuario actual → añade
user
(o contextos más granulares comouser.roles
) - Idioma → añade
languages:language_interface
- Tema o punto de interrupción → añade
theme
,responsive_image_style
, etc.
El preprocesamiento en sí no es especial; lo que importa es si el array de renderizado resultante debe ser almacenado en caché de manera diferente entre solicitudes. Si la salida varía, declara los contextos de caché correctos.
Elegir el contexto de caché adecuado
- Prefiere la precisión: Si dependes del nodo canónico, considera
route
en lugar deurl.path
para evitar fragmentación innecesaria de la caché (por ejemplo, cadenas de consulta o alias). - Bloques basados en entidades: Cuando dependes de una entidad (como un nodo), añade dependencias de caché para que las ediciones se purguen correctamente:
$variables['#cache']['tags'][] = 'node:' . $node->id();
- Max-age: Mantén
max-age
en el valor predeterminado (permanente) a menos que la salida realmente expire.
Alternativa más segura: Derivar del array de renderizado
En lugar de usar globales, también puedes adjuntar metadatos de caché usando CacheableMetadata
para fusionar contextos y etiquetas de forma segura:
addCacheContexts(['route']);
$route_match = \Drupal::routeMatch();
if ($route_match->getRouteName() === 'entity.node.canonical') {
$node = $route_match->getParameter('node');
if ($node && $node->bundle() === 'blog') {
$variables['site_name'] = 'HELLO WORLD';
$cacheable->addCacheTags(['node:' . $node->id()]);
}
}
$cacheable->applyTo($variables);
}
Lista de verificación
- ¿La salida cambia según la ruta o el camino? Añade
url.path
oroute
. - ¿Depende de una entidad? Añade etiquetas de caché para esa entidad.
- ¿Varía según el usuario o el idioma? Añade los contextos correspondientes.
- Mantén
max-age
alto; confía en las etiquetas para la invalidación.
Conclusión
Sí, si tu lógica de preprocesamiento cambia la salida por página, debes declarar los contextos de caché correspondientes. De lo contrario, Drupal servirá felizmente el mismo resultado almacenado en caché en todas partes.