Aller au contenu principal

Quickie 03 : Déménager la logique métier d'un preprocess vers une classe d'entité

  • 08 Avril 2024
  • 5 min
  • Développement
Développement
Drupal
Entity
Templates

J'ai remarqué que sur la plupart des projets réalisés, j'utilise énormément les preprocess de rendu d'entité afin ajouter des données pour m'en servir dans les templates.
Depuis quelques temps je passe par la redéfinition de la classe sur une entité précise afin d'avoir un maximum de code métier dans ces dernières.
Voici ma méthode pour transférer des données ou conditions complexes aux templates d'entité.  

Image d'un petit robot cute transportant des cartons.
Quickie

Ma méthode depuis Drupal 7


Certaines fois on peut avoir besoin d'ajouter de la data ou des conditions dans les templates d'entité. Jusqu'à récemment je mettais soit directement la condition dans le template si elle était simple, soit je déclarai un preprocess afin d'ajouter une variable contenant le résultat de la condition qui sera ensuite transmise au twig.
Voici un exemple :

/**
 * Implements hook_preprocess_HOOK().
 */
function mymodule_preprocess_node__article(&$variables) {
  $variables['new_article'] = (time() - $variables['node']->getCreatedTime()) < 604800; // Article créé il y a moins de 7 jours
}

Ceci me permettais directement depuis le template node--article.html.twig d'avoir une condition simple en lecture.

{% if new_article %}
   <span class="article__is_new">{{ 'Nouveau'|t }} </span>
{% endif %}

Nouvelle façon de faire

Pour continuer d'enlever un maximum de code procédurale des interminables fichiers .modules, je déporte maintenant ces règles dans des classes d'entité. Pas touche aux fichiers de Drupal alors on utilise le système d'altération qui est possible grâce à ..... un hook.?‍?
On échappe pas au hook mais il ne prendra que quelques lignes et tout le code métier, qui peut être composé de plusieurs dizaines ou centaines de lignes, sera mis dans une classe.
Par défaut chaque entité possède sa classe de "gestion". C'est notamment à cet endroit que j'interviens pour fournir une classe alternative qui étendra la classe d'origine. 
L'exemple est fait sur un nœud donc il faut changer la classe du nœud de type article via le hook HOOK_entity_bundle_info_alter()


/**
 * @hook HOOK_entity_bundle_info_alter()
 */
function mymodule_entity_bundle_info_alter(array &$bundles): void {
  if (isset($bundles['node']['article'])) {
    $bundles['node']['article']['class'] = Drupal\mymodule\Entity\Article::class;
  }
}

On définie une nouvelle classe Article uniquement pour les nœuds de type article.
Il faut maintenant créer cette classe qui doit se trouver dans src/Entity.

Fichier modules/custom/mymodule/src/Entity/Article.php :

namespace Drupal\mymodule\Entity;
use Drupal\node\Entity\Node;
class Article extends Node {
  const TIME_TO_CONSIDER_NEW = 60*60*24*7; // 7jours
  
  /**
   * Renvoie true si l'article date d'il y a moins de 7 jours
   *
   * @return bool
   */
  public function isNewArticle(): bool{
    return (time() - $this->getCreatedTime()) < self::TIME_TO_CONSIDER_NEW;
  }
 
}

Comme la classe contient le code métier, il est maintenant possible d'appeler cette méthode à chaque fois qu'un nœud de type Article est chargé. Notamment depuis le fichier twig node--article.html.twig

{% if node.isNewArticle() %}
     <span class="article__is_new">{{ 'Nouveau'|t }} </span>
{% endif %}

 

Petit message d'avertissement !
 

Faites attention aux noms des méthodes que vous allez créer. Il existe une liste avec tous les noms de méthode ou de préfixe autorisés depuis un appel dans un template Twig. Si vous préfixez vos noms de méthodes avec "get", "has" ou "is" il n'y aura pas de problèmes.
Si vous n'êtes pas dans ce cas alors vous devrez ajouter votre préfixe ou nom de méthode à la liste blanche via le code ci-dessous.
 

Dans le fichier settings.php ou settings.local.php

$settings['twig_sandbox_allowed_methods'][] = 'monNomDeMéthode';
$settings['twig_sandbox_allowed_prefixes'][] = 'monPréfixe';