Biasanya Anda bisa menyimpan nilai formulir di antara langkah-langkah menggunakan cache objek cTools (mirip dengan formulir Multistep di Drupal 7 ), atau melalui $form_state
(sesuai tutorial ini ).
Di Drupal 8 Anda bisa mewarisi FormBase
kelas untuk membuat kelas multistep baru.
Dalam artikel Cara Membangun Formulir multi-langkah di Drupal 8 Anda bisa menemukan cara sederhana untuk membuat formulir multistep di Drupal 8.
Pertama-tama, Anda harus membuat kelas dasar yang akan bertugas menyuntikkan dependensi yang diperlukan.
Kami akan mengelompokkan semua kelas formulir bersama dan menempatkannya di dalam folder baru bernama Multistep
terletak di dalam Form
direktori plugin modul demo kami. Ini murni untuk memiliki struktur yang bersih dan dapat dengan cepat mengetahui bentuk mana yang merupakan bagian dari proses formulir multi-langkah kami.
Berikut adalah kode demo (untuk MultistepFormBase.php
file):
/**
* @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);
}
}
}
Kemudian Anda bisa membuat kelas bentuk aktual di dalam file bernama 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');
}
}
Dalam buildForm()
metode ini kita mendefinisikan dua elemen bentuk boneka kami. Perhatikan bahwa kami mengambil definisi formulir yang ada dari kelas induk terlebih dahulu. Nilai default untuk bidang ini ditetapkan sebagai nilai yang ditemukan di toko untuk kunci tersebut (sehingga pengguna dapat melihat nilai yang mereka isi pada langkah ini jika mereka kembali ke sana). Akhirnya, kami mengubah nilai tombol tindakan ke Berikutnya (untuk menunjukkan bahwa formulir ini bukan yang terakhir).
Dalam submitForm()
metode kami menyimpan nilai yang dikirimkan ke toko dan kemudian mengarahkan ulang ke bentuk kedua (yang dapat ditemukan di rute demo.multistep_two
). Ingatlah bahwa kami tidak melakukan validasi apa pun di sini untuk menjaga kode tetap ringan. Tetapi sebagian besar kasus penggunaan akan meminta beberapa validasi input.
Dan perbarui file perutean Anda di modul demo ( 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'
Akhirnya, buat formulir kedua ( 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');
}
}
Di dalam submitForm()
metode kami sekali lagi menyimpan nilai-nilai ke toko dan tunduk pada kelas induk untuk bertahan data ini dengan cara apa pun yang menurutnya cocok. Kami kemudian mengarahkan ke halaman apa pun yang kami inginkan (rute yang kami gunakan di sini adalah dummy).
Kami sekarang harus memiliki formulir multistep yang berfungsi yang menggunakan PrivateTempStore
untuk menjaga data tersedia di beberapa permintaan. Jika kita membutuhkan lebih banyak langkah, yang harus kita lakukan adalah membuat beberapa formulir lagi, menambahkannya di antara yang sudah ada dan membuat beberapa penyesuaian.