Skip to content

Commit 8a07af0

Browse files
navneet0693torenware
authored andcommitted
Issue #2793383 by Torenware, andypost, navneet0693, minakshiPh: A multistep form example is missing in fapi_example
1 parent d9f404d commit 8a07af0

File tree

6 files changed

+276
-0
lines changed

6 files changed

+276
-0
lines changed

fapi_example/fapi_example.info.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ type: module
33
description: Demonstrates the Drupal Form API.
44
package: Example modules
55
core: 8.x
6+
configure: fapi_example.description
67
dependencies:
78
- examples
89
- node

fapi_example/fapi_example.links.menu.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,9 @@ fapi_example.ajax_addmore:
5151
description: Form with 'add more' and 'remove' buttons.
5252
route_name: fapi_example.ajax_addmore
5353
parent: fapi_example.description
54+
55+
fapi_example.multistep_form:
56+
title: Multistep Form API Example
57+
description: Multistep form example with submit processing.
58+
route_name: fapi_example.multistep_form
59+
parent: fapi_example.description

fapi_example/fapi_example.routing.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,11 @@ fapi_example.ajax_addmore:
8989
_title: 'Add-more button'
9090
requirements:
9191
_permission: 'access content'
92+
93+
fapi_example.multistep_form:
94+
path: 'examples/fapi-example/multistep-form'
95+
defaults:
96+
_form: '\Drupal\fapi_example\Form\MultistepForm'
97+
_title: 'Multistep Form Example'
98+
requirements:
99+
_permission: 'access content'

fapi_example/src/Controller/Page.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public function description() {
2727
'#theme' => 'item_list',
2828
'#items' => [
2929
Link::createFromRoute($this->t('Simple Form'), 'fapi_example.simple_form'),
30+
Link::createFromRoute($this->t('Multistep Form'), 'fapi_example.multistep_form'),
3031
Link::createFromRoute($this->t('Input Demo'), 'fapi_example.input_demo'),
3132
Link::createFromRoute($this->t('Form State Example'), 'fapi_example.state_demo'),
3233
Link::createFromRoute($this->t('Container Demo'), 'fapi_example.container_demo'),
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
<?php
2+
3+
namespace Drupal\fapi_example\Form;
4+
5+
use Drupal\Core\Form\FormBase;
6+
use Drupal\Core\Form\FormStateInterface;
7+
8+
/**
9+
* Provides a form with two steps.
10+
*
11+
* This example demonstrates a multistep form with text input elements. We
12+
* extend FormBase which is the simplest form base class used in Drupal.
13+
*
14+
* @see \Drupal\Core\Form\FormBase
15+
*/
16+
class MultistepForm extends FormBase {
17+
18+
/**
19+
* {@inheritdoc}
20+
*/
21+
public function getFormId() {
22+
return 'fapi_example_multistep_form';
23+
}
24+
25+
/**
26+
* {@inheritdoc}
27+
*/
28+
public function buildForm(array $form, FormStateInterface $form_state) {
29+
30+
if ($form_state->has('page_num') && $form_state->get('page_num') == 2) {
31+
return self::fapiExamplePageTwo($form, $form_state);
32+
}
33+
34+
$form_state->set('page_num', 1);
35+
36+
$form['description'] = [
37+
'#type' => 'item',
38+
'#title' => $this->t('A basic multistep form (page 1)'),
39+
];
40+
41+
$form['first_name'] = [
42+
'#type' => 'textfield',
43+
'#title' => $this->t('First Name'),
44+
'#description' => $this->t('Enter your first name.'),
45+
'#default_value' => $form_state->getValue('first_name', ''),
46+
'#required' => TRUE,
47+
];
48+
49+
$form['last_name'] = [
50+
'#type' => 'textfield',
51+
'#title' => $this->t('Last Name'),
52+
'#default_value' => $form_state->getValue('last_name', ''),
53+
'#description' => $this->t('Enter your last name.'),
54+
];
55+
56+
$form['birth_year'] = [
57+
'#type' => 'number',
58+
'#title' => $this->t('Birth Year'),
59+
'#default_value' => $form_state->getValue('birth_year', ''),
60+
'#description' => $this->t('Format is "YYYY" and value between 1900 and 2000'),
61+
];
62+
63+
// Group submit handlers in an actions element with a key of "actions" so
64+
// that it gets styled correctly, and so that other modules may add actions
65+
// to the form. This is not required, but is convention.
66+
$form['actions'] = [
67+
'#type' => 'actions',
68+
];
69+
70+
$form['actions']['next'] = [
71+
'#type' => 'submit',
72+
'#button_type' => 'primary',
73+
'#value' => $this->t('Next'),
74+
// Custom submission handler for page 1.
75+
'#submit' => ['::fapiExampleMultistepFormNextSubmit'],
76+
// Custom validation handler for page 1.
77+
'#validate' => ['::fapiExampleMultistepFormNextValidate'],
78+
];
79+
80+
return $form;
81+
}
82+
83+
/**
84+
* {@inheritdoc}
85+
*/
86+
public function submitForm(array &$form, FormStateInterface $form_state) {
87+
$page_values = $form_state->get('page_values');
88+
89+
drupal_set_message($this->t('The form has been submitted. name="@first @last", year of birth=@year_of_birth', [
90+
'@first' => $page_values['first_name'],
91+
'@last' => $page_values['last_name'],
92+
'@year_of_birth' => $page_values['birth_year'],
93+
]));
94+
95+
drupal_set_message($this->t('And the favorite color is @color', ['@color' => $form_state->getValue('color')]));
96+
}
97+
98+
/**
99+
* Provides custom validation handler for page 1.
100+
*
101+
* @param array $form
102+
* An associative array containing the structure of the form.
103+
* @param \Drupal\Core\Form\FormStateInterface $form_state
104+
* The current state of the form.
105+
*/
106+
public function fapiExampleMultistepFormNextValidate(array &$form, FormStateInterface $form_state) {
107+
$birth_year = $form_state->getValue('birth_year');
108+
109+
if ($birth_year != '' && ($birth_year < 1900 || $birth_year > 2000)) {
110+
// Set an error for the form element with a key of "birth_year".
111+
$form_state->setErrorByName('birth_year', $this->t('Enter a year between 1900 and 2000.'));
112+
}
113+
}
114+
115+
/**
116+
* Provides custom submission handler for page 1.
117+
*
118+
* @param array $form
119+
* An associative array containing the structure of the form.
120+
* @param \Drupal\Core\Form\FormStateInterface $form_state
121+
* The current state of the form.
122+
*/
123+
public function fapiExampleMultistepFormNextSubmit(array &$form, FormStateInterface $form_state) {
124+
$form_state
125+
->set('page_values', [
126+
// Keep only first step values to minimize stored data.
127+
'first_name' => $form_state->getValue('first_name'),
128+
'last_name' => $form_state->getValue('last_name'),
129+
'birth_year' => $form_state->getValue('birth_year'),
130+
])
131+
->set('page_num', 2)
132+
->setRebuild(TRUE);
133+
}
134+
135+
/**
136+
* Builds the second step form (page 2).
137+
*
138+
* @param array $form
139+
* An associative array containing the structure of the form.
140+
* @param \Drupal\Core\Form\FormStateInterface $form_state
141+
* The current state of the form.
142+
*
143+
* @return array
144+
* The render array defining the elements of the form.
145+
*/
146+
public function fapiExamplePageTwo(array &$form, FormStateInterface $form_state) {
147+
148+
$form['description'] = [
149+
'#type' => 'item',
150+
'#title' => $this->t('A basic multistep form (page 2)'),
151+
];
152+
153+
$form['color'] = [
154+
'#type' => 'textfield',
155+
'#title' => $this->t('Favorite color'),
156+
'#required' => TRUE,
157+
'#default_value' => $form_state->getValue('color', ''),
158+
];
159+
$form['back'] = [
160+
'#type' => 'submit',
161+
'#value' => $this->t('Back'),
162+
// Custom submission handler for 'Back' button.
163+
'#submit' => ['::fapiExamplePageTwoBack'],
164+
// We won't bother validating the required 'color' field, since they
165+
// have to come back to this page to submit anyway.
166+
'#limit_validation_errors' => [],
167+
];
168+
$form['submit'] = [
169+
'#type' => 'submit',
170+
'#button_type' => 'primary',
171+
'#value' => $this->t('Submit'),
172+
];
173+
174+
return $form;
175+
}
176+
177+
/**
178+
* Provides custom submission handler for 'Back' button (page 2).
179+
*
180+
* @param array $form
181+
* An associative array containing the structure of the form.
182+
* @param \Drupal\Core\Form\FormStateInterface $form_state
183+
* The current state of the form.
184+
*/
185+
public function fapiExamplePageTwoBack(array &$form, FormStateInterface $form_state) {
186+
$form_state
187+
// Restore values for the first step.
188+
->setValues($form_state->get('page_values'))
189+
->set('page_num', 1)
190+
->setRebuild(TRUE);
191+
}
192+
193+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
<?php
2+
3+
namespace Drupal\Tests\fapi_example\Functional;
4+
5+
use Drupal\Tests\BrowserTestBase;
6+
7+
/**
8+
* Tests the Multistep FAPI Example.
9+
*
10+
* @group fapi_example
11+
* @group examples
12+
*/
13+
class MultistepFormTest extends BrowserTestBase {
14+
15+
public static $modules = ['fapi_example'];
16+
17+
/**
18+
* Test of paths through the example wizard form.
19+
*/
20+
public function testWizardForm() {
21+
$this->drupalGet('examples/fapi-example/multistep-form');
22+
$page = $this->getSession()->getPage();
23+
$h1 = $page->find('css', 'h1');
24+
$this->assertContains('Multistep Form', $h1->getText());
25+
$desc = $page->find('css', '#edit-description label');
26+
$this->assertContains('page 1', $desc->getText());
27+
$this->submitForm([
28+
'first_name' => 'Bozo',
29+
'last_name' => 'Di Clown',
30+
'birth_year' => 1980,
31+
],
32+
'Next');
33+
34+
// Really new page?
35+
$page2 = $this->getSession()->getPage();
36+
$desc = $page2->find('css', '#edit-description label');
37+
$this->assertContains('page 2', $desc->getText());
38+
39+
// Try the back button.
40+
$this->submitForm([], 'Back');
41+
$page1 = $this->getSession()->getPage();
42+
$desc = $page1->find('css', '#edit-description label');
43+
$this->assertContains('page 1', $desc->getText());
44+
// Is the form still filled out?
45+
$first_name = $page1->findField('first_name')->getValue();
46+
$this->assertEquals('Bozo', $first_name);
47+
$second_name = $page1->findField('last_name')->getValue();
48+
$this->assertEquals('Di Clown', $second_name);
49+
$birth_year = $page1->findField('birth_year')->getValue();
50+
$this->assertEquals('1980', $birth_year);
51+
52+
// Back to the second page.
53+
$this->click('#edit-next');
54+
$page2 = $this->getSession()->getPage();
55+
$desc = $page2->find('css', '#edit-description label');
56+
$this->assertContains('page 2', $desc->getText());
57+
$this->submitForm(['color' => 'neon green'], 'Submit');
58+
59+
// This should take us back to the first page with a status message.
60+
$messages = $this->getSession()->getPage()->find('css', 'ul.messages__list');
61+
$message_text = $messages->getHtml();
62+
$this->assertContains('Bozo Di Clown', $message_text);
63+
$this->assertContains('1980', $message_text);
64+
$this->assertContains('neon green', $message_text);
65+
}
66+
67+
}

0 commit comments

Comments
 (0)