diff --git a/form_example/form_example.info.yml b/form_example/form_example.info.yml new file mode 100644 index 0000000..f0487f3 --- /dev/null +++ b/form_example/form_example.info.yml @@ -0,0 +1,5 @@ +name: Form example +type: module +description: 'Examples of using the Drupal Form API' +package: Example modules +core: 8.x diff --git a/form_example/form_example.links.menu.yml b/form_example/form_example.links.menu.yml new file mode 100644 index 0000000..a99b4ce --- /dev/null +++ b/form_example/form_example.links.menu.yml @@ -0,0 +1,39 @@ +form_example.tutorial1: + title: Form Example tutorial 1 + route_name: form_example.tutorial_1 + +form_example.tutorial2: + title: Form Example tutorial 2 + route_name: form_example.tutorial_2 + +form_example.tutorial3: + title: Form Example tutorial 3 + route_name: form_example.tutorial_3 + +form_example.tutorial4: + title: Form Example tutorial 4 + route_name: form_example.tutorial_4 + +form_example.tutorial5: + title: Form Example tutorial 5 + route_name: form_example.tutorial_5 + +form_example.tutorial6: + title: Form Example tutorial 6 + route_name: form_example.tutorial_6 + +form_example.tutorial7: + title: Form Example tutorial 7 + route_name: form_example.tutorial_7 + +form_example.tutorial8: + title: Form Example tutorial 8 + route_name: form_example.tutorial_8 + +form_example.tutorial9: + title: Form Example tutorial 9 + route_name: form_example.tutorial_9 + +form_example.tutorial10: + title: Form Example tutorial 10 + route_name: form_example.tutorial_10 \ No newline at end of file diff --git a/form_example/form_example.local_tasks.yml b/form_example/form_example.local_tasks.yml new file mode 100644 index 0000000..64afca0 --- /dev/null +++ b/form_example/form_example.local_tasks.yml @@ -0,0 +1,50 @@ + form_example.tutorial_1_tab: + route_name: form_example.tutorial_1 + tab_root_id: form_example.tutorial_tab_1 + title: '#1' + weight: 0 +form_example.tutorial_2_tab: + route_name: form_example.tutorial_2 + tab_root_id: form_example.tutorial_tab_1 + title: '#2' + weight: 5 +form_example.tutorial_3_tab: + route_name: form_example.tutorial_3 + tab_root_id: form_example.tutorial_tab_1 + title: '#3' + weight: 10 +form_example.tutorial_4_tab: + route_name: form_example.tutorial_4 + tab_root_id: form_example.tutorial_tab_1 + title: '#4' + weight: 15 +form_example.tutorial_5_tab: + route_name: form_example.tutorial_5 + tab_root_id: form_example.tutorial_tab_1 + title: '#5' + weight: 20 +form_example.tutorial_6_tab: + route_name: form_example.tutorial_6 + tab_root_id: form_example.tutorial_tab_1 + title: '#6' + weight: 25 +form_example.tutorial_7_tab: + route_name: form_example.tutorial_7 + tab_root_id: form_example.tutorial_tab_1 + title: '#7' + weight: 30 +form_example.tutorial_8_tab: + route_name: form_example.tutorial_8 + tab_root_id: form_example.tutorial_tab_1 + title: '#8' + weight: 35 +form_example.tutorial_9_tab: + route_name: form_example.tutorial_9 + tab_root_id: form_example.tutorial_tab_1 + title: '#9' + weight: 45 +form_example.tutorial_10_tab: + route_name: form_example.tutorial_10 + tab_root_id: form_example.tutorial_tab_1 + title: '#10' + weight: 45 diff --git a/form_example/form_example.module b/form_example/form_example.module new file mode 100644 index 0000000..fdfabd3 --- /dev/null +++ b/form_example/form_example.module @@ -0,0 +1,127 @@ + 'Form Example', + 'route_name' => 'form_example', + 'access callback' => TRUE, + 'expanded' => TRUE, + ); + $items['examples/form_example/tutorial'] = array( + 'title' => 'Form Tutorial', + 'route_name' => array('form_example.tutorial'), + 'access callback' => TRUE, + 'description' => 'A set of ten tutorials', + ); + $items['examples/form_example/tutorial/1'] = array( + 'title' => '#1', + 'route_name' => array('form_example.tutorial_1'), + 'access callback' => TRUE, + 'description' => 'Tutorial 1: Simplest form', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/2'] = array( + 'title' => '#2', + 'route_name' => array('form_example.tutorial_2'), + 'access callback' => TRUE, + 'description' => 'Tutorial 2: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/3'] = array( + 'title' => '#3', + 'route_name' => array('form_example.tutorial_3'), + 'access callback' => TRUE, + 'description' => 'Tutorial 3: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/3'] = array( + 'title' => '#3', + 'route_name' => array('form_example.tutorial_3'), + 'access callback' => TRUE, + 'description' => 'Tutorial 3: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/4'] = array( + 'title' => '#4', + 'route_name' => array('form_example.tutorial_4'), + 'access callback' => TRUE, + 'description' => 'Tutorial 4: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/5'] = array( + 'title' => '#5', + 'route_name' => array('form_example.tutorial_5'), + 'access callback' => TRUE, + 'description' => 'Tutorial 5: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/6'] = array( + 'title' => '#6', + 'route_name' => array('form_example.tutorial_6'), + 'access callback' => TRUE, + 'description' => 'Tutorial 6: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/7'] = array( + 'title' => '#7', + 'route_name' => array('form_example.tutorial_7'), + 'access callback' => TRUE, + 'description' => 'Tutorial 7: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/8'] = array( + 'title' => '#8', + 'route_name' => array('form_example.tutorial_8'), + 'access callback' => TRUE, + 'description' => 'Tutorial 8: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/9'] = array( + 'title' => '#9', + 'route_name' => array('form_example.tutorial_9'), + 'access callback' => TRUE, + 'description' => 'Tutorial 9: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/tutorial/10'] = array( + 'title' => '#10', + 'route_name' => array('form_example.tutorial_10'), + 'access callback' => TRUE, + 'description' => 'Tutorial 10: Form with a submit button', + 'type' => MENU_VISIBLE_IN_BREADCRUMB, + ); + $items['examples/form_example/wizard'] = array( + 'title' => 'Extensible Wizard: Step 1', + 'route_name' => array('form_example.wizard'), + 'access callback' => TRUE, + 'description' => 'A general approach to a wizard multistep form.', + ); + return $items; +} + diff --git a/form_example/form_example.routing.yml b/form_example/form_example.routing.yml new file mode 100644 index 0000000..782e7e5 --- /dev/null +++ b/form_example/form_example.routing.yml @@ -0,0 +1,80 @@ +form_example: + path: 'examples/form_example' + defaults: + _content: '\Drupal\form_example\Controller\FormExampleController::description' + _title: 'Form Example' + requirements: + _access: 'TRUE' +form_example.tutorial: + path: 'examples/form_example/tutorial' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial' + requirements: + _access: 'TRUE' +form_example.tutorial_1: + path: 'examples/form_example/tutorial/1' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial' + requirements: + _access: 'TRUE' +form_example.tutorial_2: + path: 'examples/form_example/tutorial/2' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial2' + requirements: + _access: 'TRUE' +form_example.tutorial_3: + path: 'examples/form_example/tutorial/3' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial3' + requirements: + _access: 'TRUE' +form_example.tutorial_4: + path: 'examples/form_example/tutorial/4' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial4' + requirements: + _access: 'TRUE' +form_example.tutorial_5: + path: 'examples/form_example/tutorial/5' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial5' + requirements: + _access: 'TRUE' +form_example.tutorial_6: + path: 'examples/form_example/tutorial/6' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial6' + requirements: + _access: 'TRUE' +form_example.tutorial_7: + path: 'examples/form_example/tutorial/7' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial7' + requirements: + _access: 'TRUE' +form_example.tutorial_8: + path: 'examples/form_example/tutorial/8' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial8' + requirements: + _access: 'TRUE' +form_example.tutorial_9: + path: 'examples/form_example/tutorial/9' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial9' + requirements: + _access: 'TRUE' +form_example.tutorial_10: + path: 'examples/form_example/tutorial/10' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleTutorial10' + requirements: + _access: 'TRUE' +form_example.wizard: + path: 'examples/form_example/wizard' + description: 'A general approach to a wizard multistep form.' + defaults: + _form: '\Drupal\form_example\Forms\FormExampleWizard' + requirements: + _access: 'TRUE' diff --git a/form_example/src/Controller/FormExampleController.php b/form_example/src/Controller/FormExampleController.php new file mode 100644 index 0000000..9ed0f61 --- /dev/null +++ b/form_example/src/Controller/FormExampleController.php @@ -0,0 +1,31 @@ + t('

The form example module provides a tutorial, extensible multistep example, an element example, and a #states example

') + ); + + return $build; + } +} diff --git a/form_example/src/Forms/FormExampleTutorial.php b/form_example/src/Forms/FormExampleTutorial.php new file mode 100644 index 0000000..560bf63 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial.php @@ -0,0 +1,57 @@ + 'item', + '#title' => t('A form with nothing but a textfield'), + ); + // This is the first form element. It's a textfield with a label, "Name" + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) {} + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) {} +} diff --git a/form_example/src/Forms/FormExampleTutorial10.php b/form_example/src/Forms/FormExampleTutorial10.php new file mode 100644 index 0000000..0140f98 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial10.php @@ -0,0 +1,112 @@ + 'file', + '#title' => t('Image'), + '#description' => t('Upload a file, allowed extensions: jpg, jpeg, png, gif'), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + /** + * Validate function for form_example_tutorial_10(). + * + */ + public function validateForm(array &$form, array &$form_state) { + + $file = file_save_upload('file', array( + // Validates file is really an image. + 'file_validate_is_image' => array(), + // Validate extensions. + 'file_validate_extensions' => array('png gif jpg jpeg'), + )); + // If the file passed validation: + if ($file) { + // Move the file into the Drupal file system. + + $file=$file[0]; + + if ($file = file_move($file,'public://')) { + // Save the file for use in the submit handler. + $form_state['storage']['file'] = $file; + + } + else { + ; + $this->setFormError('file', $form_state, t("Failed to write the uploaded file to the site's file folder.")); + } + } + else { + $this->setFormError('file', $form_state, t('No file was uploaded.')); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $file = $form_state['storage']['file']; + // We are done with the file, remove it from storage. + + unset($form_state['storage']['file']); + // Make the storage of the file permanent. + $file->status = FILE_STATUS_PERMANENT; + // Save file status. + //$file->save(); + // Set a response to the user. + drupal_set_message(t('The form has been submitted and the image has been saved, filename: @filename.', array('@filename' => $file->getFilename()))); + } + + + +} + diff --git a/form_example/src/Forms/FormExampleTutorial2.php b/form_example/src/Forms/FormExampleTutorial2.php new file mode 100644 index 0000000..26d5aa4 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial2.php @@ -0,0 +1,59 @@ + 'item', + '#title' => t('A simple form with a submit button'), + ); + + $form['name'] = array( + '#type' => 'textfield', + '#title' => t('Name'), + ); + + // Adds a simple submit button that refreshes the form and clears its + // contents. This is the default behavior for forms. + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) {} + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) {} +} diff --git a/form_example/src/Forms/FormExampleTutorial3.php b/form_example/src/Forms/FormExampleTutorial3.php new file mode 100644 index 0000000..1140225 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial3.php @@ -0,0 +1,83 @@ + 'item', + '#title' => t('A form with a fieldset'), + ); + + $form['name'] = array( + '#type' => 'fieldset', + '#title' => t('Name'), + // Make the fieldset collapsible. + '#collapsible' => TRUE, // Added + '#collapsed' => FALSE, // Added + ); + + $form['name']['first'] = array( + '#type' => 'textfield', + '#title' => t('First Name'), + '#default_value' => '', + '#placeholder' => t('First Name'), + '#required' => false, + ); + $form['name']['last'] = array( + '#type' => 'textfield', + '#title' => t('Last Name'), + '#default_value' => '', + '#placeholder' => t('Last Name'), + '#required' => false, + ); + $form['name']['actions']['#type'] = 'actions'; + $form['name']['actions']['submit'] = array( + '#name' => 'op', + '#type' => 'submit', + '#value' => t('Submit'), + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) {} + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) {} +} diff --git a/form_example/src/Forms/FormExampleTutorial4.php b/form_example/src/Forms/FormExampleTutorial4.php new file mode 100644 index 0000000..dea1bc7 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial4.php @@ -0,0 +1,75 @@ + 'item', + '#title' => t('A form with required fields'), + ); + + $form['name'] = array( + '#type' => 'fieldset', + '#title' => t('Name'), + // Make the fieldset collapsible. + '#collapsible' => TRUE, // Added + '#collapsed' => FALSE, // Added + ); + + $form['name']['first'] = array( + '#type' => 'textfield', + '#title' => t('First Name'), + '#default_value' => '', + '#placeholder' => t('First Name'), + '#required' => TRUE, + ); + $form['name']['last'] = array( + '#type' => 'textfield', + '#title' => t('Last Name'), + '#default_value' => '', + '#placeholder' => t('Last Name'), + '#required' => TRUE, + ); + $form['name']['actions']['#type'] = 'actions'; + $form['name']['actions']['submit'] = array( + '#name' => 'op', + '#type' => 'submit', + '#value' => t('Submit'), + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) {} + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) {} +} diff --git a/form_example/src/Forms/FormExampleTutorial5.php b/form_example/src/Forms/FormExampleTutorial5.php new file mode 100644 index 0000000..ecf684f --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial5.php @@ -0,0 +1,86 @@ + 'item', + '#title' => t('A form with additional attributes'), + '#description' => t('This one adds #default_value and #description'), + ); + + $form['name'] = array( + '#type' => 'fieldset', + '#title' => t('Name'), + // Make the fieldset collapsible. + '#collapsible' => TRUE, // Added + '#collapsed' => FALSE, // Added + ); + + $form['name']['first'] = array( + '#type' => 'textfield', + '#title' => t('First name'), + '#required' => TRUE, + '#default_value' => "First name", // added default value. + '#description' => "Please enter your first name.", // added description + '#placeholder' => t('Last Name'), + '#size' => 20, // added + '#maxlength' => 20, // added + ); + $form['name']['last'] = array( + '#type' => 'textfield', + '#title' => t('Last Name'), + '#default_value' => '', + '#placeholder' => t('Last Name'), + '#required' => TRUE, + ); + $form['name']['actions']['#type'] = 'actions'; + $form['name']['actions']['submit'] = array( + '#name' => 'op', + '#type' => 'submit', + '#value' => t('Submit'), + '#button_type' => 'primary', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + public function validateForm(array &$form, array &$form_state) {} + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) {} +} diff --git a/form_example/src/Forms/FormExampleTutorial6.php b/form_example/src/Forms/FormExampleTutorial6.php new file mode 100644 index 0000000..54f4b8c --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial6.php @@ -0,0 +1,96 @@ + 'item', + '#title' => t('A form with a validation handler'), + ); + + $form['name'] = array( + '#type' => 'fieldset', + '#title' => t('Name'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + $form['name']['first'] = array( + '#type' => 'textfield', + '#title' => t('First name'), + '#required' => TRUE, + '#default_value' => "First name", + '#description' => "Please enter your first name.", + '#size' => 20, + '#maxlength' => 20, + ); + $form['name']['last'] = array( + '#type' => 'textfield', + '#title' => t('Last name'), + '#required' => TRUE, + ); + + // New form field added to permit entry of year of birth. + // The data entered into this field will be validated with + // the default validation function. + $form['year_of_birth'] = array( + '#type' => 'textfield', + '#title' => "Year of birth", + '#description' => 'Format is "YYYY"', + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + /** + * Now we add a handler/function to validate the data entered into the + * "year of birth" field to make sure it's between the values of 1900 + * and 2000. If not, it displays an error. The value report is + * $form_state['values'] (see http://drupal.org/node/144132#form-state). + * + * Notice the name of the function. It is simply the name of the form + * followed by '_validate'. This is always the name of the default validation + * function. An alternate list of validation functions could have been provided + * in $form['#validate']. + */ + public function validateForm(array &$form, array &$form_state) { + $year_of_birth = $form_state['values']['year_of_birth']; + if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) { + $this->setFormError('year_of_birth', $form_state, t('Enter a year between 1900 and 2000.')); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) {} +} diff --git a/form_example/src/Forms/FormExampleTutorial7.php b/form_example/src/Forms/FormExampleTutorial7.php new file mode 100644 index 0000000..9eb90ee --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial7.php @@ -0,0 +1,105 @@ + 'item', + '#title' => t('A form with a validation handler'), + ); + + $form['name'] = array( + '#type' => 'fieldset', + '#title' => t('Name'), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + $form['name']['first'] = array( + '#type' => 'textfield', + '#title' => t('First name'), + '#required' => TRUE, + '#default_value' => "First name", + '#description' => "Please enter your first name.", + '#size' => 20, + '#maxlength' => 20, + ); + $form['name']['last'] = array( + '#type' => 'textfield', + '#title' => t('Last name'), + '#required' => TRUE, + ); + + // New form field added to permit entry of year of birth. + // The data entered into this field will be validated with + // the default validation function. + $form['year_of_birth'] = array( + '#type' => 'textfield', + '#title' => t('Year of birth'), + '#description' => 'Format is "YYYY"', + '#default_value' => !empty($form_state['values']['year_of_birth']) ? $form_state['values']['year_of_birth'] : '', + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => 'Submit', + ); + + return $form; + } + + /** + * {@inheritdoc} + */ + /** + * Now we add a handler/function to validate the data entered into the + * "year of birth" field to make sure it's between the values of 1900 + * and 2000. If not, it displays an error. The value report is + * $form_state['values'] (see http://drupal.org/node/144132#form-state). + * + * Notice the name of the function. It is simply the name of the form + * followed by '_validate'. This is always the name of the default validation + * function. An alternate list of validation functions could have been provided + * in $form['#validate']. + */ + public function validateForm(array &$form, array &$form_state) { + + + $year_of_birth = $form_state['values']['year_of_birth']; + // Validate birthday year + if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) { + $this->setFormError('year_of_birth', $form_state, t('Enter a year between 1900 and 2000.')); + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + if ($form_state['values']['op'] == t('Submit')) { + drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth', + array('@first' => $form_state['values']['first'], '@last' => $form_state['values']['last'], '@year_of_birth' => $form_state['values']['year_of_birth']))); + } + } +} diff --git a/form_example/src/Forms/FormExampleTutorial8.php b/form_example/src/Forms/FormExampleTutorial8.php new file mode 100644 index 0000000..2e3c009 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial8.php @@ -0,0 +1,211 @@ + 2000)) { + $this->setFormError('year_of_birth', $form_state, t('Enter a year between 1900 and 2000.')); + } + } + // if (!empty($form_state['page_num']) && $form_state['page_num'] == 2) {} + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + // Normally, some code would go here to alter the database with the data + // collected from the form. Instead sets a message with drupal_set_message() + // to validate that the code worked. + + if ($form_state['values']['op'] == t('Next >>') && !empty($form_state['values'])) { + // Values are saved for each page. + // to carry forward to subsequent pages in the form. + // and we tell FAPI to rebuild the form. + if (empty($form_state['page_values'][0])) { + $form_state['page_values'][0] = $form_state['values']; + } + + // When form rebuilds, it will look at this to figure which page to build. + $form_state['page_num'] = 2; + // Rebuild the form + $form_state['rebuild'] = TRUE; + } + + if ($form_state['values']['op'] == t('<< Back') && !empty($form_state['values'])) { + if (empty($form_state['page_values'][1])) { + $form_state['page_values'][1] = $form_state['values']; + } + + $form_state['page_num'] = 1; + // Rebuild the form + $form_state['rebuild'] = TRUE; + } + + if ($form_state['values']['op'] == t('Submit')) { + if (empty($form_state['page_values'][1])) { + $form_state['page_values'][1] = $form_state['values']; + } + + drupal_set_message( + t('The form has been submitted. name=@first @last, year of birth=@year_of_birth + and the favorite color is @color', + array( + '@first' => $form_state['page_values'][0]['first'], + '@last' => $form_state['page_values'][0]['last'], + '@year_of_birth' => $form_state['page_values'][0]['year_of_birth'], + '@color' => $form_state['values']['color'], + ) + ) + ); + // If we wanted to redirect on submission, set $form_state['redirect'] + // $form_state['redirect'] = 'node'; // Redirects the user to /node. + } + } +} + + +/** + * Returns the form for the second page of form. + */ +function form_example_tutorial_8_page_one($form, &$form_state) { + if (!empty($form_state['page_values'][0])){ + $form_state['values'] = $form_state['page_values'][0]; + } + $form['description'] = array( + '#type' => 'item', + '#title' => t('A basic multistep form (page 1)'), + ); + + $form['first'] = array( + '#type' => 'textfield', + '#title' => t('First name'), + '#description' => "Please enter your first name.", + '#size' => 20, + '#maxlength' => 20, + '#required' => TRUE, + '#default_value' => !empty($form_state['values']['first']) ? $form_state['values']['first'] : '', + ); + + $form['last'] = array( + '#type' => 'textfield', + '#title' => t('Last name'), + '#default_value' => !empty($form_state['values']['last']) ? $form_state['values']['last'] : '', + ); + + $form['year_of_birth'] = array( + '#type' => 'textfield', + '#title' => t('Year of birth'), + '#description' => 'Format is "YYYY"', + '#default_value' => !empty($form_state['values']['year_of_birth']) ? $form_state['values']['year_of_birth'] : '', + ); + + $form['next'] = array( + '#type' => 'submit', + '#value' => t('Next >>'), + ); + return $form; +} + +/** + * Returns the form for the second page of form + */ +function form_example_tutorial_8_page_two($form, &$form_state) { + + if (!empty($form_state['page_values'][1])){ + $form_state['values'] = $form_state['page_values'][1]; + } + + $form['description'] = array( + '#type' => 'item', + '#title' => t('A basic multistep form (page 2)'), + ); + + $form['color'] = array( + '#type' => 'textfield', + '#title' => t('Favorite color'), + '#size' => 20, + '#maxlength' => 20, + '#required' => TRUE, + '#default_value' => !empty($form_state['values']['color']) ? $form_state['values']['color'] : '', + ); + + $form['back'] = array( + '#type' => 'submit', + '#value' => t('<< Back'), + // '#submit' => array('form_example_tutorial_8_page_two_back'), + // We won't bother validating the required 'color' field, since they + // have to come back to this page to submit anyway. + //'#limit_validation_errors' => array(), + ); + + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Submit'), + // '#submit' => array('form_example_tutorial_8_page_two_submit'), + ); + + return $form; +} diff --git a/form_example/src/Forms/FormExampleTutorial9.php b/form_example/src/Forms/FormExampleTutorial9.php new file mode 100644 index 0000000..40c8742 --- /dev/null +++ b/form_example/src/Forms/FormExampleTutorial9.php @@ -0,0 +1,181 @@ + 'item', + '#title' => t('A form with dynamically added new fields'), + ); + + if (empty($form_state['num_names'])) { + $form_state['num_names'] = 1; + } + + // Build the number of name fieldsets indicated by $form_state['num_names'] + for ($i = 1; $i <= $form_state['num_names']; $i++) { + $form['name'][$i] = array( + '#type' => 'fieldset', + '#title' => t('Name #@num', array('@num' => $i)), + '#collapsible' => TRUE, + '#collapsed' => FALSE, + ); + + $form['name'][$i]['first'] = array( + '#type' => 'textfield', + '#title' => t('First name'), + '#description' => t("Enter first name."), + '#size' => 20, + '#maxlength' => 20, + '#required' => TRUE, + ); + $form['name'][$i]['last'] = array( + '#type' => 'textfield', + '#title' => t('Enter Last name'), + '#required' => TRUE, + ); + $form['name'][$i]['year_of_birth'] = array( + '#type' => 'textfield', + '#title' => t("Year of birth"), + '#description' => t('Format is "YYYY"'), + ); + } + + $form['submit'] = array( + '#type' => 'submit', + '#value' => T('Submit'), + ); + + // Adds "Add another name" button. + $form['add_name'] = array( + '#type' => 'submit', + '#value' => t('Add another name'), + '#submit' => array(array($this,'add_name')), + ); + + // If we have more than one name, this button allows removal of the + // last name. + if ($form_state['num_names'] > 1) { + $form['remove_name'] = array( + '#type' => 'submit', + '#value' => t('Remove latest name'), + '#submit' => array(array($this,'remove_name')), + // Since we are removing a name, don't validate until later. + '#limit_validation_errors' => array(), + ); + } + + return $form; + } + + /** + * {@inheritdoc} + */ + /** + * Validate function for form_example_tutorial_9(). + * + * Adds logic to validate the form to check the validity of the new fields, + * if they exist. + */ + public function validateForm(array &$form, array &$form_state) { + for ($i = 1; $i <= $form_state['num_names']; $i++) { + $year_of_birth = $form_state['values']['name'][$i]['year_of_birth']; + + if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) { + $this->setFormError("name][$i][year_of_birth", $form_state, t('Enter a year between 1900 and 2000.')); + } + } + } + + /** + * {@inheritdoc} + */ + public function submitForm(array &$form, array &$form_state) { + $output = t("Form 9 has been submitted."); + for ($i = 1; $i <= $form_state['num_names']; $i++) { + $output .= t("@num: @first @last (@date)...", + array( + '@num' => $i, + '@first' => $form_state['values']['name'][$i]['first'], + '@last' => $form_state['values']['name'][$i]['last'], + '@date' => $form_state['values']['name'][$i]['year_of_birth'], + ) + ) . ' '; + } + + drupal_set_message($output); + } + +/** + * Submit handler for "Add another name" button on form_example_tutorial_9(). + * + * $form_state['num_names'] tells the form builder function how many name + * fieldsets to build, so here we increment it. + * + * All elements of $form_state are persisted, so there's no need to use a + * particular key, like the old $form_state['storage']. We can just use + * $form_state['num_names']. + */ + public function add_name($form, &$form_state) { + + // Everything in $form_state is persistent, so we'll just use + // $form_state['add_name'] + $form_state['num_names']++; + + // Setting $form_state['rebuild'] = TRUE causes the form to be rebuilt again. + $form_state['rebuild'] = TRUE; + } + + /** + * Submit handler for "Remove name" button on form_example_tutorial_9(). + */ + public function remove_name($form, &$form_state) { + + if ($form_state['num_names'] > 1) { + $form_state['num_names']--; + } + // Setting $form_state['rebuild'] = TRUE causes the form to be rebuilt again. + $form_state['rebuild'] = TRUE; + //$form_state->set('rebuild', TRUE); + } + +} + + + + + diff --git a/form_example/src/Tests/FormExampleTest.php b/form_example/src/Tests/FormExampleTest.php new file mode 100644 index 0000000..fd77dde --- /dev/null +++ b/form_example/src/Tests/FormExampleTest.php @@ -0,0 +1,192 @@ + 'Form Example', + 'description' => 'Various tests on the form_example module', + 'group' => 'Examples', + ); + } + + /** + * Test each tutorial. + */ + function testFormExample() { + /** + * Tutorial 1 + */ + $this->drupalGet('examples/form_example/tutorial/1'); + $this->assertResponse(200); + + /** + * Tutorial 2 + */ + $path='examples/form_example/tutorial/2'; + $post=array('name' => t('name')); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertResponse(200); + + /** + * Tutorial 3 + */ + $path='examples/form_example/tutorial/3'; + $post=array('first' => t('first'), 'last' => t('last')); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertResponse(200); + + /** + * Tutorial 4 + */ + $path='examples/form_example/tutorial/4'; + $post= array('first' => t('firstname'), 'last' => t('lastname')); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertResponse(200); + + /* $post= array(); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertText(t('First Name field is required.')); + $this->assertText(t('Last name field is required.'));*/ + + /** + * Tutorial 5 + */ + $path='examples/form_example/tutorial/5'; + $post= array('first' => t('firstname'), 'last' => t('lastname')); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertResponse(200); + + /** + * Tutorial 6 + */ + $path='examples/form_example/tutorial/6'; + $post= array( + 'first' => t('firstname'), + 'last' => t('lastname'), + 'year_of_birth' => 1955, + ); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertNoText(t('Enter a year between 1900 and 2000.')); + + $post= array( + 'first' => t('firstname'), + 'last' => t('lastname'), + 'year_of_birth' => 1855, + ); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertText(t('Enter a year between 1900 and 2000.')); + + /** + * Tutorial 7 + */ + $path='examples/form_example/tutorial/7'; + $post= array( + 'first' => t('firstname'), + 'last' => t('lastname'), + 'year_of_birth' => 1955, + ); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertNoText(t('Enter a year between 1900 and 2000.')); + + $post= array( + 'first' => t('firstname'), + 'last' => t('lastname'), + 'year_of_birth' => 1855, + ); + $this->drupalPostForm($path, $post,t('Submit')); + $this->assertText(t('Enter a year between 1900 and 2000.')); + + /** + * Tutorial 8 + */ + $path='examples/form_example/tutorial/8'; + $post= array( + 'first' => t('firstname'), + 'last' => t('lastname'), + 'year_of_birth' => 1955, + ); + + $this->drupalPostForm($path, $post,t('Next >>')); + $this->drupalPostForm(NULL, array('color' => t('green')), t('<< Back')); + $this->drupalPostForm(NULL, array(), t('Next >>')); + $this->drupalPostForm(NULL, array('color' => t('red')), t('Submit')); + $this->assertText(t('The form has been submitted. name=firstname lastname, year of birth=1955 + and the favorite color is red')); + + /** + * Tutorial 9 + */ + $path = 'examples/form_example/tutorial/9'; + for ($i = 1; $i <= 4; $i++) { + if ($i > 1) { + // Later steps of multistep form take NULL. + $path = NULL; + } + + $post= array( + "name[$i][first]" => "firstname $i", + "name[$i][last]" => "lastname $i", + "name[$i][year_of_birth]" => 1950 + $i, + ); + $this->drupalPostForm($path, $post,t('Add another name')); + + + $this->assertText(t('Name #@num', array('@num' => $i + 1))); + } + + // Now remove the last name added (#5). + $this->drupalPostForm(NULL, array(), t('Remove latest name')); + $this->assertNoText("Name #5"); + + $this->drupalPostForm(NULL, array(), t('Submit')); + + $this->assertText('Form 9 has been submitted'); + for ($i = 1; $i <= 4; $i++) { + $this->assertText(t('@num: firstname @num lastname @num (@year)', array('@num' => $i, '@year' => 1950 + $i))); + } + + /** + * Tutorial 10 + */ + $path = 'examples/form_example/tutorial/10'; + $this->drupalPostForm($path, array(), t('Submit')); + $this->assertText(t('No file was uploaded.')); + + + // Get sample images. + $images = $this->drupalGetTestFiles('image'); + foreach ($images as $image) { + $this->drupalPostForm($path, array('files[file]' => drupal_realpath($image->uri)), t('Submit')); + $this->assertText(t('The form has been submitted and the image has been saved, filename: @filename.', array('@filename' => $image->filename))); + } + } +} +