Cache API

Drupal 8 est arrivé avec plusieurs améliorations en performance, et qui dit performance dit cache.

Dans cet article on va voir en détail les types de cache fournit par Drupal, et comment les utiliser dans nos modules personnalisés pour garantir une performance optimale aux utilisateurs.

Avant de pencher dans les variétés du cache backend, je tiens à préciser que Drupal 8 fournit des modules installés par défaut :

  • Dynamic Page Cache et Internal Page Cache: ne nécessitent aucune configuration, il gére respectivement le cache pour les utilisateurs authentifiés et anonymes.
  • BigPipe : il s'agit d'une technique qui est connue dans le web introduite par Facebook, et qui permet de gagner en performance. L'idée du module est d'envoyer plusieurs morceaux d'une page les uns après les autres, afin de permettre au navigateur de charger les morceaux qui sont prêts pour l'affichage. Ci-dessous une démonstration du fonctionnement de BigPipe

    Alt Text

L'API cache de Drupal utilise plusieurs bins qui sont liés à des tables de cache dans la base de donnée (commencent par le préfixe cache_), il faut alors commencer par demander un cache bin donné pour pouvoir interagir avec le cache API.

$render_cache = \Drupal::cache('render');

La variable $render_cache dans le code snippet en-dessus présente un objet du cache bin render, néanmoins le cache dans cet exemple est appelé de manière statique, cependant si on travaille avec des classes qui est bien le cas dans les modules customs Drupal, il est recommandé d'utiliser l'injection des dépendances en injectant le service du cache (cache.render dans notre exemple).

L'API cache (backend) est basée sur trois principes fondamentaux qu'il faut bien comprendre pour pouvoir les utiliser de manière efficace dans le développement des modules personnalisés :

  • Les caches tags
  • Les caches context
  • Le cache par durée (max-age)

Caches tags

Le principe des caches tags est simple, ces derniers donnent la possibilité de tager des contenus, éléments du render avec des tags différents et précis, ces tags vont être invalidés par la suite après une action bien définie. Exemple : Imaginant un simple contenu de type Article qui va être affiché dans sa propre page de détail, page de listing ou autres pages. Si on ne gère pas le cache dans le render array qui permet l'affichage des contenus, ces derniers vont être cachés dans le render array et on va finir par afficher du faux contenus aux utilisateurs. On peut utiliser le tag node_list dans tous les render arrays qui affichent les contenus pour s'assurer qu'à chaque modification d'un contenu, tous les renders arrays tagés par le même tag (node_list) vont être invalidés afin de reconstruire le nouveau cache dans les render arrays et afficher le nouveau contenu.

  • Par convention, les cache tags prennent le format <entity type ID>:<entity ID> ou config:<configuration name>, et si l'objet accepte qu'une seule instance on peut utiliser objet comme cache tag.
  • Les caches tags sont tout simplement des chaines de caractères (ex: node_list, config:system.performance)
  • On peut passer plusieurs cache tags dans un render array.
  • L'ordre des caches tags dans un render array n'est pas pris en considération par Drupal.

( ! ) Remarque

Il faut noter que les caches tags sur Drupal 8 ne supportent pas les tags des entités par bundle, ce problème sera résolu dans les prochaines versions de Drupal. En revanche, le module Handy Cache Tags gère cette contrainte de manière efficace et qui permet d'utiliser des tags par bundle (ex: handy_cache_tags:node:article).


Caches contexts

Comme son nom l'indique, un cache context se base sur les contextes définis par Drupal, en d'autres termes les caches contexts permettent de varier le cache dans un render array par chemin, utilisateur, langue, theme ou autres contextes.

  • On peut ajouter plusieurs caches contexts dans un render array
  • L'ordre des caches contexts dans un render array n'est pas pris en considération par Drupal.
  • Par nature il y a une hiérarchie prédéfinie de contexts sur Drupal, par exemple lorsqu'on varie le cache par utilisateur, ça sert à rien de le varier par permission vu que l'utilisateur possède un groupe de permissions par défaut.

Caches Max Age

Le Cache Max-Age permet de cacher un render array sur une durée bien définie. Il prend le format d'un nombre positif en secondes (0, 60, 100). Exemple d'utilisation du cache dans les render arrays :

	//Case of render array
    $build['#cache']['max-age'] = 0;
	
	//Case of plugin bloc (OOP way)
	public function getCacheMaxAge()
	{
		return 0;
	}

Comme on l'avait vu au début de cet article, Drupal dispose des modules Internal Dynamic Page Cache (gère le cache pour les utilisateurs authentifiés) et Internal Page Cache (gère le cache pour les utilisateurs anonymes), et bien ce dernier ne reconnait pas l'existence du cache max age, en d'autres termes si on rajoute un cache max-age dans un render array, ce dernier va être caché pour les utilisateurs anonymes à cause d'Internal Page Cache qui ne tient pas compte du max-age. Il est déconseillé d'utiliser le cache max-age dans vos développements personnalisés. D'ailleurs le cache max-age n'est pas utilisé dans le code source (Core) de Drupal.