J'ai ce bloc très basique qui montre juste l'ID du nœud actuel.
<?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']);
}
}
Mais une fois mis en cache, le bloc reste le même, quel que soit le nœud que je visite. Comment mettre correctement en cache le résultat par ID de nœud?
getCacheTags()
depuis BlockBase, il vous suffit d'ajouter une balise qui représente votre nœud (nœud: {nid}). Désolé, je suis pressé maintenant, je peux mieux expliquer plus tard,Réponses:
Il s'agit d'un code de travail complet avec des commentaires.
Je l'ai testé; Ça marche.
Placez simplement le code dans un fichier nommé NodeCachedBlock.php dans le dossier de votre module, changez son espace de nom {module_name}, videz le cache et utilisez-le.
la source
#cache
paramètres de la fonction de construction et d'ajouter simplement les fonctions publiques?La façon de loin la plus simple de le faire est de s'appuyer sur le système de contexte plugin / bloc.
Voir ma réponse pour Comment créer un bloc qui extrait le contenu du nœud actuel?
Il vous suffit de mettre une définition de contexte de nœud dans votre annotation de bloc comme ceci:
Et puis utilisez-le comme ceci:
$this->getContextValue('node')
La bonne chose à ce sujet est que Drupal se chargera ensuite de la mise en cache pour vous. Automatiquement. Parce qu'il sait que le contexte de nœud par défaut (et pour autant que le cœur ne va que) est le nœud actuel. Et qui sait d'où il vient, le contexte de cache et les balises de cache sont ajoutés automatiquement.
Par le biais
\Drupal\Core\Plugin\ContextAwarePluginBase::getCacheContexts()
et lesgetCacheTags()
méthodes correspondantes , BlockBase / votre classe de bloc s'étend de cela et hérite de ces méthodes.la source
\Drupal::routeMatch()->getParameter('node')
par$this->getContextValue('node')
et vous résolvez tout le problème de mise en cache avec une seule ligne de code? Génial!Si vous dérivez la classe de votre plugin de bloc
Drupal\Core\Block\BlockBase
, vous aurez deux méthodes pour définir les balises de cache et les contextes.getCacheTags()
getCacheContexts()
Par exemple, le bloc de module Book implémente ces méthodes comme suit.
Le bloc de module Forum utilise le code suivant.
Dans votre cas, j'utiliserais le code suivant.
Vous pouvez également utiliser la méthode suivante, pour rendre le bloc impossible à mettre en cache (même si je l'évite). Cela pourrait être utile dans d'autres cas, peut-être.
N'oubliez pas d'ajouter
use Drupal\Core\Cache\Cache;
en haut du fichier, si vous allez utiliser laCache
classe.la source
BlockBase
classe comme classe parente?Lorsque vous créez un tableau de rendu, attachez toujours les métadonnées correctes:
Ce n'est pas spécifique au bloc et les méthodes de dépendance du cache des plugins de bloc getCacheTags (), getCacheContext () et getCacheMaxAge () ne sont pas un remplacement. Ils ne doivent être utilisés que pour des métadonnées de cache supplémentaires, qui ne peuvent pas être fournies via le tableau de rendu.
Consultez la documentation:
https://www.drupal.org/docs/8/api/render-api/cacheability-of-render-arrays
Voir cet exemple comment Drupal s'attend à ce qu'un tableau de rendu fournisse les métadonnées de cache nécessaires lors de l'optimisation de la mise en cache via la mise en place automatique et la construction paresseuse Problème de définition de balises de cache spécifiques à l'utilisateur sur un bloc personnalisé avec un contexte utilisateur
la source
#markup
peut être mis en cache comme n'importe quel autre élément de rendu. Dans ce cas, ce n'est pas le balisage, mais le bloc, qui est mis en cache et voici le problème. Vous ne pouvez pas le résoudre avec des balises de cache, car elles ne sont invalidées que si le nœud est modifié dans la base de données.BlockBase
classe a même les méthodes nécessaires.return [ '#markup' => render($output), '#cache' => [ 'contexts' => ['url'] ] ];
fonctionne très bien pour la mise en cache par URL.Le problème ici est que les contextes de cache ne sont pas déclarés au bon endroit dans la fonction de génération:
Si vous appelez ce bloc sur un noeud non, la fonction de construction retourne un tableau vide, il n'y a donc pas de contexte de cache pour ce bloc et ce comportement sera mis en cache par drupal: l'affichage de ce bloc ne sera pas correctement invalidé ou restitué.
La solution consiste simplement à initialiser la construction de $ avec les contextes de cache à chaque fois:
la source
Je me rends compte que je suis en retard à cette conversation, mais le code ci-dessous a fonctionné pour moi:
la source
Avez-vous essayé d'implémenter hook_block_view_BASE_BLOCK_ID_alter?
fonction hook_block_view_BASE_BLOCK_ID_alter (array & $ build, \ Drupal \ Core \ Block \ BlockPluginInterface $ block) {$ build ['# cache'] ['max-age'] = 0; }
la source