Plongée dans l'Entité API Drupal

Illustration des entités par Elie :)
Nous prenons le temps d'évoquer dans ce post la documentation de @berdir sur l'entité API ainsi que les points principaux à retenir de cette publication.

@berdir a écrit une documentation très riche et synthétique de l'entité API de Drupal. La documentation passe en revue les principaux aspects de la célèbre "API entity", du CRUD, en passant par la manipulation des champs d'entités, les révisions, les traductions, les modèles d'entités en PHP et Twig, jusqu'au fonctionnement interne des entités de contenu. 

https://berdir.github.io/entities-explained/#/5/11

Nous récapitulons ci-après les points notables à l'attention des développeurs qui utilisent déjà l’entité API. Ils concernent : 

  • Les noms des propriétés et méthodes génériques ;
  • Les méthodes sur les entités de contenus ;
  • Utilisation de la fonction loadByProperties()
  • Les révisions ;
  • La traduction des entités ; 
  • Le bundle class.

Noms des propriétés et méthodes génériques

$node->get('title')->value = $node->get('title')->get('value')->getValue()

$node->get('title')->getValue()

-------------------------

// ->entity on entity reference fields is the target.
$user->get('roles')->entity == $role;
// ->getEntity() is the host/parent entity.
$user->get('roles')->getEntity() == $user;

Méthodes magiques sur les entités de contenu

// __get()/__set() support non-fields, get() does not:
$node->foo = 'bar';
// throws an exception:
$node->set('foo', 'bar');
// Various "API"s in rely on this behavior at the moment:
$entity->original, $entity->view, $entity->_referringItem;

Pour aller plus loin : https://www.drupal.org/project/drupal/issues/3281720

Utilisation de la fonction loadByProperties()

Pour charger les entités, il faut absolument éviter l’utilisation de la fonction loadByProperties() qui, dans sa déclaration, ne fait pas de contrôle d’accès à l’entité. 

Matt Glaman propose de mentionner plus clairement, dans la documentation officielle de Drupal, quand et comment utiliser la fonction loadByProperties(). Cette information serait notamment très utile aux développeurs qui entreprennent la mise à niveau de Drupal 7 vers Drupal 8/9.
https://twitter.com/nmdmatt/status/1514002594083098629 et https://mglaman.dev/blog/avoid-using-loadbyproperties-load-entities

Quoi qu'il en soit, à partir de Drupal 9.2.X, il est préférable d'utiliser les Entity Queries (\Drupal::entityQuery(ENTITY_TYPE)) qui permettent de spécifier le contrôle d’accès (https://www.drupal.org/node/3201242).

Les révisions

La documentation de @berdir précise que : 

  • Les contenus des entités peuvent être révisables ;
  • Une entité a toujours une révision par défaut ;
  • Une entité peut être enregistrée comme une nouvelle révision ;
  • Une nouvelle révision peut être la nouvelle révision par défaut ou non, auquel cas elle devient une révision en attente (brouillon).
// Get the current revision ID.
$entity->getRevisionId();
// Is/was the default revision or is latest revision.
$entity->isDefaultRevision();
$entity->wasDefaultRevision();
$entity->isLatestRevision();
// Set a new non-default revision.
$entity->setNewRevision(TRUE);
$entity->isDefaultRevision(FALSE);
$entity->save();

Dans le back office de Drupal, la création de nouvelles révisions à chaque sauvegarde est forcée. Dans le code, par défaut, sauf si on change le paramètre Sync, le comportement est identitque : 
$entity-> setSyncing(TRUE), dans ce cas, on sauvegarde la révision actuelle (en cours de modification).

Un sujet intéressant à creuser serait de permettre la création de “Workspaces”. Cette interface pourrait permettre de consulter le site complet dans un état où les entités sont dans une version spécifique de révisions. Il serait alors judicieux de permettre la publication de toutes ces dernières révisions en même temps.

A noter - Meilleure méthode pour récupérer une traduction en retombant sur le contenu par défaut si cette première n’est pas disponible :

$er = \Drupal::service('entity.repository'); 
$translation = $er->getTranslationFromContext($entity, 'de');

Les révisions et leurs traductions

La documentation de @berdir précise également que : 

  • Chaque révision contient toutes les traductions existantes et leurs valeurs ;
  • Les révisions suivent les langues qui ont été modifiées dans celles-ci ;
  • Pour fusionner les modifications, une seule traduction peut être modifiée dans une révision donnée ;
  • Les nouvelles révisions en attente des traductions sont basées sur la révision par défaut de la langue publiée.

Le bundle class

Le tutoriel de @berdir montre que :

  • Le bundle class permet de définir une classe unique par bundle d'entités à utiliser à la place de la classe d'entité par défaut ;
  • Le bundle class est utile pour distribuer la logique business, y compris dans les modèles twigs ;
  • Le bundle class doit s'étendre à partir de la classe d'entité ;
  • Drush 11 dispose d'un générateur pour créer la structure de base et le hook requis.

Pour aller plus loin : https://www.drupal.org/node/3191609

Pour finir, puisque nous sommes tous dans le même bateau, voici les liens principaux sur les ressources disponibles avec l'entité API : 
https://www.drupal.org/docs/drupal-apis/entity-api
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Entity!entity.api.php/group/entity_api