โดยปกติคุณสามารถเก็บค่าแบบฟอร์มระหว่างขั้นตอนโดยใช้แคชวัตถุ cTools (คล้ายกับรูปแบบ Multistep ใน Drupal 7 ) หรือผ่านทาง$form_state
(ตามบทช่วยสอนนี้)
ใน Drupal 8 คุณสามารถสืบทอดFormBase
คลาสเพื่อสร้างคลาส multistep ใหม่
ในบทความวิธีสร้างฟอร์มหลายขั้นตอนใน Drupal 8คุณสามารถหาวิธีง่าย ๆ ในการสร้างฟอร์มหลายขั้นตอนใน Drupal 8
ก่อนอื่นคุณจะต้องสร้างคลาสพื้นฐานซึ่งจะรับผิดชอบการฉีดการพึ่งพาที่จำเป็น
เราจะจัดกลุ่มคลาสฟอร์มทั้งหมดเข้าด้วยกันและวางไว้ในโฟลเดอร์ใหม่ที่เรียกว่าMultistep
ตั้งอยู่ภายในForm
ไดเรกทอรีปลั๊กอินของโมดูลตัวอย่างของเรา นี่เป็นเพียงการมีโครงสร้างที่สะอาดและสามารถบอกได้อย่างรวดเร็วว่าแบบฟอร์มใดเป็นส่วนหนึ่งของกระบวนการแบบหลายขั้นตอนของเรา
นี่คือตัวอย่างรหัส (สำหรับ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);
}
}
}
จากนั้นคุณสามารถสร้างคลาสฟอร์มจริงภายในไฟล์ชื่อ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');
}
}
ในbuildForm()
วิธีการที่เราจะกำหนดองค์ประกอบรูปแบบทั้งสองของเรา โปรดสังเกตว่าเรากำลังเรียกคืนนิยามของฟอร์มที่มีอยู่จากคลาสพาเรนต์ก่อน ค่าเริ่มต้นสำหรับฟิลด์เหล่านี้จะถูกตั้งค่าเป็นค่าที่พบในร้านค้าสำหรับคีย์เหล่านั้น (เพื่อให้ผู้ใช้สามารถเห็นค่าที่กรอกไว้ในขั้นตอนนี้หากพวกเขากลับมาที่นี่) สุดท้ายเรากำลังเปลี่ยนค่าของปุ่มการกระทำเป็นถัดไป (เพื่อระบุว่าแบบฟอร์มนี้ไม่ใช่แบบสุดท้าย)
ในsubmitForm()
วิธีการที่เราบันทึกค่าที่ส่งไปยังร้านค้าแล้วเปลี่ยนเส้นทางไปยังรูปแบบที่สอง (ซึ่งสามารถพบได้ที่เส้นทางdemo.multistep_two
) โปรดทราบว่าเราไม่ได้ทำการตรวจสอบใด ๆ ที่นี่เพื่อให้ไฟรหัส แต่กรณีการใช้งานส่วนใหญ่จะเรียกร้องให้มีการตรวจสอบอินพุต
และอัปเดตไฟล์เส้นทางของคุณในโมดูลตัวอย่าง ( 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'
สุดท้ายสร้างฟอร์มที่สอง ( 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');
}
}
ภายในsubmitForm()
วิธีที่เราบันทึกค่าไปยังร้านค้าอีกครั้งและเลื่อนไปที่คลาสพาเรนต์เพื่อยืนยันข้อมูลนี้ในแบบที่มันเหมาะสม จากนั้นเราจะเปลี่ยนเส้นทางไปยังหน้าใดก็ได้ที่เราต้องการ (เส้นทางที่เราใช้ที่นี่คือตัวจำลอง)
ตอนนี้เราควรจะมีรูปแบบหลายขั้นตอนการทำงานที่ใช้ในPrivateTempStore
การเก็บข้อมูลที่มีอยู่ในหลาย ๆ คำขอ หากเราต้องการขั้นตอนเพิ่มเติมสิ่งที่เราต้องทำคือสร้างแบบฟอร์มเพิ่มเติมเพิ่มในแบบฟอร์มที่มีอยู่และทำการปรับเปลี่ยนสองสามอย่าง