Sans aucun doute, Display Suite est l’un des modules les plus populaires de l’histoire des modules contribués de Drupal. Il permet la création de mises en page, de champs et expose toutes sortes d’autres outils puissants que nous utilisons pour construire la couche de présentation de nos sites Drupal.
L’une des fonctionnalités les plus puissantes de Display Suite (DS) est la possibilité de créer des champs personnalisés qui peuvent être affichés dans les mises en page DS aux côtés des valeurs de champ de base réelles. Dans Drupal 7, cela a été un moyen très populaire de créer des mises en page et d’afficher des données dynamiques qui ne sont pas strictement liées à la sortie d’un champ de l’API Field sur l’entité de nœud (ou autre).
Display Suite a été porté et est maintenu pour Drupal 8. Selon un autre module contribué appelé Layout Plugin, la version D8 offre une grande partie de ce que nous avons disponible dans Drupal 7 et probablement même plus.
Dans cet article, nous allons voir comment créer notre propre champ Display Suite dans Drupal 8 en utilisant la nouvelle architecture OOP et le système de plug-ins. Pour illustrer cela, nous allons créer un champ DS disponible uniquement sur les nœuds Article qui peut être utilisé pour afficher une liste de termes de taxonomie d’un certain vocabulaire. Et nous allons faire en sorte que ce dernier puisse être configuré depuis l’interface utilisateur, à savoir que les administrateurs pourront spécifier quels termes de vocabulaire doivent être répertoriés. Pas beaucoup d’utilité dans cet exemple, je sais, mais il vous permettra de comprendre comment les choses fonctionnent.
Si vous suivez, le code que nous écrivons est disponible dans ce référentiel à l’intérieur du module Demo. Alors n’hésitez pas à vérifier cela.
plugins Drupal 8
Une grande partie des fonctionnalités qui étaient déclarées à l’aide d’un crochet _info dans Drupal 7 sont désormais déclarées à l’aide de plugins dans Drupal 8. Pour plus d’informations sur l’utilisation des plugins et la création de vos propres types de plugins, assurez-vous de consulter un précédent article de Sitepoint qui parle de juste ça.
Display Suite utilise également le nouveau système de plug-in pour permettre à d’autres modules de définir des champs DS. Il expose un type de plugin DsField qui nous permet d’écrire et de maintenir toute la logique nécessaire pour un tel champ dans une seule classe de plugin (+ tous les services que nous pourrions y injecter). Nous n’implémentons donc plus hook_ds_field_info() et renvoyons un tableau d’informations de champ par type d’entité, mais créons une classe de plug-in avec des données directement dans son annotation et la logique pertinente dans ses méthodes.
Classe VocabularyTerms
Commençons par créer notre classe de plug-in appelée VocabularyTerms dans le dossier src/plugins/DsField de notre module personnalisé et annotons-le pour nos besoins :
espace de noms DrupaldemoPluginDsField;
utilisation DrupaldsPluginDsFieldDsFieldBase;
/** * Plugin qui rend les termes d’un vocabulaire taxonomique choisi. * * @DsField( * id = «vocabulary_terms», * title = @Translation(«Termes de vocabulaire»), * entity_type = «node», * provider = «demo», * ui_limit = {«article|*»} * ) */
classer Termes de vocabulaire s’étend DsFieldBase {
}
Cette classe à elle seule contiendra toute notre logique pour notre plugin DsField très simple. Mais voici quelques remarques sur ce que nous avons jusqu’à présent :
- L’annotation est assez explicite : elle fournit des méta-informations sur le plugin.
- La classe étend DsFieldBase qui fournit des fonctionnalités de base pour tous les plugins de ce type.
- Au moment de la rédaction, l’annotation ui_limit vient d’être validée dans HEAD, il se peut donc qu’elle ne soit pas disponible dans la version que vous utilisez. La limitation de la disponibilité du champ sur les types de contenu et les modes d’affichage peut être effectuée en remplaçant la méthode isAllowed() de la classe de base et en y exécutant la logique.
Configuration par défaut
Nous voulons que notre champ soit configurable : la possibilité de sélectionner parmi une liste de vocabulaires existants. Commençons donc par fournir quelques valeurs par défaut à cette configuration afin que si l’utilisateur ne sélectionne rien, le vocabulaire des balises fourni avec core sera utilisé. Pour cela, nous devons implémenter la méthode defaultConfiguration() :
/** * {@inheritdoc} */
Publique fonction configuration par défaut() {
$configuration = déployer(
‘vocabulaire’ => ‘Mots clés’,
);
revenir $configuration;
}
Et comme nous n’avons qu’une seule option de configuration, nous renvoyons un tableau avec un élément identifié par le nom de la configuration. C’est à peu près ça.
Formateurs
Nous voulons également avoir la possibilité de spécifier à partir de l’interface utilisateur si la liste des termes de taxonomie est une série de liens vers leurs pages de termes ou leur formateur en texte brut. Nous pourrions implémenter cela dans le domaine de la configuration, mais faisons-le plutôt en utilisant des formateurs. Et c’est très simple : nous implémentons la méthode formatters() et retournons un tableau des formateurs disponibles :
/** * {@inheritdoc} */
Publique fonction formateurs() {
revenir déployer(‘lié’ => ‘Lié’, ‘non lié’ => ‘Dissocié’);
}
Ceux-ci seront disponibles pour sélection dans l’interface utilisateur sous l’en-tête Champ de la page Gérer l’affichage du type de contenu. Et nous pourrons voir le choix lorsque nous construirons le champ réel pour l’affichage. Mais plus à ce sujet dans une seconde.
Résumé de la configuration
Il est également recommandé que si nous utilisons des paramètres définis par l’interface utilisateur, nous ayons un résumé de ce qui a été sélectionné sous la forme d’une simple chaîne qui le décrit. Ceci est imprimé sous l’en-tête Widget de la page Gérer l’affichage du type de contenu.
Pour ce faire, nous devons implémenter la méthode settingsSummary() et renvoyer ledit texte :
/** * {@inheritdoc} */
Publique fonction paramètresRésumé($ paramètres) {
$config = $ceci->obtenirConfiguration();
$no_selection = déployer(‘Aucun vocabulaire sélectionné.’);
si (isset($config[‘vocabulary’]) && $config[‘vocabulary’]) {
$vocabulaire = Vocabulaire::charger($config[‘vocabulary’]);
revenir $vocabulaire ? déployer(‘Vocabulaire: ‘ . $vocabulaire->étiquette()) : $no_selection;
}
revenir $no_selection;
}
Ici, nous commençons à nous familiariser avec la configuration réelle qui a été stockée avec le champ, disponible en appelant la méthode getConfiguration () sur notre classe de plug-in. Ce que nous faisons ci-dessus, alors, est de vérifier si le paramètre de vocabulaire a été défini, nous le chargeons en fonction de son nom de machine à l’aide de la classe Vocabulary et renvoyons un tableau de chaînes qui doivent être imprimées.
Puisque nous faisons référence à la classe Vocabulaire, nous devons également l’utiliser en haut :
utilisation DrupaltaxonomieEntitéVocabulaire;
Important à noter: J’utilise Vocabulary statiquement ici pour charger une entité par souci de brièveté. Il est fortement recommandé d’injecter le stockage approprié à l’aide de l’injection de dépendances et de l’utiliser pour charger des entités. Il en va de même pour la plupart des classes auxquelles vous me verrez faire référence de manière statique ci-dessous.
Formulaire de paramètres
Maintenant que nous affichons quelle configuration a été choisie dans l’interface utilisateur, il est temps de fournir le formulaire réel qui permettra à l’utilisateur de le faire. Cela sera rendu disponible en cliquant sur la roue dentée sous l’en-tête Opérations de la page Gérer l’affichage du type de contenu.
/** * {@inheritdoc} */
Publique fonction ParamètresFormulaire($formulaire, FormStateInterface $form_state) {
$config = $ceci->obtenirConfiguration();
$noms = taxonomy_vocabulary_get_names();
$vocabulaires = Vocabulaire::chargerMultiple($noms);
$options = déployer();
pour chaque ($vocabulaires comme $vocabulaire) {
$options[$vocabulary->id()] = $vocabulaire->étiquette();
}
$ paramètres[‘vocabulary’] = déployer(
‘#taper’ => ‘sélectionner’,
‘#Titre’ => t(‘Vocabulaire’),
‘#valeur par défaut’ => $config[‘vocabulary’],
‘#options’ => $options,
);
revenir $ paramètres;
}
Comme précédemment, nous devons implémenter une méthode pour cela. Et ce que nous faisons à l’intérieur est de charger tous les noms de vocabulaire de taxonomie et de préparer un tableau d’options à utiliser avec une liste de sélection d’API de formulaire. Ce dernier est le seul élément dont nous avons besoin pour ce formulaire.
Rendu du champ
La dernière chose à faire est d’implémenter la méthode build() chargée de restituer le contenu de notre champ :
/** * {@inheritdoc} */
Publique fonction construire() {
$config = $ceci->obtenirConfiguration();
si (!isset($config[‘vocabulary’]) || !$config[‘vocabulary’]) {
revenir;
}
$requête = Drupal::entityQuery(‘taxonomy_term’)
->condition(‘à’, $config[‘vocabulary’]);
$temps = $requête->exécuter();
si (!$temps) {
revenir;
}
$termes = Terme::chargerMultiple($temps);
si (!$termes) {
revenir;
}
revenir déployer(
‘#thème’ => ‘liste des articles’,
‘#éléments’ => $ceci->buildTermList($termes),
);
}
Alors qu’est-ce qu’on fait ici ? Tout d’abord, nous accédons au vocabulaire choisi depuis la configuration. Ensuite, nous exécutons une EntityQuery pour trouver tous les termes de ce vocabulaire. Ensuite, nous chargeons tous ces termes et enfin nous renvoyons un tableau de rendu qui utilise le thème item_list pour imprimer nos termes.
Bien que nous n’en ayons pas besoin ici, dans la plupart des cas, vous devrez accéder à l’entité de nœud en cours de rendu. Cela est disponible dans le tableau de configuration sous la clé d’entité. De plus, sous la clé de construction, vous avez le tableau de rendu réel du nœud en cours de construction. Alors gardez cela à l’esprit et inspectez vous-même les autres éléments du tableau de configuration pour plus d’informations.
Je voudrais mentionner quelques points supplémentaires avant de jeter un coup d’œil à la méthode buildTermList(). Tout d’abord, par souci de concision, nous avons utilisé le service EntityQuery de manière statique. Dans votre projet, vous devez l’injecter. Deuxièmement, nous avons utilisé la classe Term de manière statique pour charger les entités de terme de taxonomie. Encore une fois, vous devez injecter son stockage et l’utiliser à cette fin. Et enfin, nous devrions importer la classe Term en haut avec use :
utilisation DrupaltaxonomieEntitéTerme;
Maintenant que c’est clair, regardons notre propre méthode buildTermList() :
privé fonction buildTermList(tableau $termes) {
$config = $ceci->obtenirConfiguration();
$formatter = isset($config[‘field’][‘formatter’]) && $config[‘field’][‘formatter’] ? $config[‘field’][‘formatter’] : ‘non lié’;
$articles = déployer();
pour chaque ($termes comme $ terme) {
$articles[] = $ceci->buildTermListItembuildTermListItem($ terme, $formatter);
}
revenir $articles;
}
Cette méthode est chargée d’obtenir le formateur de champ, de parcourir les entités de terme et de créer un tableau d’informations sur les termes qui peuvent être imprimées à l’aide du thème item_list. Comme vous pouvez le voir, cependant, l’entité de terme individuelle et le formateur sont passés à une autre méthode d’assistance pour garder les choses bien rangées :
privé fonction buildTermListItembuildTermListItem(Terme $ terme, $formatter) {
si ($formatter === ‘lié’) {
$link_url = URL::deRoute(‘entity.taxonomy_term.canonical’, déployer(‘taxonomy_term’ => $ terme->identifiant()));
revenir Drupal::je($ terme->étiquette(), $link_url);
}
revenir SafeMarkup::checkPlain($ terme->étiquette());
}
Enfin, dans la méthode buildTermListItem(), nous renvoyons soit le titre épuré du terme, soit un lien vers celui-ci en fonction du formateur.
Encore une fois, nous voyons des classes qui devraient être injectées mais qui ont été utilisées statiquement pour économiser de l’espace. Avec le risque de ressembler à un disque rayé, gardez à l’esprit que vous devez les injecter. Pour l’instant, il faut les utiliser en haut :
utilisation DrupalNoyauUrl;
utilisation DrupalComposantUtilitaireSafeMarkup;
Conclusion
Et voilà, nous l’avons, notre propre plugin DsField dans Drupal 8. Effacer les caches rendrait désormais ce champ disponible sur tous les modes d’affichage du type de contenu Article.
De plus, il peut être configuré pour choisir parmi plusieurs vocabulaires dont il affichera alors les termes. Et enfin, nous pouvons même spécifier un formateur pour imprimer ces termes liés ou en texte brut.