Understanding Forms in Drupal

Web applications today are being used in all kinds of industries. They need to take in and process a lot of user data. The capturing of the data happens through HTML forms which let you create different types of input fields like textboxes, radio buttons etc. using HTML tags. These forms get difficult to maintain or update if they are written directly in the HTML code. Drupal provides a very good way of defining forms directly in your PHP code, while the form generation is done by Drupal itself. This makes it easy for you to create and maintain forms. In this article we are going to see how we can create forms in Drupal. The final code can be cloned from Github.

The drupal_get_form function – Form generation in Drupal

The whole magic of form creation in Drupal is performed by the function drupal_get_form. This function returns a renderable form array to the Drupal system. It takes an argument as the form_id: a unique identifier to identify the form, and if a function with the same name exits then that function is called to build it. You can read more about drupal_get_form at the link https://api.drupal.org/api/drupal/includes!form.inc/function/drupal_get_form/7

Creating a basic form in Drupal

Let’s start by creating a small module which will create a menu callback and then on that menu callback create a form using the drupal_get_form function. To create a module add a folder to your Drupal installation sites\all\modules\drupalform and add two files to it: drupalform.info and drupalform.module with the following code:

drupalform.info

name = drupalform
description = This module creates a form using Drupal.
core = 7.x

drupalform.module

<?php
/**
 * @file
 * This is the main module file.
 */

 /**
 * Implements hook_help().
 */
function drupalform_help($path, $arg) {

  if ($path == 'admin/help#rupalform') {
    $output = '<h3>' . t('About') . '</h3>';
    $output .= '<p>' . t('The drupalform module shows how to create forms using Drupal.') . '</p>';
    return $output;
  }
}

With the above code you should be able to see your module in the available module list and should be able to enable it as shown below. If these steps seem mysterious or complicated, please see my last tutorial for a good Drupal Module introduction.

Once we have done this we will add a menu callback using hook_menu and create a form on the page. The code for that is as follows

/**
* Implementation of hook_menu().
*/
function drupalform_menu() {
  $items['drupalform/form1'] = array(
        'type' => MENU_CALLBACK,
        'access arguments' => array('access content'),
        'page callback' => 'drupal_get_form',
        'page arguments'=>array('drupalform_form1'));

  return $items;
}

function drupalform_form1() {
    $form = array();


    $form['name']=array(
        '#type'=>'textfield',
        '#title'=>t('Enter your name'),
        '#description'=>t('Your first name goes here')
      );
    $form['last_name']=array(
        '#type'=>'textfield',
        '#title'=>t('Enter your Last name'),
        '#description'=>t('Your Last name goes here')
      );

     $form['email']=array(
        '#type'=>'textfield',
        '#title'=>t('Enter your email'),
        '#description'=>t('Your email goes here')
      );

    $form['country']=array(
        '#type'=>'select',
        '#title'=>t('Select your country'),
        '#options'=>array('USA','UK','France','Japan')
      );

    $form['submit']=array(
        '#type'=>'submit',
        '#value'=>t('Submit')
      );

      return $form;
}

In the above code in the implementation of hook_menu we create a menu item whose page_callback is drupal_get_form and the argument to that is the form_id "drupalform_form1". The function drupalform_form1 returns the form array which we want to create.

In the function drupalform_form1 we create three text fields: name, last_name, email, and one select box for the country. In the select box we specify the options of the country with an array. We have also added a Submit button, so the user can actually submit the form. Now you should be able to go to your menu url: <your drupal base url>/drupalform/form1 and see the form as follows

Validating a Drupal form

Drupal uses naming conventions heavily to identify which functions to call on which events. The complete Drupal hook system is based on naming conventions. Similarly, the function called to validate your form data has to follow the naming convention <form_id>_validate and it will be passed the form_state as a variable.

Hence, for our form the function name will be:
drupalform_form1_validate($form, $form_state).

The values which the user has entered will be present in an array $form_state['values'] with the same id as you specified in the form. So if we have to do the validations for our form the function will be:

function drupalform_form1_validate($form, $form_state) {

  if(empty($form_state['values']['name']))
     form_set_error('name','Name cannot be empty');
  else if(empty($form_state['values']['last_name']))
     form_set_error('last_name','Last name cannot be empty');
  else if(filter_var($form_state['values']['email'], FILTER_VALIDATE_EMAIL) == false)
    form_set_error('email','Email is not valid');
}

In the above function we check if the name and last_name are not empty and that the email is valid. If that is not the case we set a form error using the Drupal function form_set_error. This will display the error to the user and the form will not be submitted.

If you submit the form by entering an empty name you should see the following error on the screen:

Submitting a Drupal form

Similar to the validation function the submit function is also called based on the naming convention and the function name should be <form_id>_submit. Again, the variable $form_state will be passed to it. Our submit function will thus be defined as:

function drupalform_form1_submit($form, $form_state) {
   //Depending on the type of form you can add the logic
   //to store the details of the form 
   //by adding it in a Drupal table.
   //or sending a mail to the admin
   //Storing in a file
   //or pass it to some other service
   drupal_set_message("Form has been submitted");
}

Now if we pass all the valid fields you will get the following message on screen.

Using Field sets in Drupal Forms to separate elements.

Sometimes when the form is bigger and has many fields you might want to break it into small sections so that the form seems more logical to the user. To do this you can create fieldsets in Drupal to create groups of fields.

To create a fieldset called basicdetails to hold the fields we defined above we will have to update the drupalform_form1 as follows

function drupalform_form1() {
    $form = array();


     $form['basicdetails']=array(
        '#type'=>'fieldset',
        '#title'=>t('Enter your Basic details below'),
        '#description'=>t('These are all madatory')
      );

        $form['basicdetails']['name']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your name'),
            '#description'=>t('Your first name goes here')
          );
        $form['basicdetails']['last_name']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your Last name'),
            '#description'=>t('Your Last name goes here')
          );

         $form['basicdetails']['email']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your email'),
            '#description'=>t('Your email goes here')
          );


    $form['submit']=array(
        '#type'=>'submit',
        '#value'=>t('Submit')
      );

      return $form;
}

This will create a separate fieldset as shown below

The different form elements that can be used in Drupal forms

Drupal provides a great number of different types of fields which we can use in our forms. I will update our form to use some of these by creating two more field sets for address details and additional details.
The updated code is below:

function drupalform_form1() {
    $form = array();


     $form['basicdetails']=array(
        '#type'=>'fieldset',
        '#title'=>t('Enter your Basic details below'),
        '#description'=>t('These are all madatory')
      );

        $form['basicdetails']['name']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your name'),
            '#description'=>t('Your first name goes here')
          );
        $form['basicdetails']['last_name']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your Last name'),
            '#description'=>t('Your Last name goes here')
          );

         $form['basicdetails']['email']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your email'),
            '#description'=>t('Your email goes here')
          );

  $form['addressdetails']=array(
        '#type'=>'fieldset',
        '#title'=>t('Enter your Address details below'),
        '#description'=>t('These are all madatory')
      );

        $form['addressdetails']['country']=array(
            '#type'=>'select',
            '#title'=>t('Select your country'),
            '#options'=>array('USA','UK','France','Japan')
          );
        $form['addressdetails']['city']=array(
            '#type'=>'textfield',
            '#title'=>t('Enter your city'),
            '#description'=>t('Your city name goes here')
          );
        $form['addressdetails']['localaddress']=array(
            '#type'=>'textarea',
            '#title'=>t('Enter address'),
            '#description'=>t('Your Address name goes here')
          );

     $form['additionaldetails']=array(
        '#type'=>'fieldset',
        '#title'=>t('Enter your other details below'),
        '#description'=>t('These are all optional')
      );

        $form['additionaldetails']['gender']=array(
            '#type'=>'radios',
            '#title'=>t('Gender'),
            '#options'=>array('Male','Female')
          );

        $form['additionaldetails']['suscribtion']=array(
            '#type'=>'checkboxes',
            '#title'=>t('I want to subscribe for'),
            '#options'=>array('Email newsletter','Offer vouchers')
          );

        $form['additionaldetails']['birthdate']=array(
            '#type'=>'date',
            '#title'=>t('Birthdate'),
          );

        $form['#attributes']['enctype'] = 'multipart/form-data';

         $form['additionaldetails']['picture']=array(
            '#type'=>'file',
            '#title'=>t('Upload your picture'),
          );



    $form['submit']=array(
        '#type'=>'submit',
        '#value'=>t('Submit')
      );

      return $form;
}

This is what the new fieldsets look like:

Conclusion

Drupal helps you create and process forms right inside your module. The APIs Drupal offers make it very simple to make an addition or modification of your form as the forms are arrays and even the validation and submission happens in a different function. This modular approach keeps the form code in your module clean and easy to maintain. You also do not need to bother with the HTML details of the form if you use the Drupal form API – all the HTML is auto-generated. Have fun creating your next form in your Drupal module!

If you'd like us to cover a more specific use case or go into more details, or just have feedback, let us know in the comments below!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.