Normalerweise können Sie Formularwerte zwischen Schritten entweder mithilfe des cTools-Objektcaches (ähnlich wie bei mehrstufigen Formularen in Drupal 7 ) oder über $form_state
(gemäß diesem Lernprogramm ) speichern .
In Drupal 8 können Sie eine FormBase
Klasse erben , um eine neue mehrstufige Klasse zu erstellen.
In dem Artikel Wie 8 Multi-Schritt - Formulare in Drupal bauen können Sie einen einfachen Weg zu finden , ein mehrstufiges Formular in Drupal 8 zu erstellen.
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 platzieren, der Multistep
sich im Form
Plugin-Verzeichnis 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 MultistepFormBase.php
Datei):
/**
* @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
:
/**
* @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 buildForm()
Methode 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).
Bei der submitForm()
Methode speichern wir die übermittelten Werte im Speicher und leiten sie dann zum zweiten Formular weiter (das sich auf der Route befindet demo.multistep_two
). 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 submitForm()
Methode speichern wir die Werte erneut im Speicher und verschieben sie auf die übergeordnete Klasse, um diese Daten nach eigenem Ermessen beizubehalten. 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 das verwendet PrivateTempStore
, um Daten über mehrere Anforderungen hinweg 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.