9.10. API des champs Drupal. Les champs Drupal dans la base de données.
Dans cet article, nous allons comprendre comment fonctionnent les champs dans Drupal, pourquoi ils sont nécessaires et comment ils facilitent le développement rapide de sites Drupal.
Nous avons déjà travaillé avec les champs dans les articles précédents :
7.5. Mise en forme du bloc services avec les colonnes bootstrap
7.6. Galerie Isotope pour Drupal
7.7. Bloc avec vidéo YouTube dans Drupal
Maintenant, nous allons découvrir comment cela fonctionne. Allons dans l’édition des champs du type de contenu Article et ajoutons un nouveau champ de type Lien :
/admin/structure/types/manage/article/fields
Lorsque vous créez un nouvel article, vous aurez deux champs de saisie : URL et texte du lien :
Chaque fois que vous créez un champ via l’administration, deux tables sont créées dans la base de données :
{entity_type}__{field_name}
{entity_type}_revision__{field_name}
Drupal supporte les révisions, donc toutes les données sont dupliquées au moins une fois, car la seule révision est la révision actuelle de votre article. Ainsi, les champs et toute l’API Fields de Drupal servent à simplifier le travail avec la base de données. Nous créons simplement des champs via l’administration, et Drupal crée les tables dans la base de données.
Le nom des tables MySQL montre clairement que le même champ peut être utilisé pour un type d’entité. Par exemple, nous pouvons maintenant utiliser le champ Lien dans le contenu du type Page de base déjà existant :
/admin/structure/types/manage/page/fields/add-field
Mais si vous voulez créer un champ Lien dans un bloc, vous devrez créer un nouveau champ. Il n’est pas possible d’utiliser le même champ dans une entité de type différent. Créons un champ Lien pour le type Bloc de base :
/admin/structure/block/block-content/manage/basic/fields/add-field
Comme vous pouvez le voir lors de la création d’un champ, il n’y a pas de choix pour un champ Lien existant, car Block et Node sont des types d’entités différents.
Et comme pour les nœuds, nous aurons deux tables pour stocker les données du champ Lien pour les blocs :
block_content_revision__field_link et block_content__field_link.
Voyons maintenant comment Drupal stocke les données du même champ pour différents bundles de nœuds. Nous avons créé le champ Lien pour le type de nœud Article, puis réutilisé ce champ dans le type de nœud Page de base. Pour plus de commodité, il est préférable d’exporter la configuration du site dans un dossier et de consulter les fichiers, mais vous pouvez aussi retrouver la configuration via Adminer ou phpMyAdmin dans la table config :
Si vous recherchez toutes les configurations contenant le mot « link » :
SELECT * FROM `config` WHERE CONVERT(`name` USING utf8mb4) LIKE '%link%' LIMIT 50
Nous trouverons les configurations suivantes pour notre champ field_link :
field.field.block.block_content.basic.field_link
field.field.node.article.field_link
field.field.node.page.field_link
field.storage.block_content.field_link
field.storage.node.field_link
Pour chaque type d’entité, chaque champ crée sa propre configuration Field Storage. Cette configuration indique comment stocker les données dans les tables {entity_type}__{field_name}, {entity_type}_revision__{field_name}. Dans notre cas, il s’agit des tables block_content_field_link, block_content_revision_field_link, node__field_link, node_revision__field_link. Ensuite, examinons comment le module Link stocke les données. Ouvrons la configuration Field Storage pour le champ Link :
uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6
langcode: en
status: true
dependencies:
module:
- block_content
- link
id: block_content.field_link
field_name: field_link
entity_type: block_content
type: link
settings: { }
module: link
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
Examinons chacune de ces lignes pour bien comprendre ce qui est stocké dans la configuration Field Storage.
uuid: dba847ef-f4d6-4462-a2ee-f642a007fca6
C’est l’identifiant unique de la configuration. Il n’est pas nécessaire de recréer manuellement le champ sur un environnement de staging si vous l’avez créé localement et exporté la configuration. Le champ sera créé automatiquement. Si vous supprimez le champ et sa configuration localement, toutes les données seront aussi supprimées après import sur le staging. Donc si vous créez un champ sur le staging, exportez la configuration et ajoutez-la à Git pour ne pas perdre vos modifications.
langcode: en
Dans les sites multilingues, pour les différentes versions des nœuds en différentes langues, la table des champs stocke toutes les données pour toutes les langues en indiquant quelle langue utilise quelles données :
J’ai la même langue, donc la langue par défaut dans la configuration est la même.
status: true
Commun à toutes les entités de configuration, ce champ indique si l’entité est activée ou non. La configuration Field Storage utilise cette entité de configuration créée dans Drupal, voir la classe FieldStorageConfig, qui hérite de ConfigEntityBase :
https://api.drupal.org/api/drupal/core!modules!field!src!Entity!
dependencies:
module:
- block_content
- link
Dépendances aux modules additionnels. Comme nous avons utilisé le champ Link dans les blocs, le module Block content est obligatoire.
id: block_content.field_link
Le nom unique de notre configuration.
field_name: field_link
Le nom machine du champ créé, utilisé par Drupal. Par exemple, on peut accéder au champ dans l’objet node par $node->field_link->uri. Nous verrons comment référencer les champs d’entité en détail dans les prochains articles.
entity_type: block_content
Type d’entité auquel appartient cette configuration Field Storage.
type: link
Type de champ Drupal. Nous créerons notre propre type de champ, mais ici il faut savoir que ce type link est créé par le module Link. Vous pouvez consulter la classe :
core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
qui est utilisée dans notre exemple.
settings: { }
Les paramètres du type de champ, ici vides, mais par exemple pour le champ body il y a un paramètre d’affichage du teaser :
config/sync/field.field.block_content.basic.body.yml
settings:
display_summary: false
module: link
Module qui fournit le type de champ link. Ici, le nom du module et du type de champ sont identiques, mais ils peuvent différer. Par exemple, un module peut fournir plusieurs types de champs, comme le module DateTime :
core/modules/datetime/src/Plugin/Field/FieldType/DateTimeFieldItemList.php
core/modules/datetime/src/Plugin/Field/FieldType/DateTimeItem.php
locked: false
Indique si le champ est modifiable. Cela concerne sa configuration. Par exemple, dans le module Commerce, les champs Billing Information et Shipping Information étaient verrouillés car obligatoires pour la gestion de la livraison et de la TVA.
cardinality: 1
Nombre de valeurs pouvant être saisies pour ce champ dans une entité. Ici 1, mais cela peut être 2, 3, 5, etc. Pour un nombre illimité, on utilise cardinality : -1.
translatable: true
Indique si le champ est traduisible en plusieurs langues.
indexes: { }
Index SQL supplémentaires pour optimiser la recherche dans ce champ.
persist_with_no_fields: false
Indique si le Field Storage est supprimé lorsque le champ est supprimé de toutes les entités. Par exemple, si on supprime le champ dans Article et Basic Page, le Field Storage ne sera pas supprimé.
custom_storage: false
Le stockage personnalisé signifie que les données du champ sont stockées dans une table spéciale différente de {entity_type}__{field_name}. Ce n’est pas utilisé ici, mais cela peut être utile pour intégrer d’autres systèmes.
Ouvrons maintenant le fichier du type de champ link :
core/modules/link/src/Plugin/Field/FieldType/LinkItem.php
Voyons quelles données ce champ stocke en base. Cela se trouve dans la méthode propertyDefinitions() :
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
$properties['uri'] = DataDefinition::create('uri')
->setLabel(t('URI'));
$properties['title'] = DataDefinition::create('string')
->setLabel(t('Link text'));
$properties['options'] = MapDataDefinition::create()
->setLabel(t('Options'));
return $properties;
}
Comme vous le voyez, on stocke URI, Title, Options. Si vous ouvrez la table node__field_link, vous verrez ces mêmes colonnes :
Nous abordons ici le sujet de l’API Fields dans Drupal. On crée un type de champ via un module dans un fichier PHP avec la classe LinkItem. Cela permet de créer un champ pour une entité et ensuite de l’utiliser pour saisir et stocker des données en base. C’est la partie saisie de données. L’API Fields configure aussi le formulaire de saisie et l’affichage des données de nos champs.
Revenons au moment où nous créons les champs pour les types de contenu Article et Basic Page. Nous avons un fichier de configuration pour le Field Storage dans Node : field.storage.node.field_link.yml, mais aussi un fichier de configuration par bundle de l’entité, donc par exemple nous avons trois fichiers pour ce champ :
field.field.node.article.field_link.yml
field.field.node.page.field_link.yml
field.field.block.block_content.basic.field_link.yml
Ces configurations stockent les paramètres du formulaire de configuration du champ :
De cette façon, on peut personnaliser la saisie des données pour un même champ selon les bundles. Chaque configuration de champ dans un bundle est appelée Field Instance dans Drupal. On crée d’abord un Field Storage, puis on peut l’utiliser dans plusieurs Field Instances selon les bundles. Dans Drupal 8, contrairement à Drupal 7, il n’y a plus de fonctions spécifiques pour les Field Instances, cette fonctionnalité est passée dans l’API CRUD :
https://www.drupal.org/node/2054619
Des exemples de manipulation des champs en code sont disponibles dans la documentation officielle :
https://www.drupal.org/node/2012896
Nous avons ici seulement regardé la partie de l’API Fields liée au stockage des données en base. Dans les prochains cours, nous verrons comment l’API Fields gère la saisie et l’affichage des données, et comment créer notre propre type de champ complet.