Introduction
Dans un environnement de gestion de contenu dynamique, il est souvent nécessaire de structurer les données pour garantir une organisation cohérente et automatisée. Cet article détaille la mise en œuvre d’un module personnalisé sous Drupal, conçu pour associer automatiquement chaque contenu créé par un utilisateur à son entreprise via un champ d’identifiant unique. Cette approche assure une attribution précise et transparente de la relation entre les utilisateurs et leurs contenus, facilitant ainsi l’accès et le suivi des données. Ce guide vous conduira, étape par étape, à travers les configurations et les implémentations nécessaires pour établir cette fonctionnalité de manière optimale.
Prérequis
Avant de procéder à la configuration, veuillez vous assurer de satisfaire aux conditions suivantes :
- Disposer d’un environnement Drupal fonctionnel. Pour des instructions détaillées, veuillez consulter Comment installer Drupal dans un conteneur Docker.
- Être familier avec l’authentification OAuth 2.0 et avoir le module Simple OAuth activé sur votre site Drupal. Voir Authentification OAuth 2.0 pour sécuriser JSON avec les modules Consumers et Simple OAuth.
- Maîtriser la création d’un module personnalisé en respectant les bonnes pratiques. Pour plus de détails, reportez-vous à la section Créer un module personnalisé en appliquant les principes SOLID.
Use Case
Dans ce cas d’utilisation, nous allons créer un module personnalisé appelé custom_entity_associate
qui permet d’associer automatiquement chaque contenu d’un type spécifique, tel que Document
, à l’entreprise de l’utilisateur authentifié. L’objectif est de garantir que, lorsqu’un utilisateur, ici “John” de la société “Alpha”, crée un contenu de type Document
(par exemple, “document0”), l’identifiant de son entreprise soit automatiquement renseigné dans le champ field_accountid
du contenu. Cela assure une liaison cohérente et automatisée entre chaque contenu et l’entreprise de l’utilisateur, simplifiant ainsi la gestion des données et leur suivi par entreprise.
Création d’un Content Type
Nous allons créer un type de contenu dédié, nommé Document
, auquel nous ajouterons un champ de référence pour associer chaque contenu à l’entreprise de l’utilisateur qui le crée.
- Créer le type de contenu : Dans l’interface d’administration de Drupal, rendez-vous à l’adresse
/admin/structure/types
et cliquez sur Add content type. Donnez au type de contenu le nomDocument
et, si nécessaire, ajoutez une description. Par défaut, un champ Title est inclus et défini comme requis. - Ajouter un champ de référence d’entité : Une fois le type de contenu enregistré, ajoutez un champ de référence d’entité nommé
field_accountid
, qui pointera vers le type de contenuAccount
. Ce champ est essentiel pour stocker l’ID de l’entreprise de l’utilisateur. SélectionnezContent
comme type de référence, puis spécifiez le type de contenuAccount
pour établir le lien entre le document et l’entreprise. - Configurer JSON (facultatif) : Pour adapter l’endpoint JSON de ce type de contenu, accédez à
/admin/config/services/jsonapi/resource_types
. Modifiez le chemin par défaut de l’endpoint/api/node/document
vers/api/document
si vous souhaitez simplifier l’accès aux données. - Configurer les permissions d’accès : Afin que chaque utilisateur authentifié puisse créer un contenu de type
Document
, accédez à/admin/people/permissions
dans l’administration de Drupal. Dans la section Document, activez la permission Create new content pour le rôle Authenticated user. Cette étape garantit que les utilisateurs pourront créer des contenus de typeDocument
et que le champfield_accountid
contiendra l’identifiant de leur entreprise.
Mise en Place du Service
Nous allons implémenter un service qui associe automatiquement chaque contenu créé par un utilisateur à son entreprise via un champ d’identifiant unique. Ce service s’appuie sur le module personnalisé custom_entity_associate
et assure une liaison transparente entre l’utilisateur et son contenu à travers le champ field_accountid
. Tout d’abord, nous allons créer le fichier de configuration du service pour le module. Ce fichier définit un service qui gère l’association des entités avec l’entreprise de l’utilisateur.
services: custom_entity_associate.entity_associator: class: Drupal\custom_entity_associate\Service\EntityAssociator arguments: ['@logger.factory', '@entity_type.manager'] tags: - { name: event_subscriber }
Ce fichier déclare un service nommé custom_entity_associate.entity_associator
, qui fait appel à la classe EntityAssociator
(à créer dans la suite). Le service injecte deux dépendances : entity_type.manager
pour gérer les entités et logger.factory
pour enregistrer des logs.
Le cœur de notre fonctionnalité réside dans le service EntityAssociator
, qui associe automatiquement chaque contenu créé par un utilisateur à son entreprise. Voici le code de ce service :
<?php namespace Drupal\custom_entity_associate\Service; use Drupal\Core\Entity\EntityInterface; use Drupal\Core\Entity\EntityTypeManagerInterface; use Drupal\Core\Logger\LoggerChannelFactoryInterface; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Drupal\node\NodeInterface; class EntityAssociator implements EventSubscriberInterface { protected $loggerFactory; protected $entityTypeManager; public function __construct(LoggerChannelFactoryInterface $loggerFactory, EntityTypeManagerInterface $entityTypeManager) { $this->loggerFactory = $loggerFactory; $this->entityTypeManager = $entityTypeManager; } public static function getSubscribedEvents() { return [ 'entity.insert' => 'onEntityInsert', ]; } public function onEntityInsert(EntityInterface $entity) { // Check if the entity has a 'field_accountid' field. if ($entity instanceof NodeInterface && $entity->hasField('field_accountid')) { $this->loggerFactory->get('custom_entity_associate')->notice('Entity insert hook called for entity type @entity_type.', [ '@entity_type' => $entity->getEntityTypeId(), ]); $this->associateEntityWithAccount($entity); } } private function associateEntityWithAccount(EntityInterface $entity) { // Retrieve the company account information. $account_id = $this->getAccountForCurrentUser(); // Implement logic to fetch the appropriate account ID. if ($account_id) { $entity->set('field_accountid', $account_id); // Assuming 'field_accountid' is the reference field. $entity->save(); $this->loggerFactory->get('custom_entity_associate')->notice('Entity @entity_id associated with account @account_id', [ '@entity_id' => $entity->id(), '@account_id' => $account_id, ]); } else { $this->loggerFactory->get('custom_entity_associate')->error('Failed to find or associate an account with entity @entity_id', [ '@entity_id' => $entity->id(), ]); } } // Example logic to retrieve account ID, adjust as per your requirement. private function getAccountForCurrentUser() { // Retrieve the current user. $user = \Drupal::currentUser(); // Retrieve the account associated with the user. $account_id = NULL; if ($user->isAuthenticated()) { $account = $this->entityTypeManager->getStorage('user')->load($user->id()); $account_id = $account->get('field_accountid')->target_id; } return $account_id; } }
Le code utilise plusieurs éléments pour garantir une gestion efficace des entités. D’abord, EntityTypeManagerInterface
est injecté afin de permettre la manipulation des entités, tandis que LoggerChannelFactoryInterface
est utilisé pour enregistrer les événements dans les logs. La méthode onEntityInsert()
est déclenchée chaque fois qu’une entité est insérée. Elle vérifie si l’entité est un Node et si elle contient le champ field_accountid
. Si ces conditions sont remplies, elle appelle la méthode associateEntityWithAccount()
, qui assigne l’ID de l’entreprise de l’utilisateur au champ field_accountid
du contenu et enregistre l’action dans les logs à l’aide de la méthode notice()
. La méthode getAccountForCurrentUser()
récupère l’ID de l’entreprise de l’utilisateur authentifié, en supposant que l’utilisateur possède un champ field_accountid
. Enfin, la méthode getSubscribedEvents()
permet à la classe de s’abonner à l’événement EntityInsertEvent
, ce qui signifie que chaque fois qu’une entité est insérée, la méthode onEntityInsert()
est appelée.
Utilisation du hook
Nous utilisons le hook hook_entity_insert()
pour déclencher le service d’association. Ce hook permet d’intervenir immédiatement après la création d’une entité en appelant notre service EntityAssociator
pour gérer l’association.
/** * Implements hook_entity_insert(). */ function custom_entity_associate_entity_insert(Drupal\Core\Entity\EntityInterface $entity) { // Use the service to handle company account association. if ($entity instanceof Node) { \Drupal::service('custom_entity_associate.entity_associator')->onEntityInsert($entity); } }
Le code commence par vérifier si l’entité est un nœud (Node) afin de s’assurer que l’opération s’applique uniquement aux entités de type contenu. Ensuite, il appelle le service custom_entity_associate.entity_associator
et utilise sa méthode onEntityInsert()
pour effectuer l’association avec l’entreprise de l’utilisateur.
Configuration du fichier .info
Pour que le module custom_entity_associate
soit reconnu par Drupal et puisse fonctionner correctement, vous devez configurer le fichier .info.yml
de votre module, qui contient des informations essentielles sur le module, comme son nom, sa version, sa description et ses dépendances. Créez un fichier nommé custom_entity_associate.info.yml
dans le répertoire de votre module, puis ajoutez-y le contenu suivant :
name: 'Custom Entity Account Association' type: module description: 'Automatically associates a company account when a new entity with field_accountid is created.' core_version_requirement: ^8 || ^9 || ^10 package: Custom dependencies: - drupal:node - drupal:field - drupal:user - drupal:system
Ce fichier .info.yml
configure le module Custom Entity Account Association
, qui associe automatiquement un compte d’entreprise lors de la création d’une entité avec le champ field_accountid
. Il précise les versions de Drupal compatibles (8, 9, et 10), le classe sous “Custom” et déclare les dépendances nécessaires (node
, field
, user
, et system
) pour son bon fonctionnement.
Test
Pour tester le module, voici un exemple de requête curl
à exécuter après avoir activé le module et vérifié que l’utilisateur “John” possède un champ field_accountid
lié à son entreprise (par exemple, “Alpha”).
Avant de créer un contenu via l’API, récupérez le jeton CSRF pour autoriser la requête.
curl -X GET "https://your-drupal-site.com/session/token" -H "Content-Type: application/json"
Une fois le jeton CSRF obtenu, utilisez-le dans la requête suivante pour créer un contenu Document
avec les informations ci-dessous. Assurez-vous de remplacer <X-CSRF-Token>
par le jeton CSRF obtenu, et <OAuth2-Access-Token>
par le jeton d’accès de John.
curl -X POST "https://your-drupal-site.com/api/document" \
-H "Content-Type: application/vnd.api+json" \
-H "X-CSRF-Token: <X-CSRF-Token>" \
-H "Authorization: Bearer <OAuth2-Access-Token>" \
-d '{
"data": {
"type": "node--document",
"attributes": {
"title": "document0"
}
}
}'
Dans la réponse de l’API, assurez-vous que le champ field_accountid
est automatiquement rempli. La réponse JSON devrait inclure un objet relationships
où field_accountid
est lié à l’entreprise de l’utilisateur “John”, c’est-à-dire “Alpha”.
{
"data": {
"type": "node--document",
"id": "generated-document-id",
"attributes": {
"title": "document0"
},
"relationships": {
"field_accountid": {
"data": {
"type": "node--account",
"id": "bb027692-c144-41f4-807b-fcdef4915391",
"meta": {
"drupal_internal__target_id": 1
}
}
}
}
}
}
Dans cet exemple, l’ID bb027692-c144-41f4-807b-fcdef4915391
et le drupal_internal__target_id
(1) représentent l’ID de l’entreprise “Alpha”, confirmant que le champ field_accountid
est correctement lié à l’entreprise et de John.
Conclusion
Ce module personnalisé pour Drupal automatise l’association des contenus avec les entreprises des utilisateurs, améliorant ainsi la gestion des données en liant chaque contenu à l’entreprise de son créateur. En suivant les étapes de configuration et d’implémentation, vous pourrez assurer une organisation et une traçabilité optimales pour chaque entité créée, contribuant à un système plus cohérent et efficace pour les utilisateurs et administrateurs du site.
Développeuse fullstack spécialisée en Systèmes d'Information Répartis , diplômée de la section informatique de la Faculté des Sciences et Techniques (FST) de l'UCAD. Je relève avec passion des défis complexes, avec une forte capacité d'adaptation et un engagement pour la collaboration en équipe. Toujours avide d'apprendre, je vise à créer un impact positif et à promouvoir l'excellence organisationnelle dans chaque projet.