it-swarm.com.de

Mehrschritt- / Assistentenformulare

Ich versuche, ein mehrstufiges/Assistentenformular für Drupal 8) zu erstellen.

  • Der Benutzer füllt die Felder Vorname und Nachname aus
  • Klicken Sie auf die nächste Schaltfläche
  • Füllt weitere Informationen aus
  • Klicken Sie auf die Schaltfläche "Senden"

Derzeit gibt es viele Ressourcen für mehrstufige oder Assistentenformulare für Drupal 7 wie dieses eins und dieses .

Andererseits hatte ich einige Probleme herauszufinden, welche "Drupal" -Methode zum Erstellen von Drupal 8 Mehrschritt-/Assistentenformularen) ist.

Ich habe einige Nachforschungen angestellt und festgestellt, dass es mehrere Ansätze gibt:

  • Speichern Sie Werte mit dem neuen Konfigurationssystem
  • Verwenden Sie die Assistentenformularoberfläche ( noch nicht im Kern )
  • Speichern Sie Werte mit drupal Sitzungsobjekt (nicht sicher, ob das existiert oder nicht)

Sind das gültige Ansätze für Drupal 8?

10
chrisjlee

Der einfachste Weg, dies zu tun, ist die Verwendung von $ form_state. In Ihrer formBuild () -Methode haben Sie ein if/else oder einen Schalter, der auf $form_state['step'] Basiert, und zeigen verschiedene Formularelemente an. Dann haben Sie entweder dasselbe in Ihrem Submit-Rückruf oder mehrere Submit-Rückrufe, die etwas mit einem Objekt in $ form_state tun, das Sie erstellen, den Schritt ändern und das Flag $form_state['rebuild'] Auf TRUE setzen.

Dieser Ansatz hat einige Nachteile, weshalb (unter anderem) der ctools-Formularassistent erstellt wurde. Es kann kompliziert werden, wenn Sie mehrere Schritte haben und all dies in einer einzigen Formfunktion/Klasse definieren müssen und alles in POST Anfragen) geschieht.

Der ctools-Formularassistent gruppiert mehrere separate Formulare und steuert die Navigation von einem zum anderen. Sie verwenden auch den ctools-Objektcache, um Ihr Objekt anstelle von $ form_state zu speichern, da dies nicht mehr für Ihre Formulare freigegeben ist.

Während dieses System noch nicht existiert, wurde der ctools-Objektcache auf 8.x portiert und heißt jetzt User Tempstore, verfügbar als Service: \Drupal::service('user.private_tempstore') (before 8.0-beta8 heißt user.tempstore ). Dies ist eine Schicht über dem Speicher für auslauffähige Schlüsselwerte, die den Besitz der darin gespeicherten Daten einführt. Dies ist es, was die bekannte Nachricht in Ansichten antreibt, dass ein anderer Benutzer diese Ansicht gerade bearbeitet und sie aus diesem Grund gesperrt ist. Ein weiterer Vorteil gegenüber der Verwendung von $ _SESSION besteht darin, dass Ihre Daten nur bei Bedarf geladen werden müssen, wenn Sie 3 Ansichten bearbeiten. Wenn Sie dann $ _SESSION bearbeiten, müssen Sie sie bei jeder einzelnen Seitenanforderung laden und herumtragen.

Wenn Sie das nicht benötigen, können Sie sich auf die Sitzung verlassen oder sie auch direkt in einem Speicher für ablaufbare Schlüsselwerte ablegen ($ form_state wird jetzt auch dort gespeichert, kein Pseudo-Cache wie in 7.x).

Das Konfigurationssystem passt jedoch nicht gut zusammen. Dies ist nicht für Inhalte pro Benutzer (oder überhaupt für Inhalte) gedacht, da es nicht wirklich skalierbar ist, um Tausende oder Zehntausende von Datensätzen zu speichern, und möglicherweise einige Annahmen trifft, um alles vorzuladen, was für eine bestimmte Seitenanforderung erforderlich ist ( noch nicht, aber es gibt ein Problem, das dies ermöglicht)

12
Berdir

Normalerweise können Sie Formularwerte zwischen Schritten entweder mit dem cTools-Objektcache (ähnlich wie Mehrstufige Formulare in Drupal 7 ) oder über $form_state (As) speichern per this Tutorial ).

In Drupal 8) können Sie die Klasse FormBase erben, um eine neue mehrstufige Klasse zu erstellen.

Im Artikel Erstellen von mehrstufigen Formularen in Drupal 8 finden Sie eine einfache Möglichkeit, ein mehrstufiges Formular in Drupal) zu erstellen = 8.

Zunächst müssten Sie die Basisklasse erstellen, die für das Einfügen der erforderlichen Abhängigkeiten zuständig ist.

Wir werden alle Formularklassen zusammenfassen und sie in einem neuen Ordner namens Multistep ablegen, der sich im Plugin-Verzeichnis Form unseres Demo-Moduls befindet. Dies dient lediglich dazu, eine saubere Struktur zu haben und schnell erkennen zu können, welche Formulare Teil unseres mehrstufigen Formularprozesses sind.

Hier ist der Demo-Code (für die Datei MultistepFormBase.php):

/**
 * @file
 * Contains \Drupal\demo\Form\Multistep\MultistepFormBase.
 */

namespace Drupal\demo\Form\Multistep;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Session\SessionManagerInterface;
use Drupal\user\PrivateTempStoreFactory;
use Symfony\Component\DependencyInjection\ContainerInterface;

abstract class MultistepFormBase extends FormBase {

  /**
   * @var \Drupal\user\PrivateTempStoreFactory
   */
  protected $tempStoreFactory;

  /**
   * @var \Drupal\Core\Session\SessionManagerInterface
   */
  private $sessionManager;

  /**
   * @var \Drupal\Core\Session\AccountInterface
   */
  private $currentUser;

  /**
   * @var \Drupal\user\PrivateTempStore
   */
  protected $store;

  /**
   * Constructs a \Drupal\demo\Form\Multistep\MultistepFormBase.
   *
   * @param \Drupal\user\PrivateTempStoreFactory $temp_store_factory
   * @param \Drupal\Core\Session\SessionManagerInterface $session_manager
   * @param \Drupal\Core\Session\AccountInterface $current_user
   */
  public function __construct(PrivateTempStoreFactory $temp_store_factory, SessionManagerInterface $session_manager, AccountInterface $current_user) {
    $this->tempStoreFactory = $temp_store_factory;
    $this->sessionManager = $session_manager;
    $this->currentUser = $current_user;

    $this->store = $this->tempStoreFactory->get('multistep_data');
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('user.private_tempstore'),
      $container->get('session_manager'),
      $container->get('current_user')
    );
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    // Start a manual session for anonymous users.
    if ($this->currentUser->isAnonymous() && !isset($_SESSION['multistep_form_holds_session'])) {
      $_SESSION['multistep_form_holds_session'] = true;
      $this->sessionManager->start();
    }

    $form = array();
    $form['actions']['#type'] = 'actions';
    $form['actions']['submit'] = array(
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
      '#button_type' => 'primary',
      '#weight' => 10,
    );

    return $form;
  }

  /**
   * Saves the data from the multistep form.
   */
  protected function saveData() {
    // Logic for saving data goes here...
    $this->deleteStore();
    drupal_set_message($this->t('The form has been saved.'));

  }

  /**
   * Helper method that removes all the keys from the store collection used for
   * the multistep form.
   */
  protected function deleteStore() {
    $keys = ['name', 'email', 'age', 'location'];
    foreach ($keys as $key) {
      $this->store->delete($key);
    }
  }
}

Anschließend können Sie die eigentliche Formularklasse in einer Datei mit dem Namen MultistepOneForm.php Erstellen:

/**
 * @file
 * Contains \Drupal\demo\Form\Multistep\MultistepOneForm.
 */

namespace Drupal\demo\Form\Multistep;

use Drupal\Core\Form\FormStateInterface;

class MultistepOneForm extends MultistepFormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'multistep_form_one';
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

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

    $form['name'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Your name'),
      '#default_value' => $this->store->get('name') ? $this->store->get('name') : '',
    );

    $form['email'] = array(
      '#type' => 'email',
      '#title' => $this->t('Your email address'),
      '#default_value' => $this->store->get('email') ? $this->store->get('email') : '',
    );

    $form['actions']['submit']['#value'] = $this->t('Next');
    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->store->set('email', $form_state->getValue('email'));
    $this->store->set('name', $form_state->getValue('name'));
    $form_state->setRedirect('demo.multistep_two');
  }
}

In der Methode buildForm() definieren wir unsere beiden Dummy-Formularelemente. Beachten Sie, dass wir zuerst die vorhandene Formulardefinition aus der übergeordneten Klasse abrufen. Die Standardwerte für diese Felder werden als die Werte festgelegt, die im Speicher für diese Schlüssel gefunden wurden (damit Benutzer die Werte sehen können, die sie in diesem Schritt eingegeben haben, wenn sie darauf zurückkommen). Schließlich ändern wir den Wert der Aktionsschaltfläche in Weiter (um anzuzeigen, dass dieses Formular nicht das endgültige ist).

In der Methode submitForm() speichern wir die übermittelten Werte im Speicher und leiten sie dann in das zweite Formular um (das sich auf der Route demo.multistep_two Befindet). Beachten Sie, dass wir hier keine Validierung durchführen, um den Code hell zu halten. Die meisten Anwendungsfälle erfordern jedoch eine Eingabevalidierung.

Und aktualisieren Sie Ihre Routing-Datei im Demo-Modul (demo.routing.yml):

demo.multistep_one:
  path: '/demo/multistep-one'
  defaults:
    _form: '\Drupal\demo\Form\Multistep\MultistepOneForm'
    _title: 'First form'
  requirements:
    _permission: 'access content'
demo.multistep_two:
  path: '/demo/multistep-two'
  defaults:
    _form: '\Drupal\demo\Form\Multistep\MultistepTwoForm'
    _title: 'Second form'
  requirements:
    _permission: 'access content'

Erstellen Sie abschließend das zweite Formular (MultistepTwoForm):

/**
 * @file
 * Contains \Drupal\demo\Form\Multistep\MultistepTwoForm.
 */

namespace Drupal\demo\Form\Multistep;

use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

class MultistepTwoForm extends MultistepFormBase {

  /**
   * {@inheritdoc}.
   */
  public function getFormId() {
    return 'multistep_form_two';
  }

  /**
   * {@inheritdoc}.
   */
  public function buildForm(array $form, FormStateInterface $form_state) {

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

    $form['age'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Your age'),
      '#default_value' => $this->store->get('age') ? $this->store->get('age') : '',
    );

    $form['location'] = array(
      '#type' => 'textfield',
      '#title' => $this->t('Your location'),
      '#default_value' => $this->store->get('location') ? $this->store->get('location') : '',
    );

    $form['actions']['previous'] = array(
      '#type' => 'link',
      '#title' => $this->t('Previous'),
      '#attributes' => array(
        'class' => array('button'),
      ),
      '#weight' => 0,
      '#url' => Url::fromRoute('demo.multistep_one'),
    );

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $this->store->set('age', $form_state->getValue('age'));
    $this->store->set('location', $form_state->getValue('location'));

    // Save the data
    parent::saveData();
    $form_state->setRedirect('some_route');
  }
}

Innerhalb der Methode submitForm() speichern wir die Werte erneut im Speicher und verschieben sie auf die übergeordnete Klasse, um diese Daten auf eine Weise beizubehalten, die sie für richtig halten. Wir leiten dann zu jeder gewünschten Seite weiter (die Route, die wir hier verwenden, ist eine Dummy-Route).

Wir sollten jetzt ein funktionierendes mehrstufiges Formular haben, das PrivateTempStore verwendet, um Daten für mehrere Anforderungen verfügbar zu halten. Wenn wir weitere Schritte benötigen, müssen wir lediglich weitere Formulare erstellen, diese zwischen die vorhandenen hinzufügen und einige Anpassungen vornehmen.

4
kenorb

Der mehrstufige Assistent , den Sie erwähnt haben, ist bereits in CTools integriert, siehe: Assistentenunterstützung für 8.x-3.x , daher können Sie ihn in your_module.services.yml, Z.

services:
  ctools.wizard.form:
    class: Drupal\MyModuleMultistep\Controller\MyWizardForm

erweitern Sie dann die Klasse in src/Controller/MyWizardForm.php:

<?php

/**
 * @file
 * Contains \Drupal\MyModuleMultistep\Controller\MyWizardForm
 */

namespace Drupal\MyModuleMultistep\Controller;

/**
 * Wrapping controller for wizard forms that serve as the main page body.
 */
class MyWizardForm extends WizardFormController {

}
1
kenorb