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

9.8. Arbeiten mit Formularen in Drupal. Programmgesteuertes Hinzufügen eines Konfigurationsformulars.

27/05/2025, by Ivan

In diesem Tutorial beschäftigen wir uns mit der Drupal Form API und erstellen ein Einstellungsformular für das Modul. Wir haben bereits Module zum Anzeigen von Seiten und Blöcken erstellt, nun wollen wir ein Konfigurationsformular anlegen, in dem wir Daten für die Verbindung zu einem bedingten Dienst speichern. Angenommen, wir müssen auf der Seite den API-Schlüssel und die API-Client-ID speichern, zum Beispiel für die Google Maps API.

Codebeispiele können auf GitHub eingesehen werden:
https://github.com/levmyshkin/drupalbook8

Wir könnten diese Daten in settings.php speichern und diese Einstellungen zu Git hinzufügen. Aber das wäre nicht sicher, Zugänge zu Diensten speichert man besser in der Datenbank.

Einstellungsformular

Fügen wir eine weitere Route für unser Formular hinzu:

modules/custom/drupalbook/drupalbook.routing.yml

drupalbook.settings:
  path: '/admin/structure/drupalbook/settings'
  defaults:
    _form: '\Drupal\drupalbook\Form\DrupalbookSettingsForm'
    _title: 'DrupalBook Einstellungsformular'
  requirements:
    _permission: 'administer site configuration'

Im Gegensatz zu vorherigen Routen geben wir in defaults nicht _controller, sondern _form an. Denn wir erstellen keine Controller-Klasse für das Formular, sondern eine Formular-Klasse. Erstellen wir nun eine Datei für die Formular-Klasse:

modules/custom/drupalbook/src/Form/DrupalbookSettingsForm.php

Du solltest im src-Ordner einen separaten Ordner Form für deine Formulare anlegen. So kannst du den Modulcode in einzelne Ordner strukturieren und findest den Code leicht anhand des Ordnernamens.

Füge folgenden Formularcode ein, wir analysieren jeden Block und seine Funktion:

<?php

namespace Drupal\drupalbook\Form;
 
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
 
/**
 * Beispielhafte Konfigurationseinstellungen für diese Seite.
 */
class DrupalbookSettingsForm extends ConfigFormBase {
  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'drupalbook_admin_settings';
  }
 
  /**
   * {@inheritdoc}
   */
  protected function getEditableConfigNames() {
    return [
      'drupalbook.settings',
    ];
  }
 
  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $config = $this->config('drupalbook.settings');
 
    $form['drupalbook_api_key'] = [
      '#type' => 'textfield',
      '#title' => $this->t('API-Schlüssel'),
      '#default_value' => $config->get('drupalbook_api_key'),
    ];
 
    $form['drupalbook_api_client_id'] = [
      '#type' => 'textfield',
      '#title' => $this->t('API-Client-ID'),
      '#default_value' => $config->get('drupalbook_api_client_id'),
    ];
 
    return parent::buildForm($form, $form_state);
  }
 
  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    // Die Konfiguration abrufen
    $this->configFactory->getEditable('drupalbook.settings')
      // Die übermittelten Einstellungen setzen
      ->set('drupalbook_api_key', $form_state->getValue('drupalbook_api_key'))
      // Man kann mehrere Einstellungen gleichzeitig setzen,
      // indem man mehrfach set() aufruft
      ->set('drupalbook_api_client_id', $form_state->getValue('drupalbook_api_client_id'))
      ->save();
 
    parent::submitForm($form, $form_state);
  }
}

Wir haben uns bereits mit Namespace und use-Operatoren beschäftigt, Drupal verwendet diese, um automatisch nur die benötigten Klassen zu laden:

namespace Drupal\drupalbook\Form;
 
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;

Um ein Konfigurationsformular zu erstellen, erbt man von der Klasse ConfigFormBase, diese Klasse impliziert, dass Daten aus dem Formular in die Konfiguration gespeichert werden.

extends ConfigFormBase {

Als nächstes wird die Formular-ID angegeben, diese muss für jedes Formular einzigartig sein. Wenn du deine Formular-ID mit dem Modulnamen beginnst, ist sie garantiert einzigartig:

public function getFormId() {
  return 'drupalbook_admin_settings';
}

Danach gibst du die Gruppe von Konfigurationen an, in der die Daten gespeichert werden sollen:

protected function getEditableConfigNames() {
  return [
    'drupalbook.settings',
  ];
}

Schauen wir uns an, wie die Formularfelder erstellt werden. Die Möglichkeiten der Form API und welche Felder dargestellt werden können, findest du in der Dokumentation:

https://api.drupal.org/api/drupal/elements/8.5.x

Wir haben bisher nur Textfelder verwendet:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Textfield.php/class/Textfield/8.5.x

Oft hat man aber auch Dropdown-Listen:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Select.php/class/Select/8.5.x

Checkboxen und Radio-Buttons:

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Checkboxes.php/class/Checkboxes/8.5.x

https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Render%21Element%21Radios.php/class/Radios/8.5.x

Füge gerne weitere Felder zu deinem Formular hinzu, nicht nur Textfelder.

public function buildForm(array $form, FormStateInterface $form_state) {
  $config = $this->config('drupalbook.settings');

Wir bauen ein Formular-Array in $form auf, daraus wird dann HTML generiert. Die Variable $form_state speichert alle Daten aus dem Formular, die wir absenden, inklusive der Werte aller Felder, der Formular-ID, CSRF-Token zum Schutz gegen automatische Formulareinsendungen. $form_state ermöglicht auch das Übertragen von Daten zwischen Schritten eines mehrstufigen Formulars, das werden wir in einem späteren Tutorial nutzen. Bei AJAX-Einsendungen wird das Formular immer wieder neu aufgebaut, und $form_state hilft, das Formular vor dem Abschicken wiederherzustellen. Falls das Formular aufgrund eines Fehlers nicht abgesendet wird (z.B. ein Pflichtfeld fehlt), bleiben die Eingaben erhalten, die in $form_state gespeichert sind. Deshalb gehen $form und $form_state immer zusammen.

Wir laden hier auch Werte aus der Konfiguration. Vielleicht hast du bereits Werte in drupalbook.settings gespeichert, $config ist dann nicht leer. So kannst du aktuelle Werte in den Feldern per #default_value setzen, die Werte kommen mit get() aus der Konfiguration.

$form['drupalbook_api_key'] = [
  '#type' => 'textfield',
  '#title' => $this->t('API-Schlüssel'),
  '#default_value' => $config->get('drupalbook_api_key'),
];
 
$form['drupalbook_api_client_id'] = [
  '#type' => 'textfield',
  '#title' => $this->t('API-Client-ID'),
  '#default_value' => $config->get('drupalbook_api_client_id'),
];

Am Ende der Methode geben wir $form und $form_state zurück, damit das Formular aufgebaut wird.

return parent::buildForm($form, $form_state);

Im submitForm() wird Code ausgeführt, wenn das Formular abgesendet wurde und keine Fehler vorliegen. Falls ein Pflichtfeld fehlt und Drupal einen Fehler anzeigt, wird submitForm nicht ausgeführt. Willst du Werte prüfen, kannst du validateForm() verwenden. Das wird später erklärt.

Im submitForm() lesen wir alle Felder aus, speichern deren Werte in drupalbook.settings ab:

public function submitForm(array &$form, FormStateInterface $form_state) {
  $this->configFactory->getEditable('drupalbook.settings')
    ->set('drupalbook_api_key', $form_state->getValue('drupalbook_api_key'))
    ->set('drupalbook_api_client_id', $form_state->getValue('drupalbook_api_client_id'))
    ->save();
 
  parent::submitForm($form, $form_state);
}

Die parent-Methode zeigt auch eine Bestätigungsmeldung an. Du kannst diese Zeile auskommentieren und eine eigene Meldung schreiben:

//parent::submitForm($form, $form_state);
//drupal_set_message($this->t('Mein tolles Formular wurde gespeichert!'));

Cache muss für die Route gelöscht werden, damit die Änderungen wirksam werden. Nun kannst du dein Formular ausprobieren. Um den API-Schlüssel zu laden, verwende diesen Code:

$config = \Drupal::config('drupalbook.settings');
$api_key = $config->get('drupalbook_api_key');
$api_client_id = $config->get('drupalbook_api_client_id');

Dieser Code funktioniert in jedem Modul oder Preprocess-Function, da es ein zentrales Konfigurationssystem in Drupal gibt.

Das war es für die nächste Lektion zu Formularen, wir werden dann mehrstufige Formulare besprechen.

Codebeispiele sind auf GitHub verfügbar:
https://github.com/levmyshkin/drupalbook8