Mechanism behind Drupal Forms

Mechanism behind Drupal Forms

Mechanism behind drupal forms

In Drupal 9 forms are also recreated with Object Oriented Programming in mind. The forms are now created as class and kept in the directory "/src/Form". The form we create will have to extend "FormBase" class and have the method "buildForm".

Standard Drupal Form

Let's say we want to create a form with basic input text and submit button. For this, we create a file in "/src/Form" called "MyForm.php". We setup the class by defining our namespace (usually it is Drupal\), create our class and extend "FormBase". If you have good IDE setup, it will automatically import the class and add default methods you need to implement. I recommend using PHPStorm for any php related development.

Here's its how a basic form looks like.

<?php

namespace Drupal\hello_world\Form;

use Drupal\Core\Form\FormBase;

class GreetingMailForm extends FormBase {

  public function getFormId()
  {
    return 'greeting_mail_form';
  }

  public function buildForm(array $form, \Drupal\Core\Form\FormStateInterface $form_state)
  {
    $form['send_email'] = array(
      '#type' => 'textfield',
      '#title' => 'Send Email',
      '#description' => t('The email will be sent to this email address'),
    );

    $form['message'] = array(
      '#type' => 'textarea',
      '#title' => t('Message'),
    );

    $form['submit'] = [
      '#type' => 'submit',
      '#value' => 'Go',
    ];

    return $form;
  }

  public function submitForm(array &$form, \Drupal\Core\Form\FormStateInterface $form_state)
  {
    $send = false;
    $sent_mail = $form_state->getValue('send_email');

    // send mail
    $message = $form_state->getValue('message');

    // prepare mail
    if ($send) {
      $to = $sent_mail;
      $langode = 'en';

      // send the mail
    }

    \Drupal::messenger()->addStatus('Mail sent to ' . $sent_mail);
  }
}

Here, the buildForm method returns an array and it is using form api standards to provide what kind of form element drupal should render. There are lot of form elements like checkbox, date, textarea, richtext and so on which you can find the following link. [ api.drupal.org/api/drupal/elements ]

Similar to buildForm method, we have two more methods "validateForm" and "submitForm" which can be used to do validation and submission respectively.

In conclusion, drupal forms needs to extend Form specific classes like FormBase, and use methods like "buildForm", "validateForm" and "submitForm" to handle its rendering and validations.

Bonus content!!

FormBase Class

Now we have basic understanding of a Drupal form lets dive more deep into it. Previously we extended FormBase class to create our form. Let's examine what that class gives us.

FormBase class is an abstract class, we can't make direct object from it but instead only extend it. It uses several traits to enhance the functionality of this form. For example, MessengerTrait helps to print message to the page after the form is submitted.

abstract class FormBase implements FormInterface, ContainerInjectionInterface {
  use DependencySerializationTrait;
  use LoggerChannelTrait;
  use MessengerTrait;
  use RedirectDestinationTrait;
  use StringTranslationTrait;
}

ConfigFormBase Class

Similarly drupal also provides another class called "ConfigFormBase" which is extended from FormBase class. This type of form is usually created for configuration of your pages or module. This class uses dependency injection for using Configuration API of drupal to store module related setting values.

In Drupal 8, you do not use the {variables} table and variable_get/set/delete() because configuration is stored in the database and synced with YML files on the disk for deployment purposes. It is possible to disable use of the database for config storage entirely but it comes with a performance hit with most filesystems.

abstract class ConfigFormBase extends FormBase {
  use ConfigFormBaseTrait;

  /**
   * Constructs a \Drupal\system\ConfigFormBase object.
   *
   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
   *   The factory for configuration objects.
   */
  public function __construct(ConfigFactoryInterface $config_factory) {
    $this->setConfigFactory($config_factory);
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('config.factory')
    );
  }
....

Thank you for reading through a long post. Your support is everything to me!!