Thông thường, bạn có thể lưu trữ giá trị biểu mẫu giữa các bước bằng cách sử dụng bộ đệm đối tượng cTools (tương tự như biểu mẫu Multistep trong Drupal 7 ) hoặc thông qua $form_state
(theo hướng dẫn này ).
Trong Drupal 8, bạn có thể kế thừa FormBase
lớp để tạo lớp đa lớp mới.
Trong bài viết Cách xây dựng biểu mẫu nhiều bước trong Drupal 8, bạn có thể tìm thấy một cách đơn giản để tạo biểu mẫu nhiều bước trong Drupal 8.
Trước hết, bạn sẽ cần tạo lớp cơ sở chịu trách nhiệm tiêm các phụ thuộc cần thiết.
Chúng tôi sẽ nhóm tất cả các lớp biểu mẫu lại với nhau và đặt chúng trong một thư mục mới có tên Multistep
nằm trong thư mục Form
plugin của mô-đun demo. Điều này hoàn toàn là để có một cấu trúc sạch và có thể nhanh chóng cho biết các biểu mẫu nào là một phần của quy trình biểu mẫu nhiều bước của chúng tôi.
Đây là mã demo (cho MultistepFormBase.php
tệp):
/**
* @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);
}
}
}
Sau đó, bạn có thể tạo lớp biểu mẫu thực tế bên trong một tệp có tên 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');
}
}
Trong buildForm()
phương pháp, chúng tôi đang xác định hai yếu tố hình thức giả của chúng tôi. Xin lưu ý rằng chúng tôi đang truy xuất định nghĩa biểu mẫu hiện có từ lớp cha trước. Các giá trị mặc định cho các trường này được đặt làm giá trị tìm thấy trong cửa hàng cho các khóa đó (để người dùng có thể thấy các giá trị họ đã điền ở bước này nếu họ quay lại với nó). Cuối cùng, chúng tôi sẽ thay đổi giá trị của nút hành động thành Tiếp theo (để chỉ ra rằng hình thức này không phải là hình thức cuối cùng).
Trong submitForm()
phương thức, chúng tôi lưu các giá trị được gửi vào cửa hàng và sau đó chuyển hướng đến dạng thứ hai (có thể tìm thấy tại tuyến đường demo.multistep_two
). Hãy nhớ rằng chúng tôi không thực hiện bất kỳ loại xác nhận nào ở đây để giữ cho mã sáng. Nhưng hầu hết các trường hợp sử dụng sẽ gọi cho một số xác nhận đầu vào.
Và cập nhật tệp định tuyến của bạn trong mô-đun 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'
Cuối cùng, tạo dạng thứ hai ( 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');
}
}
Bên trong submitForm()
phương thức, chúng ta lại lưu các giá trị vào cửa hàng và trì hoãn lớp cha để duy trì dữ liệu này theo bất kỳ cách nào nó thấy phù hợp. Sau đó chúng tôi chuyển hướng đến bất kỳ trang nào chúng tôi muốn (tuyến đường chúng tôi sử dụng ở đây là một trang giả).
Bây giờ chúng ta nên có một biểu mẫu nhiều bước hoạt động sử dụng PrivateTempStore
để giữ dữ liệu có sẵn trên nhiều yêu cầu. Nếu chúng ta cần nhiều bước hơn, tất cả những gì chúng ta phải làm là tạo thêm một số biểu mẫu, thêm chúng vào giữa những cái hiện có và thực hiện một vài điều chỉnh.