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(),
);
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
email
url
search
entity_autocomplete
Number
Range
Weight
Color
Date
Some grouping types
vertical_tabs
dropbutton
operations
details
datelist
...
Defining forms
FormBase
namespace Drupalfapi_exampleForm;
use DrupalCoreFormFormBase;
use DrupalCoreFormFormStateInterface;
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 DrupalsummerForm;
use DrupalCoreFormConfigFormBase;
use DrupalCoreFormFormStateInterface;
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 DrupalbanForm;
use DrupalCoreFormConfirmFormBase;
use DrupalCoreFormFormStateInterface;
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 entityValidation
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: 'Drupalfapi_exampleFormSimpleForm'
_title: 'Simple Form'
requirements:
_permission: 'access content'
Retrieving a form
outside of routes
Retrieving a form
$extra = '612-123-4567';
$form = Drupal::formBuilder()
->getForm('DrupalmymoduleFormExampleForm', $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, DrupalCoreFormFormStateInterface $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' => 'DrupalmoduleTypeClassName::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

D8 Form api

  • 1.
    Playing with formAPI Drupal Summer 2017
  • 2.
  • 3.
  • 5.
    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; }
  • 6.
    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; }
  • 7.
    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'), ), ), ); }
  • 8.
    D7 Form //Exists inD6 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(), );
  • 9.
    D7 Form //Exists inD6 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; }
  • 10.
  • 11.
  • 13.
    Same concept but... New types HTML5 types "Drupal" types POO developed Ajax more powerful
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
    FormBase namespace Drupalfapi_exampleForm; use DrupalCoreFormFormBase; useDrupalCoreFormFormStateInterface; 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) {} }
  • 24.
    ConfigFormBase namespace DrupalsummerForm; use DrupalCoreFormConfigFormBase; useDrupalCoreFormFormStateInterface; 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(); }
  • 25.
    ConfirmFormBase namespace DrupalbanForm; use DrupalCoreFormConfirmFormBase; useDrupalCoreFormFormStateInterface; 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 } }
  • 26.
  • 27.
    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.') ); }
  • 28.
  • 29.
    Entity Form Alter entity Validation Entity SaveentityValidation Form Load entity
  • 30.
  • 31.
    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]) ); }
  • 32.
    Integrate the formin a request
  • 33.
  • 34.
  • 35.
    Retrieving a form $extra= '612-123-4567'; $form = Drupal::formBuilder() ->getForm('DrupalmymoduleFormExampleForm', $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; }
  • 36.
  • 38.
    form_alter <?php /** * Implements hook_form_FORM_ID_alter(). */ functionexample2_form_example_form_alter(&$form, DrupalCoreFormFormStateInterface $form_state) { $form['important_question']['#description'] = t('Why did not we call the eagles at the beginning of the movie?'); }
  • 39.
  • 40.
    #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;
  • 41.
  • 42.
  • 43.
    #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; }
  • 44.
    #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'), ], ], ]; }
  • 45.
  • 46.
  • 47.
    Ajax anatomy '#ajax' =>[ 'callback' => 'DrupalmoduleTypeClassName::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, ), ];
  • 48.
    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; }
  • 49.
  • 50.
  • 52.
    Form API isyour friend!
  • 53.