Eu tenho esse bloco muito básico que apenas mostra o ID do nó atual.
<?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']);
}
}
Porém, uma vez armazenado em cache, o bloco permanece o mesmo, independentemente de qual nó eu visito. Como faço para armazenar em cache corretamente o resultado por ID do nó?
getCacheTags()
BlockBase, você só precisa adicionar uma tag que representa seu nó (nó: {nid}). Desculpe, eu estou com pressa agora, eu posso explicar melhor mais tarde,Respostas:
Este é um código de trabalho completo com comentários.
Eu testei; funciona.
Basta colocar o código em um arquivo chamado NodeCachedBlock.php na pasta do módulo, alterar o espaço para nome {module_name}, limpar o cache e usá-lo.
fonte
#cache
configurações na função de compilação e apenas adicionar as funções públicas?A maneira mais fácil de fazer isso é confiar no sistema de contexto de plug-in / bloco.
Veja minha resposta em Como faço para criar um bloco que puxa o conteúdo atual do nó?
Você só precisa colocar uma definição de contexto de nó na anotação de bloco, como segue:
E então use-o assim:
$this->getContextValue('node')
O bom disso é que o Drupal cuidará do cache para você. Automaticamente. Porque ele sabe que o contexto do nó padrão (e no que diz respeito apenas ao núcleo) é o nó atual. E como sabe de onde vem, o contexto e as tags de cache são adicionados automaticamente.
Através
\Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()
dosgetCacheTags()
métodos correspondentes , BlockBase / sua classe de bloco se estende disso e herda esses métodos.fonte
\Drupal::routeMatch()->getParameter('node')
com$this->getContextValue('node')
e você resolver todo o problema de cache com uma linha de código? Ótimo!Se você derivar a classe do seu plug-in de bloco
Drupal\Core\Block\BlockBase
, você terá dois métodos para definir tags e contextos de cache.getCacheTags()
getCacheContexts()
Por exemplo, o bloco do módulo Livro implementa esses métodos da seguinte maneira.
O bloco do módulo Fórum usa o seguinte código.
No seu caso, eu usaria o seguinte código.
Você também pode usar o método a seguir, para tornar o bloco inalcançável, mesmo que eu o evite. Pode ser útil em outros casos, talvez.
Lembre-se de adicionar
use Drupal\Core\Cache\Cache;
na parte superior do arquivo, se você for usar aCache
classe.fonte
BlockBase
classe como classe pai?Ao criar uma matriz de renderização, sempre anexe os metadados corretos:
Isso não é específico de um bloco e os métodos de dependência de cache de plug-ins de bloco getCacheTags (), getCacheContext () e getCacheMaxAge () não são um substituto. Eles devem ser usados apenas para metadados de cache adicionais, que não podem ser entregues através da matriz de renderização.
Veja a documentação:
https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays
Veja este exemplo de como o Drupal espera que uma matriz de renderização forneça os metadados de cache necessários ao otimizar o armazenamento em cache por meio de reserva automática e construção lenta Problema ao definir tags de cache específicas do usuário no bloco personalizado com o contexto do usuário
fonte
#markup
pode ser armazenado em cache da mesma forma que qualquer outro elemento de renderização. Nesse caso, não é a marcação, mas o bloco, que é armazenado em cache e aqui está o problema. Você não pode resolvê-lo com tags de cache, porque elas são invalidadas apenas se o nó for alterado no banco de dados.BlockBase
classe possui até os métodos necessários.return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];
funciona super bem para o cache por URL.O problema aqui é que os contextos de cache não são declarados no lugar certo na função de construção:
Se você chamar esse bloco em um não nó, a função de compilação retornará uma matriz vazia, para que não haja contexto de cache para esse bloco e esse comportamento será armazenado em cache por drupal: a exibição desse bloco não invalidará ou será renderizada corretamente.
A solução é apenas inicializar o $ build com os contextos de cache sempre:
fonte
Percebo que estou atrasado para esta conversa, mas o código abaixo funcionou para mim:
fonte
Você já tentou implementar hook_block_view_BASE_BLOCK_ID_alter?
função hook_block_view_BASE_BLOCK_ID_alter (matriz & $ build, \ Drupal \ Core \ Block \ BlockPluginInterface $ block) {$ build ['# cache'] ['max-age'] = 0; }
fonte