Tengo este bloque muy básico que solo muestra la ID del nodo actual.
<?php
/**
* @file
* Contains \Drupal\mymodule\Plugin\Block\ExampleEmptyBlock.
*/
namespace Drupal\mymodule\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Cache\Cache;
/**
* @Block(
* id = "example_empty",
* admin_label = @Translation("Example: empty block")
* )
*/
class ExampleEmptyBlock extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
$node = \Drupal::routeMatch()->getParameter('node');
$build = array();
if ($node) {
$config = \Drupal::config('system.site');
$build = array(
'#type' => 'markup',
'#markup' => '<p>' . $node->id() . '<p>',
'#cache' => array(
'tags' => $this->getCacheTags(),
'contexts' => $this->getCacheContexts(),
),
);
}
return $build;
}
/**
* {@inheritdoc}
*/
public function getCacheTags() {
$node = \Drupal::routeMatch()->getParameter('node');
return Cache::mergeTags(parent::getCacheTags(), ["node:{$node->id()}"]);
}
/**
* {@inheritdoc}
*/
public function getCacheContexts() {
return Cache::mergeContexts(parent::getCacheContexts(), ['user.node_grants:view']);
}
}
Pero una vez en caché, el bloque permanece igual, independientemente del nodo que visite. ¿Cómo guardo correctamente en caché el resultado por ID de nodo?
getCacheTags()
desde BlockBase, solo necesita agregar una etiqueta que represente su nodo (nodo: {nid}). Lo siento, tengo prisa ahora, puedo explicarlo mejor más tarde,Respuestas:
Este es un código de trabajo completo con comentarios.
Lo probé; funciona.
Simplemente coloque el código en un archivo llamado NodeCachedBlock.php en la carpeta de su módulo, cambie su espacio de nombres {module_name}, borre el caché y úselo.
fuente
#cache
configuración de la función de compilación y simplemente agregar las funciones públicas?La forma más fácil de hacerlo es confiar en el sistema de contexto de complemento / bloque.
Vea mi respuesta para ¿Cómo hago un bloque que extrae el contenido del nodo actual?
Solo tiene que poner una definición de contexto de nodo en su anotación de bloque como esta:
Y luego úsalo así:
$this->getContextValue('node')
Lo bueno de esto es que Drupal se encargará del almacenamiento en caché por usted. Automáticamente. Porque sabe que el contexto de nodo predeterminado (y en lo que respecta al núcleo únicamente) es el nodo actual. Y eso sabe de dónde viene, por lo que el contexto de caché y las etiquetas de caché se agregan automáticamente.
Mediante
\Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()
y losgetCacheTags()
métodos correspondientes , BlockBase / su clase de bloque se extiende a partir de eso y hereda esos métodos.fuente
\Drupal::routeMatch()->getParameter('node')
con$this->getContextValue('node')
y resuelve todo el problema de almacenamiento en caché con una línea de código? ¡Excelente!Si deriva la clase de su complemento de bloque
Drupal\Core\Block\BlockBase
, tendrá dos métodos para establecer etiquetas y contextos de caché.getCacheTags()
getCacheContexts()
Por ejemplo, el bloque del módulo Libro implementa esos métodos de la siguiente manera.
El bloque del módulo Forum utiliza el siguiente código.
En su caso, usaría el siguiente código.
También podría usar el siguiente método para hacer que el bloque no se pueda almacenar en caché (incluso si lo evitaría). Podría ser útil en otros casos, tal vez.
Recuerda agregar
use Drupal\Core\Cache\Cache;
en la parte superior del archivo, si va a usar laCache
clase.fuente
BlockBase
clase como clase principal?Cuando crea una matriz de renderizado, siempre adjunte los metadatos correctos:
Esto no es específico del bloque y los métodos de dependencia de caché de complementos de bloque getCacheTags (), getCacheContext () y getCacheMaxAge () no son un reemplazo. Solo deben usarse para metadatos de caché adicionales, que no se pueden entregar a través de la matriz de representación.
Ver la documentación:
https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays
Vea este ejemplo de cómo Drupal espera que una matriz de renderización proporcione los metadatos de caché necesarios al optimizar el almacenamiento en caché mediante la colocación automática de marcadores de posición y la creación diferida. Problema al configurar etiquetas de caché específicas del usuario en un bloque personalizado con el contexto del usuario
fuente
#markup
se puede almacenar en caché igual que cualquier otro elemento de representación. En este caso, no es el marcado, sino el bloque, que se almacena en caché y aquí está el problema. No puede resolverlo con etiquetas de caché, porque solo se invalidan si el nodo se cambia en la base de datos.BlockBase
clase tiene incluso los métodos necesarios.return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];
funciona muy bien para el almacenamiento en caché por URL.El problema aquí es que los contextos de caché no se declaran en el lugar correcto en la función de compilación:
Si llama a ese bloque en un no nodo, la función de construcción devuelve una matriz vacía, por lo que no hay contexto de caché para este bloque y ese comportamiento será almacenado en caché por drupal: la visualización de este bloque no se invalidará o representará correctamente.
La solución es simplemente inicializar $ build con los contextos de caché cada vez:
fuente
Me doy cuenta de que llego tarde a esta conversación, pero el siguiente código funcionó para mí:
fuente
¿Has intentado implementar hook_block_view_BASE_BLOCK_ID_alter?
función hook_block_view_BASE_BLOCK_ID_alter (array & $ build, \ Drupal \ Core \ Block \ BlockPluginInterface $ block) {$ build ['# cache'] ['max-age'] = 0; }
fuente