Playing with form API
Drupal Summer 2017
Register
name
Samuel Solís
nick
@estoyausente
company
Bodeboca
http://www.bodeboca.com
submit
Some background
D6 Form
function form_example_tutorial_6(&$form_state) {
$form['description'] = array(
'#type' => 'item',
'#title' => t('A form with a validation handler'),
);
$form['data'] = array(
'#type' => 'fieldset',
'#title' => t('Data'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['data']['name'] = array(
'#type' => 'textfield',
'#title' => t('First name'),
'#required' => TRUE,
'#default_value' => "First name",
'#description' => "Please enter your first name.",
'#size' => 20,
'#maxlength' => 20,
);
$form['data']['year_of_birth'] = array(
'#type' => 'textfield',
'#title' => "Year of birth",
'#description' => 'Format is "YYYY"',
);
$form['submit'] = array(
'#type' => 'submit',
'#value' => 'Submit',
);
return $form;
}
D6 Form
function form_example_tutorial_6_ahah(&$form_state) {
$initial_markup = '<div>'
. t('This box will be replaced')
. '</div>';
$form['box'] = array(
'#type' => 'markup',
'#prefix' => '<div id="box">',
'#suffix' => '</div>',
'#value' => $initial_markup,
);
$form['submit'] = array(
'#type' => 'submit',
'#ahah' => array(
'path' => 'examples/ahah_example/simplest_ahah/callback',
'wrapper' => 'box',
),
'#value' => t('Click Me to change box color'),
);
return $form;
}
D7 Form
function form_example_tutorial_7 ($form, &$form_state) {
$form['drupal_summer'] = array(
'#type' => 'radios',
'#options' => array(
'go_to_the_beach' => t('To the beach'),
'go_this_session' => t('To this awesome session'),
'hangover' => t('Sorry, I have a huge hangover'),
),
'#title' => t('Where do you want to go this Saturday Morning?'),
);
$form['learn_something'] = array(
'#type' => 'textfield',
'#title' => t('What do you want to learn?'),
'#states' => array(
'visible' => array(
':input[name="drupal_summer"]' => array('value' => 'go_this_session'),
),
),
);
}
D7 Form
//Exists in D6 too
function _form_example_7_steps() {
return array(
1 => array(
'form' => 'form_example_wizard_7_1',
),
2 => array(
'form' => 'form_example_wizard_7_2',
),
);
}
function form_example_wizard($form, &$form_state) {
if (empty($form_state['step'])) {
$form_state['step'] = 1;
$form_state['step_information'] = _form_example_steps();
}
$step = &$form_state['step'];
drupal_set_title(t('Extensible Wizard: Step @step', array('@step' => $step)));
$form = $form_state['step_information'][$step]['form']($form, $form_state);
if ($step > 1) {
$form['prev'] = array(
'#type' => 'submit',
'#value' => t('Previous'),
'#name' => 'prev',
'#submit' => array('form_example_wizard_previous_submit'),
'#limit_validation_errors' => array(),
);
}
if ($step < count($form_state['step_information'])) {
$form['next'] = array(
'#type' => 'submit',
'#value' => t('Next'),
'#name' => 'next',
'#submit' => array('form_example_wizard_next_submit'),
);
}
else {
$form['finish'] = array(
'#type' => 'submit',
'#value' => t('Finish'),
);
}
// Include each validation function defined for the different steps.
if (function_exists($form_state['step_information'][$step]['form'] . '_validate')) {
$form['next']['#validate'] = array($form_state['step_information'][$step]['form'] . '_validate');
}
return $form;
}
D7 Form
//Exists in D6 too
function _form_example_element_7_info() {
$types['form_beach'] = array(
'#input' => TRUE ,
'#process' => array('form_beach_process'),
'#element_validate' => array('form_beach_validate'),
'#autocomplete_path' => FALSE,
'#value_callback' => 'form_beach_value',
'#default_value' => array(
'extension' => '',
'location' => '',
'water_temperature' => '',
),
'#theme_wrappers' => array('form_beach_form_element'),
);
return $types;
}
That's all
And what about D8?
Same concept but ...
- New types
- HTML5 types
- "Drupal" types
- POO developed
- Ajax more powerful
New #types
Special text #types
- tel
- url
- search
- entity_autocomplete
Number
Range
Weight
Color
Date
Some grouping types
- vertical_tabs
- dropbutton
- operations
- details
- datelist
- ...
Defining forms
FormBase
namespace Drupal\fapi_example\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
class BuildDemo extends FormBase {
public function getFormId() {
return 'fapi_example_simple_form';
}
public function buildForm(array $form, FormStateInterface $form_state) {}
public function validateForm(array &$form, FormStateInterface $form_state) {}
public function submitForm(array &$form, FormStateInterface $form_state) {}
}
ConfigFormBase
namespace Drupal\summer\Form;
use Drupal\Core\Form\ConfigFormBase;
use Drupal\Core\Form\FormStateInterface;
class SummerConfigurationForm extends ConfigFormBase {
public function getFormId() {
return 'your_module_admin_settings';
}
protected function getEditableConfigNames() {
return [
'summer.settings',
];
}
public function buildForm(array $form, FormStateInterface $form_state) {
$config = $this->config('summer.settings');
$form['summer_config'] = array(
'#type' => 'textfield',
'#title' => $this->t('Set why this summer is awesome'),
'#default_value' => $config->get('summer_config'),
);
return parent::buildForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
$values = $form_state->getValues();
$this->config('summer.settings')
->set('summer_config', $values['summer_config'])
->save();
}
ConfirmFormBase
namespace Drupal\ban\Form;
use Drupal\Core\Form\ConfirmFormBase;
use Drupal\Core\Form\FormStateInterface;
class ConfirmParty extends ConfirmFormBase {
public function getFormId() {
return 'confirm_party_form';
}
public function getQuestion() {
return $this->t('Are you sure you want to go to the party this nigth?');
}
public function getConfirmText() {
return $this->t('Yes, give me some beers');
}
public function getCancelUrl() {
return new Url('party.at_home');
}
public function buildForm(array $form, FormStateInterface $form_state) {
return parent::buildForm($form, $form_state);
}
public function submitForm(array &$form, FormStateInterface $form_state) {
//Go to party
}
}
Validating Forms
validateForm()
public function validateForm(array &$form, FormStateInterface $form_state) {
$rings = $form_state->getValue('rings_number');
if ($rings > 1) {
// Set an error for the form element with a key of "rings_number".
$form_state->setErrorByName(
'rings_number',
$this->t('This isn\'t the One Ring.')
);
}
Validate entities
!=
Validate forms
Entity Form
Alter entity
Validation
Entity
Save entity
Validation
Form
Load entity
Submitting Forms / Processing Form Data
submitForm()
public function submitForm(array &$form, FormStateInterface $form_state) {
/*
* This would normally be replaced by code that actually does something
* with the value.
*/
$title = $form_state->getValue('title');
drupal_set_message(
$this->t('You specified a title of %title.',
['%title' => $title])
);
}
Integrate the form in a request
Routing
fapi_example.simple_form:
path: 'examples/fapi-example/simple-form'
defaults:
_form: '\Drupal\fapi_example\Form\SimpleForm'
_title: 'Simple Form'
requirements:
_permission: 'access content'
Retrieving a form outside of routes
Retrieving a form
$extra = '612-123-4567';
$form = \Drupal::formBuilder()
->getForm('Drupal\mymodule\Form\ExampleForm', $extra);
...
public function buildForm(array $form, FormStateInterface $form_state, $extra = NULL)
$form['phone_number'] = array(
'#type' => 'tel',
'#title' => $this->t('Your phone number'),
'#value' => $extra,
);
return $form;
}
Altering a form
form_alter
<?php
/**
* Implements hook_form_FORM_ID_alter().
*/
function example2_form_example_form_alter(&$form, \Drupal\Core\Form\FormStateInterface $form_state) {
$form['important_question']['#description'] =
t('Why did not we call the eagles at the beginning of the movie?');
}
States
#states
$form['drink_wine'] = [
'#type' => 'checkbox',
'#title' => 'Do you like wine?',
];
$form['wine_type'] = [
'#type' => 'container',
'#attributes' => [
'class' => 'accommodation',
],
'#states' => [
'invisible' => [
'input[name="drink_wine"]' => ['checked' => FALSE],
],
],
];
$form['wine_type']['type'] = [
'#type' => 'radios',
'#options' => [
'white' => $this->t('White wine'),
'red' => $this->t('Red wine'),
'sparkling ' => $this->t('Sparkling wine'),
],
'#title' => t('Wine type'),
];
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Submit'),
];
return $form;
#states
Ajax
#ajax
public function buildForm(array $form, FormStateInterface $form_state) {
$form['temperature'] = [
'#title' => $this->t('Temperature'),
'#type' => 'select',
'#options' => $this->getColorTemperatures(),
'#empty_option' => $this->t('- Select a color temperature -'),
'#ajax' => [
// Could also use [get_class($this), 'updateColor'].
'callback' => '::updateColor',
'wrapper' => 'color-wrapper',
],
];
$form['color_wrapper'] = [
'#type' => 'container',
'#attributes' => ['id' => 'color-wrapper'],
];
$temperature = $form_state->getValue('temperature');
if (!empty($temperature)) {
$form['color_wrapper']['color'] = [
'#type' => 'select',
'#title' => $this->t('Color'),
'#options' => $this->getColorsByTemperature($temperature),
];
}
$form['actions'] = [
'#type' => 'actions',
'submit' => [
'#type' => 'submit',
'#value' => $this->t('Submit'),
],
];
return $form;
}
#ajax
public function updateColor(array $form, FormStateInterface $form_state) {
return $form['color_wrapper'];
}
protected function getColorsByTemperature($temperature) {
return $this->getColors()[$temperature]['colors'];
}
protected function getColorTemperatures() {
return array_map(function ($color_data) {
return $color_data['name'];
}, $this->getColors());
}
protected function getColors() {
return [
'warm' => [
'name' => $this->t('Warm'),
'colors' => [
'red' => $this->t('Red'),
'orange' => $this->t('Orange'),
'yellow' => $this->t('Yellow'),
],
],
'cool' => [
'name' => $this->t('Cool'),
'colors' => [
'blue' => $this->t('Blue'),
'purple' => $this->t('Purple'),
'green' => $this->t('Green'),
],
],
];
}
#ajax
Ajax explained
Ajax anatomy
'#ajax' => [
'callback' => 'Drupal\module\Type\ClassName::Ajaxmethod', //path or method
'event' => 'keyup', //The JavaScript event to respond to
'wrapper' => 'aValidId',
'method' => 'replaceWith', //'replaceWith', 'append', 'prepend' ...
'effect' => 'fade',
'progress' => array(
'type' => 'throbber',
'message' => NULL,
),
];
Response
public function Ajaxmethod() {
$response = new AjaxResponse();
$response->addCommand(new ReplaceCommand(
'#edit-date-format-suffix',
'<small id="edit-date-format-suffix">' . $format . '</small>'));
return $response;
}
AjaxCommands
- OpenDialogCommand
- CloseDialogCommand
- AjaxResponse
- ReplaceCommand
- ...
https://api.drupal.org/api/drupal/core!core.api.php/group/ajax/8.2.x
Documentation
- https://api.drupal.org/api/drupal/elements/8.2.x
- https://www.drupal.org/docs/8/api/form-api/introduction-to-form-api
- https://www.drupal.org/docs/8/api/form-api/configformbase-with-simple-configuration-api
- https://www.drupal.org/project/examples
Form API is your friend!
name
Samuel Solís
nick
@estoyausente
company
Bodeboca
http://www.bodeboca.com
Playing whit Form API in D8
By Samuel Solís
Playing whit Form API in D8
- 1,753