logo

Types de blocs supplémentaires (EBT) – Nouvelle expérience de Layout Builder❗

Types de blocs supplémentaires (EBT) – types de blocs stylisés et personnalisables : diaporamas, onglets, cartes, accordéons et bien d’autres. Paramètres intégrés pour l’arrière-plan, la boîte DOM, les plugins JavaScript. Découvrez dès aujourd’hui le futur de la création de mises en page.

Démo des modules EBT Télécharger les modules EBT

❗Types de paragraphes supplémentaires (EPT) – Nouvelle expérience Paragraphes

Types de paragraphes supplémentaires (EPT) – ensemble de modules basé sur les paragraphes analogiques.

Démo des modules EPT Télécharger les modules EPT

Défilement

Aperçu : création d’un champ personnalisé

04/07/2025, by Ivan
Ce tutoriel a été initialement publié sur Web Wash. Cependant, Berdir a demandé si je pouvais le publier ici, alors le voici.

Le module sous Drupal 7 permet de stocker des exemples de code / extraits dans un champ. Il est livré avec un champ personnalisé appelé « Champ Snippets » et affiche trois éléments de formulaire : description, code source et mode de surlignage syntaxique (quel langage de programmation).

Mais il est maintenant temps de mettre à jour le module pour Drupal 8.

Dans ce tutoriel, je vais vous montrer comment j'ai créé un champ personnalisé « basique » dans Drupal 8. Je ne détaillerai pas PSR-4, les annotations ou les plugins, sinon ce tutoriel serait énorme.

À la place, je fournirai des liens vers d’autres ressources qui expliquent ces concepts plus en détail.

Cependant, si vous recherchez une documentation détaillée sur l’API Field dans Drupal 8, consultez les séries suivantes :

 

Dans Drupal 8, les champs ne sont pas implémentés via des hooks comme dans Drupal 7. Ils sont créés à l’aide de la nouvelle API de plugins Drupal 8. Cela signifie qu’au lieu d’implémenter des hooks, on définit des classes pour le widget, le formatteur et l’élément de champ. La plupart des hooks Drupal 7 comme hook_field_schema, hook_field_is_empty, etc., sont désormais des méthodes dans des classes.

Étape 1 : implémenter l’élément de champ

La première chose à faire est de définir une classe d’élément de champ nommée SnippetsItem, qui étend la classe FieldItemBase.

1. Dans Drupal 8, les classes sont chargées via PSR-4.

Donc, pour définir la classe SnippetsItem, créez le fichier SnippetsItem.php dans module/src/Plugin/Field/FieldType/SnippetsItem.php.

/**
 * @file
 * Contient \Drupal\snippets\Plugin\Field\FieldType\SnippetsItem.
 */

namespace Drupal\snippets\Plugin\Field\FieldType;

use Drupal\Core\Field\FieldItemBase;
use Drupal\Core\Field\FieldStorageDefinitionInterface;
use Drupal\Core\TypedData\DataDefinition;

Ensuite, dans ce fichier, on ajoute le namespace Drupal\snippets\Plugin\Field\FieldType et les trois use statements : FieldItemBase, FieldStorageDefinitionInterface et DataDefinition.

2. Maintenant, il faut définir les détails du champ, comme l’ID du champ, le label, le widget par défaut, le formatteur, etc. C’est l’équivalent de hook_field_info dans Drupal 7.

Dans Drupal 8, la plupart des hooks d’informations ont été remplacés par des annotations.

/**
 * Implémentation du plugin pour le type de champ 'snippets'.
 *
 * @FieldType(
 *   id = "snippets_code",
 *   label = @Translation("Champ Snippets"),
 *   description = @Translation("Ce champ stocke des extraits de code dans la base de données."),
 *   default_widget = "snippets_default",
 *   default_formatter = "snippets_default"
 * )
 */
class SnippetsItem extends FieldItemBase { }

Au lieu d’implémenter hook_field_info, on définit le champ via une annotation au-dessus de la classe.

Les attributs de l’annotation sont explicites. Assurez-vous simplement que default_widget et default_formatter correspondent aux IDs d’annotation des widgets et formatteurs, et non aux classes.

Pour en savoir plus sur les annotations, consultez la page documentation des plugins basés sur annotations sur drupal.org.

3. Maintenant que nous avons la classe d’élément de champ, il faut définir plusieurs méthodes. La première est schema().

Dans Drupal 7, lors de la création d’un champ personnalisé, vous définissiez le schéma avec hook_field_schema. Dans Drupal 8, vous définissez le schéma via la méthode schema() dans la classe SnippetsItem.

La documentation de l’API Schema décrit la structure du tableau de schéma et ses valeurs possibles.
/**
 * {@inheritdoc}
 */
public static function schema(FieldStorageDefinitionInterface $field) {
  return array(
    'columns' => array(
      'source_description' => array(
        'type' => 'varchar',
        'length' => 256,
        'not null' => FALSE,
      ),
      'source_code' => array(
        'type' => 'text',
        'size' => 'big',
        'not null' => FALSE,
      ),
      'source_lang' => array(
        'type' => 'varchar',
        'length' => 256,
        'not null' => FALSE,
      ),
    ),
  );
}

4. Ensuite, il faut ajouter la méthode isEmpty() pour définir ce qu’est un élément vide. Cette méthode est équivalente à hook_field_is_empty dans Drupal 7.

/**
 * {@inheritdoc}
 */
public function isEmpty() {
  $value = $this->get('source_code')->getValue();
  return $value === NULL || $value === '';
}

5. Enfin, ajoutez la méthode propertyDefinitions().

/**
 * {@inheritdoc}
 */
static $propertyDefinitions;

/**
 * {@inheritdoc}
 */
public static function propertyDefinitions(FieldStorageDefinitionInterface $field_definition) {
    $properties['source_description'] = DataDefinition::create('string')
      ->setLabel(t('Description de l’extrait'));

    $properties['source_code'] = DataDefinition::create('string')
      ->setLabel(t('Code de l’extrait'));

    $properties['source_lang'] = DataDefinition::create('string')
      ->setLabel(t('Langage de programmation'))
      ->setDescription(t('Langage du code de l’extrait'));

    return $properties;
  }

Cette méthode sert à définir les types de données des valeurs du champ. Le champ Snippets a trois valeurs : description, code, et langage. Je les ai donc ajoutées comme chaînes de caractères dans la méthode.

Pour en savoir plus, consultez la section Comment l’Entity API implémente la documentation API Typed Data sur drupal.org.

Cliquez ici pour voir le fichier complet. Note : il doit être mis à jour pour la spécification PSR-4, voir https://www.drupal.org/node/2128865 pour plus de détails.

Étape 2 : implémenter le widget de champ

Maintenant que l’élément de champ est défini, créons le widget de champ. Il faut créer une classe SnippetsDefaultWidget qui étend WidgetBase.

1. Créez le fichier SnippetsDefaultWidget.php dans module/src/Plugin/Field/FieldWidget/SnippetsDefaultWidget.php.

/**
 * @file
 * Contient \Drupal\snippets\Plugin\Field\FieldWidget\SnippetsDefaultWidget.
 */

namespace Drupal\snippets\Plugin\Field\FieldWidget;

use Drupal\Core\Field\FieldItemListInterface;
use Drupal\Core\Field\WidgetBase;
use Drupal\Core\Form\FormStateInterface;

Assurez-vous que le namespace est Drupal\snippets\Plugin\Field\FieldWidget et ajoutez les use statements pour FieldItemListInterface, WidgetBase et FormStateInterface.

2. Ensuite, définissez le widget via une annotation, équivalente à hook_field_widget_info dans Drupal 7.

/**
 * Implémentation du plugin pour le widget 'snippets_default'.
 *
 * @FieldWidget(
 *   id = "snippets_default",
 *   label = @Translation("Snippets par défaut"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultWidget extends WidgetBase { }

Assurez-vous que l’attribut field_types fait référence aux IDs des types de champ. Ici, il s’agit de snippets_code, défini dans l’annotation @FieldType.

3. Enfin, définissez le formulaire du widget en ajoutant la méthode formElement() dans la classe SnippetsDefaultWidget. Cette méthode est équivalente à hook_field_widget_form dans Drupal 7.

/**
 * {@inheritdoc}
 */
public function formElement(FieldItemListInterface $items, $delta, array $element, array &$form, FormStateInterface $form_state) {

  $element['source_description'] = array(
        '#title' => $this->t('Description'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_description) ? $items[$delta]->source_description : NULL,
      );
  $element['source_code'] = array(
        '#title' => $this->t('Code'),
        '#type' => 'textarea',
        '#default_value' => isset($items[$delta]->source_code) ? $items[$delta]->source_code : NULL,
      );
  $element['source_lang'] = array(
        '#title' => $this->t('Langage source'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_lang) ? $items[$delta]->source_lang : NULL,
      );
  return $element;
}

Cliquez ici pour voir le fichier complet. Note : il doit être mis à jour pour la spécification PSR-4, voir https://www.drupal.org/node/2128865 pour plus de détails.

Étape 3 : implémenter le formatteur de champ

Le dernier élément est le formatteur de champ. Nous le créons en définissant une classe SnippetsDefaultFormatter qui étend FormatterBase.

1. Créez le fichier SnippetsDefaultFormatter.php dans module/src/Plugin/Field/FieldFormatter/SnippetsDefaultFormatter.php.

/**
 * @file
 * Contient \Drupal\snippets\Plugin\Field\FieldFormatter\SnippetsDefaultFormatter.
 */

namespace Drupal\snippets\Plugin\Field\FieldFormatter;

use Drupal\Core\Field\FormatterBase;
use Drupal\Core\Field\FieldItemListInterface;

Assurez-vous que le namespace est Drupal\snippets\Plugin\Field\FieldFormatter et ajoutez les use statements pour FieldItemListInterface et FormatterBase.

2. Ensuite, définissez le formatteur via une annotation, comme pour le widget et le type de champ, équivalent à hook_field_formatter_info.

/**
 * Implémentation du plugin pour le formatteur 'snippets_default'.
 *
 * @FieldFormatter(
 *   id = "snippets_default",
 *   label = @Translation("Snippets par défaut"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultFormatter extends FormatterBase { }

3. Enfin, ajoutez la méthode viewElements() pour définir le rendu du champ. Cette méthode est équivalente à hook_field_formatter_view dans Drupal 7.

/**
 * {@inheritdoc}
 */
public function viewElements(FieldItemListInterface $items, $langcode) {
  $elements = array();
  foreach ($items as $delta => $item) {
    // Rendu utilisant le thème snippets_default.
    $source = array(
      '#theme' => 'snippets_default',
      '#source_description' => $item->source_description,
      '#source_code' => $item->source_code,
    );
    
    $elements[$delta] = array('#markup' => drupal_render($source));
  }

  return $elements;
}

Notez que j’utilise un template personnalisé snippets_default pour rendre les extraits avant qu’ils ne soient affichés par le formatteur.

La raison est que je ne voulais pas mettre trop de logique ou de code HTML dans la méthode viewElements().

Cliquez ici pour voir le fichier complet. Note : il doit être mis à jour pour la spécification PSR-4, voir https://www.drupal.org/node/2128865 pour plus de détails.

Conclusion

Comme indiqué précédemment, le plus grand changement dans Drupal 8 est que les champs sont créés via l’API des plugins et non plus via des hooks. Une fois que vous avez compris cela, la notion de création de champ est très similaire à Drupal 7. Beaucoup de méthodes en Drupal 8 correspondent aux hooks en Drupal 7.

Si vous souhaitez tester Snippets, téléchargez la version 8.x-dev et essayez.