CacheableDependencyInterface
Pour faciliter la gestion des métadonnées de cache (tags de cache, contextes de cache et max-age), Drupal 8 dispose de l’interface CacheableDependencyInterface
.
Pourquoi ?
Imaginez devoir manuellement créer les tags de cache pour chaque objet et objet de configuration utilisés dans un tableau de rendu (ou dans d’autres calculs). Et sur un site multilingue, ajouter aussi manuellement les contextes de cache nécessaires (pour une entité traduite ou un remplacement de langue sur un objet configuration).
Et pas seulement les entités et la configuration, mais aussi les résultats d’accès, plugins de bloc, liens de menu, plugins de contexte, plugins de conditions, etc., car tous aboutissent à un rendu (type de calcul spécifique) que nous souhaitons mettre en cache.
Aux débuts du développement de Drupal 8, cela devait être fait manuellement, ce qui était source d’erreurs.
C’est pourquoi l’interface CacheableDependencyInterface
a été introduite. Comme son nom l’indique, les objets implémentant cette interface peuvent automatiquement devenir des dépendances cacheables.
Par exemple, en créant un tableau de rendu pour <p>Hi, %user, welcome to %site!</p>, vous dépendez à la fois de l’entité User du visiteur actuel et de la configuration system.site. Quand ce tableau est mis en cache, il inclut ces deux objets comme dépendances cacheables.
Cette interface peut être implémentée par n’importe quel objet valeur (représentant une unité logique de données). En consultant sa documentation API, on voit qu’elle est implémentée par de nombreux objets importants dans Drupal 8. En fait, la plupart des objets que vous utilisez en développement Drupal 8 l’implémentent.
Il existe deux cas extrêmes souvent rencontrés, pour lesquels Drupal propose des traits pratiques : le cas d’un objet immuable et donc cacheable indéfiniment (UnchangingCacheableDependencyTrait, qui retourne toujours max-age === permanent), et le cas d’un objet toujours calculé dynamiquement et donc jamais cacheable (UncacheableDependencyTrait, qui retourne toujours max-age === 0).
RefinableCacheableDependencyInterface
Mais CacheableDependencyInterface
ne gère que les métadonnées de cache intrinsèques à l’objet, dites « canoniques ». Parfois, un objet possède plusieurs variantes.
Les exemples les plus frappants sont les traductions d’entités (même entité avec identifiant identique, mais traduction différente) et les traductions de configuration (même configuration par nom, mais avec remplacement linguistique).
Dans ces cas, les métadonnées cacheables existantes dans l’objet original restent valides (exemple : node:5 comme tag cache). Mais – pour une entité – un contexte cache de langue du contenu est nécessaire ('languages:'. LanguageInterface::TYPE_CONTENT, voir Cache contexts) pour indiquer que cette entité varie selon la langue du contenu. De même, pour une configuration, un contexte cache de langue d’interface ('languages:'. LanguageInterface::TYPE_INTERFACE) est requis pour indiquer que cet objet configuration varie selon la langue de l’interface.
Un autre exemple hors traduction est un module « Pirate Day » qui applique un remplacement de configuration seulement ce jour-là, ajoutant des valeurs spécifiques. Ces objets configuration auront alors un contexte cache pirate_day.
Dans tous ces cas, il faut affiner les métadonnées cacheables pour refléter la variante chargée. C’est pourquoi RefinableCacheableDependencyInterface a été créé : il permet d’ajouter des tags cache, des contextes et modifier le max-age.
Pour faciliter son implémentation, Drupal fournit aussi un trait RefinableCacheableDependencyTrait.
Sur les entités et objets configuration
Toutes les entités Drupal 8 (core, contrib et custom) implémentent l’interface EntityInterface, qui étend à la fois CacheableDependencyInterface et RefinableCacheableDependencyInterface. De plus, toutes les entités du core étendent la classe abstraite Entity, et il est recommandé aux modules contrib/custom d’en faire autant. Ainsi, chaque entité que vous manipulez a automatiquement des tags cache cohérents (<type entité>:<ID>, ex. node:5 ou user:3) et les contextes cache nécessaires pour les traductions.
Tous les objets configuration du core étendent la classe abstraite ConfigBase, qui implémente aussi CacheableDependencyInterface et RefinableCacheableDependencyInterface. Chaque objet configuration a donc automatiquement des tags cache (ex. config:system.performance) et des contextes cache pour les remplacements de configuration (exemple unique dans le core étant la traduction).
Enfin, toutes les entités et objets configuration dans Drupal 8 ont automatiquement les contextes cache de langue contenu/interface grâce à EntityManager::getTranslationFromContext() et LanguageConfigFactoryOverride::getCacheableMetadata().
Utilisation d’objets cacheables comme dépendances
Le rendu est l’exemple le plus courant d’un tableau dépendant d’objets cacheables. Pour faciliter cela, Drupal fournit RendererInterface::addCacheableDependency($build, $dependency), où $build est un tableau de rendu dépendant de l’objet $dependency ; les métadonnées cacheables sont automatiquement « absorbées » par le tableau de rendu. Cela signifie que le tableau de rendu sera invalidé quand un tag cache invalide le cache, ou variera selon le contexte cache langue, et expirera automatiquement selon le max-age de la dépendance.
Voir un exemple complet de cacheabilité des tableaux de rendu.
Un autre bon exemple est la gestion des accès, où les objets AccessResult ont aussi la méthode addCacheableDependency(). Ici, on stocke les métadonnées cacheables dans l’objet résultat d’accès lui-même (contrairement au rendu où le tableau est distinct).