Création d’un formateur de champ
Un module de formateur de champ formate les données d’un champ pour l’affichage final à l’utilisateur. Les formatteurs de champ sont définis comme des plugins, il est donc recommandé de se familiariser avec l’API des plugins avant de créer un nouveau formateur de champ.
Classe du formateur de champ
Fichier : /modules/random/src/Plugin/Field/FieldFormatter/RandomDefaultFormatter.php
<?php namespace Drupal\random\Plugin\Field\FieldFormatter; use Drupal\Core\Field\FormatterBase; use Drupal\Core\Field\FieldItemListInterface; /** * Implémentation du plugin du formateur 'Random_default'. * * @FieldFormatter( * id = "Random_default", * label = @Translation("Texte aléatoire"), * field_types = { * "Random" * } * ) */ class RandomDefaultFormatter extends FormatterBase { /** * {@inheritdoc} */ public function settingsSummary() { $summary = []; $summary[] = $this->t('Affiche la chaîne aléatoire.'); return $summary; } /** * {@inheritdoc} */ public function viewElements(FieldItemListInterface $items, $langcode) { $element = []; foreach ($items as $delta => $item) { // Rendre chaque élément en tant que markup. $element[$delta] = ['#markup' => $item->value]; } return $element; } }
Paramètres du formateur
Si votre formateur nécessite des réglages personnalisés d’affichage, trois étapes sont nécessaires :
- Redéfinir PluginSettingsBase::defaultSettings() pour définir les valeurs par défaut
- Créer un schéma de configuration pour les réglages créés
- Créer un formulaire pour permettre aux utilisateurs de modifier ces réglages
Étape 1 : redéfinir PluginSettingsBase::defaultSettings() pour définir les valeurs par défaut
/** * {@inheritdoc} */ public static function defaultSettings() { return [ // Déclare un paramètre nommé 'text_length', // avec une valeur par défaut 'short' 'text_length' => 'short', ] + parent::defaultSettings(); }
Étape 2 : créer un schéma de configuration pour vos réglages
Le schéma de configuration se place dans :
[MODULE ROOT]/config/schema/[MODULE_NAME].schema.yml
Dans ce fichier, vous décrivez le(s) type(s) de données des réglages créés dans defaultSettings() :
Étape 1 a créé un paramètre nommé 'text_length' qui stocke une chaîne. Le schéma correspondant ressemble à :
field.formatter.settings.[ID_DU_FORMATTEUR]: type: mapping label: 'Longueur du texte pour FORMATTER NAME' mapping: text_length: type: string label: 'Longueur du texte'
Étape 3 : créer un formulaire pour permettre aux utilisateurs de modifier les réglages
Le formulaire pour modifier les réglages est créé en redéfinissant FormatterBase::settingsForm().
N’oubliez pas d’ajouter l’espace de noms pour FormStateInterface en début de fichier PHP :
use Drupal\Core\Form\FormStateInterface;
/** * {@inheritdoc} */ public function settingsForm(array $form, FormStateInterface $form_state) { $form['text_length'] = [ '#title' => $this->t('Longueur du texte'), '#type' => 'select', '#options' => [ 'short' => $this->t('Court'), 'long' => $this->t('Long'), ], '#default_value' => $this->getSetting('text_length'), ]; return $form; }
Utilisation de #ajax dans les formulaires de réglages
L’utilisation de #ajax dans les formulaires de réglages est complexe car le fragment de formulaire généré par settingsForm() n’est pas à la racine du formulaire, mais imbriqué profondément. Dans l’exemple ci-dessous, le formulaire possède deux réglages : display_type, qui peut être "label" ou "entity", et entity_display_mode, qui peut être "full" ou "teaser". Le mode d’affichage de l’entité est affiché uniquement si display_type vaut "entity".
public function settingsForm(array $form, FormStateInterface $form_state) { $form['display_type'] = [ '#title' => $this->t('Type d’affichage'), '#type' => 'select', '#options' => [ 'label' => $this->t('Étiquette'), 'entity' => $this->t('Entité'), ], '#default_value' => $this->getSetting('display_type'), '#ajax' => [ 'wrapper' => 'private_message_thread_member_formatter_settings_wrapper', 'callback' => [$this, 'ajaxCallback'], ], ]; $form['entity_display_mode'] = [ '#prefix' => '<div id="private_message_thread_member_formatter_settings_wrapper">', '#suffix' => '</div>', ]; // Récupérer le nom du champ actuel $field_name = $this->fieldDefinition->getItemDefinition()->getFieldDefinition()->getName(); // Clé du réglage à récupérer $setting_key = 'display_type'; // Essayer d’obtenir la valeur dans l’état du formulaire (absente au premier chargement) if ($value = $form_state->getValue(['fields', $field_name, 'settings_edit_form', 'settings', $setting_key])) { $display_type = $value; } else { // Sinon, valeur par défaut $display_type = $this->getSetting('display_type'); } if ($display_type == 'entity') { $form['entity_display_mode']['#type'] = 'select'; $form['entity_display_mode']['#title'] = $this->t('Mode d’affichage'); $form['entity_display_mode']['#options'] = [ 'full' => $this->t('Complet'), 'teaser' => $this->t('Résumé'), ]; $form['entity_display_mode']['#default_value'] = $this->getSetting('entity_display_mode'); } else { // Forcer le rendu pour que le wrapper AJAX soit affiché même sans valeur $form['entity_display_mode']['#markup'] = ''; } return $form; }
Créez ensuite la callback ajax qui retourne l’élément de formulaire approprié :
public function ajaxCallback(array $form, FormStateInterface $form_state) { $field_name = $this->fieldDefinition->getItemDefinition()->getFieldDefinition()->getName(); $element_to_return = 'entity_display_mode'; return $form['fields'][$field_name]['plugin']['settings_edit_form']['settings'][$element_to_return]; }
Injection de dépendances dans les formatteurs de champ
Pour utiliser l’injection de dépendances dans les formatteurs de champ, trois étapes sont nécessaires :
- Implémenter l’interface ContainerFactoryPluginInterface
- Implémenter la méthode create() de ContainerFactoryPluginInterface
- Redéfinir le constructeur __construct() de FormatterBase
1) Implémenter l’interface ContainerFactoryPluginInterface
use Drupal\Core\Plugin\ContainerFactoryPluginInterface; class MyFormatter extends FormatterBase implements ContainerFactoryPluginInterface {
2) Implémenter ContainerFactoryPluginInterface::create()
Exemple d’injection du service entity.manager dans le formateur :
use Symfony\Component\DependencyInjection\ContainerInterface; public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $plugin_id, $plugin_definition, $configuration['field_definition'], $configuration['settings'], $configuration['label'], $configuration['view_mode'], $configuration['third_party_settings'], // Ajouter ici les services à injecter $container->get('entity.manager') ); }
3) Redéfinir FormatterBase::__construct()
Redéfinissez __construct() dans FormatterBase, n’oubliez pas d’appeler parent::__construct(), puis sauvegardez le service dans une propriété de la classe :
use Drupal\Core\Field\FieldDefinitionInterface; use Drupal\Core\Entity\EntityManagerInterface; /** * Service entity manager. * * @var \Drupal\Core\Entity\EntityManagerInterface */ protected $entityManager; /** * Constructeur de MyFormatter. * * @param string $plugin_id * L’ID du plugin. * @param mixed $plugin_definition * La définition du plugin. * @param \Drupal\Core\Field\FieldDefinitionInterface $field_definition * Définit l’interface pour les définitions de champ d’entité. * @param array $settings * Les réglages du formateur. * @param string $label * Le paramètre d’affichage de l’étiquette du formateur. * @param string $view_mode * Le mode d’affichage. * @param array $third_party_settings * Les réglages tiers éventuels. * @param \Drupal\Core\Entity\EntityManagerInterface $entityManager * Service entity manager. */ public function __construct($plugin_id, $plugin_definition, FieldDefinitionInterface $field_definition, array $settings, $label, $view_mode, array $third_party_settings, EntityManagerInterface $entityManager) { parent::__construct($plugin_id, $plugin_definition, $field_definition, $settings, $label, $view_mode, $third_party_settings); $this->entityManager = $entityManager; }
Vous pouvez maintenant utiliser le gestionnaire d’entités n’importe où dans votre classe de formateur via $this->entityManager
.