logo

Extra Block Types (EBT) - Neue Erfahrung im Layout Builder❗

Extra Block Types (EBT) - gestylte, anpassbare Blocktypen: Diashows, Registerkarten, Karten, Akkordeons und viele andere. Eingebaute Einstellungen für Hintergrund, DOM Box, Javascript Plugins. Erleben Sie die Zukunft der Layouterstellung schon heute.

Demo EBT-Module EBT-Module herunterladen

❗Extra Absatztypen (EPT) - Erfahrung mit neuen Absätzen

Extra Paragraph Types (EPT) - analoger, auf Absätzen basierender Satz von Modulen.

Demo EPT-Module EPT-Module herunterladen

Scroll

Überblick: Erstellung eines benutzerdefinierten Feldes

18/06/2025, by Ivan
Dieses Tutorial wurde ursprünglich bei Web Wash veröffentlicht. Aber Berdir fragte, ob ich das Tutorial hier veröffentlichen könnte, also hier ist es.

Ein Modul in Drupal 7 ermöglicht das Speichern von Codebeispielen / Snippets in einem Feld. Es liefert ein benutzerdefiniertes Feld namens „Snippets-Feld“ und zeigt drei Formularelemente an: Beschreibung, Quellcode und Syntax-Highlighting-Modus (welche Programmiersprache).

Jetzt ist es an der Zeit, das Modul für Drupal 8 zu aktualisieren.

In diesem Tutorial zeige ich, wie ich ein „grundlegendes“ benutzerdefiniertes Feld in Drupal 8 erstellt habe. Ich werde nicht im Detail auf PSR-4, Annotationen oder Plugins eingehen, sonst würde das Tutorial sehr umfangreich werden.

Stattdessen werde ich Links zu anderen Seiten hinzufügen, die diese Konzepte weiter erklären.

Wenn Sie nach ausführlicher Dokumentation zur Field API in Drupal 8 suchen, sehen Sie sich folgende Serien an:

 

In Drupal 8 werden Felder nicht mehr über Hooks wie in Drupal 7 implementiert. Stattdessen werden sie mit der neuen Drupal 8 Plugin API erstellt. Das bedeutet, dass wir statt Hooks Klassen für Widget, Formatter und Feld-Element definieren. Die meisten Drupal 7 Hooks wie hook_field_schema, hook_field_is_empty usw. sind jetzt Methoden in Klassen.

Schritt 1: Implementierung des Feldelements

Der erste Arbeitsschritt ist, eine Feld-Element-Klasse namens SnippetsItem zu definieren, die von FieldItemBase erbt.

1. In Drupal 8 werden Klassen mit PSR-4 geladen.

Um also die Klasse SnippetsItem zu definieren, müssen wir die Datei SnippetsItem.php erstellen und sie in „Modul“ /src/Plugin/Field/FieldType/SnippetsItem.php ablegen.

/**
 * @file
 * Contains \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;

Dann fügen wir im Datei-Header den Namespace Drupal\snippets\Plugin\Field\FieldType sowie drei use-Anweisungen hinzu: Drupal\Core\Field\FieldItemBase, Drupal\Core\Field\FieldStorageDefinitionInterface und Drupal\Core\TypedData\DataDefinition.

2. Nun müssen wir die eigentlichen Felddetails wie Feld-ID, Label, Standard-Widget, Formatter usw. definieren. Das entspricht der Implementierung von hook_field_info in Drupal 7.

In Drupal 8 wurden viele, wenn nicht alle Informations-Hooks durch Annotationen ersetzt.

/**
 * Plugin implementation of the 'snippets' field type.
 *
 * @FieldType(
 *   id = "snippets_code",
 *   label = @Translation("Snippets field"),
 *   description = @Translation("This field stores code snippets in the database."),
 *   default_widget = "snippets_default",
 *   default_formatter = "snippets_default"
 * )
 */
class SnippetsItem extends FieldItemBase { }

Statt hook_field_info zu implementieren, definieren wir das Feld nun als Annotation im Kommentar über der Klasse.

Die Annotationseigenschaften sind selbsterklärend. Achten Sie nur darauf, dass default_widget und default_formatter auf die IDs der Widget- bzw. Formatter-Annotationen verweisen, nicht auf Klassen.

Wenn Sie mehr über Annotationen erfahren möchten, besuchen Sie die Seite Annotation-basierte Plugin-Dokumentation auf drupal.org.

3. Jetzt, wo wir die Feld-Element-Klasse haben, müssen wir einige Methoden definieren. Als Erstes betrachten wir schema().

In Drupal 7 definiert man die Schema mit hook_field_schema beim Erstellen eines benutzerdefinierten Feldes. In Drupal 8 definieren wir das Schema, indem wir die Methode schema() in der Klasse SnippetsItem hinzufügen.

Die Schema API-Dokumentation enthält eine Beschreibung der Struktur des Schema-Arrays und der möglichen Werte.
/**
 * {@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. Nun müssen wir die Methode isEmpty() hinzufügen und definieren, wann ein Feldelement als leer gilt. Diese Methode entspricht der Implementierung von hook_field_is_empty in Drupal 7.

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

5. Die letzte Methode, die wir zur Klasse hinzufügen, ist propertyDefinitions().

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

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

    $properties['source_code'] = DataDefinition::create('string')
      ->setLabel(t('Snippet code'));

    $properties['source_lang'] = DataDefinition::create('string')
      ->setLabel(t('Programming Language'))
      ->setDescription(t('Snippet code language'));

    return $properties;
}

Diese Methode definiert die Datentypen der Feldwerte. Das „Snippets-Feld“ hat nur drei Werte: Beschreibung, Code und Sprache. Daher habe ich diese als Strings in der Methode angegeben.

Für mehr Informationen siehe den Abschnitt Wie Entity API die Typed Data API-Dokumentation implementiert auf drupal.org.

Hier klicken, um die gesamte Datei zu sehen. Hinweis: Sie muss noch an die PSR-4-Spezifikation angepasst werden, weitere Informationen siehe https://www.drupal.org/node/2128865.

Schritt 2: Implementierung des Feld-Widgets

Nachdem wir das Feldelement definiert haben, erstellen wir nun das Feld-Widget. Wir brauchen eine Klasse namens SnippetsDefaultWidget, die von WidgetBase erbt.

1. Erstellen Sie die Datei SnippetsDefaultWidget.php und speichern Sie sie im Verzeichnis „Modul“ /src/Plugin/Field/FieldWidget/SnippetsDefaultWidget.php.

/**
 * @file
 * Contains \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;

Stellen Sie sicher, dass der Namespace Drupal\snippets\Plugin\Field\FieldWidget lautet und fügen Sie die use-Anweisungen für Drupal\Core\Field\FieldItemListInterface, Drupal\Core\Field\WidgetBase und Drupal\Core\Form\FormStateInterface hinzu.

2. Definieren Sie das Widget mit einer Annotation. Das entspricht hook_field_widget_info in Drupal 7.

/**
 * Plugin implementation of the 'snippets_default' widget.
 *
 * @FieldWidget(
 *   id = "snippets_default",
 *   label = @Translation("Snippets default"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultWidget extends WidgetBase { }

Wichtig: Das Attribut field_types in der Annotation muss auf die Feldtypen-IDs verweisen. Für dieses Modul ist das snippets_code, da wir in der @FieldType-Annotation id = "snippets_code" definiert haben.

3. Schließlich müssen wir das Formular des Widgets definieren, indem wir die Methode formElement() in der Klasse SnippetsDefaultWidget hinzufügen. Diese Methode entspricht hook_field_widget_form in 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('Source language'),
        '#type' => 'textfield',
        '#default_value' => isset($items[$delta]->source_lang) ? $items[$delta]->source_lang : NULL,
      );
  return $element;
}

Hier klicken, um die gesamte Datei zu sehen. Hinweis: Sie muss noch an die PSR-4-Spezifikation angepasst werden, weitere Informationen siehe https://www.drupal.org/node/2128865.

Schritt 3: Implementierung des Field Formatters

Das letzte Puzzleteil ist der Field Formatter, den wir durch Definition der Klasse SnippetsDefaultFormatter erstellen, welche von FormatterBase erbt.

1. Erstellen Sie die Datei SnippetsDefaultFormatter.php und speichern Sie sie im Verzeichnis „Modul“ /src/Plugin/Field/FieldFormatter/SnippetsDefaultFormatter.php.

/**
 * @file
 * Contains \Drupal\snippets\Plugin\field\formatter\SnippetsDefaultFormatter.
 */

namespace Drupal\snippets\Plugin\Field\FieldFormatter;

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

Stellen Sie sicher, dass der Namespace Drupal\snippets\Plugin\Field\FieldFormatter lautet und fügen Sie die use-Anweisungen für Drupal\Core\Field\FieldItemListInterface und Drupal\Core\Field\FormatterBase hinzu.

2. Definieren Sie den Formatter als Annotation. Wie bei Widget und FieldType entspricht dies hook_field_formatter_info.

/**
 * Plugin implementation of the 'snippets_default' formatter.
 *
 * @FieldFormatter(
 *   id = "snippets_default",
 *   label = @Translation("Snippets default"),
 *   field_types = {
 *     "snippets_code"
 *   }
 * )
 */
class SnippetsDefaultFormatter extends FormatterBase { }

3. Jetzt fügen wir nur noch die Methode viewElements() hinzu, die die eigentliche Feldformatierung implementiert. Diese Methode entspricht hook_field_formatter_view in Drupal 7.

/**
 * {@inheritdoc}
 */
public function viewElements(FieldItemListInterface $items, $langcode) {
  $elements = array();
  foreach ($items as $delta => $item) {
    // Ausgabe wird mit dem snippets_default-Theme gerendert.
    $source = array(
      '#theme' => 'snippets_default',
      '#source_description' => $item->source_description,
      '#source_code' => $item->source_code,
    );
    
    $elements[$delta] = array('#markup' => drupal_render($source));
  }

  return $elements;
}

Beachten Sie, dass ich ein benutzerdefiniertes Template snippets_default verwende, um die Snippets zu rendern, bevor sie vom Formatter angezeigt werden.

Der Grund dafür ist, dass ich nicht zu viel Logik oder HTML in die Methode viewElements() packen wollte.

Hier klicken, um die gesamte Datei zu sehen. Hinweis: Sie muss noch an die PSR-4-Spezifikation angepasst werden, weitere Informationen siehe https://www.drupal.org/node/2128865.

Fazit

Wie bereits erwähnt, ist die größte Änderung in Drupal 8, dass Felder mit der Plugin API und nicht mehr mit Hooks erstellt werden. Sobald Sie das verstanden haben, ist das Konzept zur Feld-Erstellung dem in Drupal 7 sehr ähnlich. Viele Methoden in Drupal 8 entsprechen den Hooks in Drupal 7.

Wenn Sie Code-Snippets testen möchten, laden Sie die 8.x-dev-Version herunter und probieren Sie es aus.

Drupal’s online documentation is © 2000-2020 by the individual contributors and can be used in accordance with the Creative Commons License, Attribution-ShareAlike 2.0. PHP code is distributed under the GNU General Public License.