The Form API in Drupal 8 has taken steps towards an object oriented architecture, forms now being defined as classes. With this come many of the OOP benefits such as dependency injection and testability.
Form classes need to implement \Drupal\Core\Form\FormInterface
but typically extend Drupal\Core\Form\FormBase
. As such there are a few methods that need to be implemented for processing of a form.
The concepts, however, are similar to Drupal 7:
- A form has an ID -> the
getFormId()
method - A form is defined as a multitude of form elements (render array) -> the
buildForm(array $form, FormStateInterface $form_state)
method - A form can be validated before it is submitted -> the
validateForm(array &$form, FormStateInterface $form_state)
method - A form is submitted -> the
submitForm(array &$form, FormStateInterface $form_state)
method
Another difference is that the form state is no longer an array but a Drupal\Core\Form\FormStateInterface
object.
For an example of a simple form definition and the methods that can/need to be implemented in a form, check out this page.
A form definition is a collection of form elements, defined as arrays. Just like in Drupal 7, the Form API comes with a number of form elements by default.
See here the complete list of form elements provided by core. Look for the ones of the type FormElement
.
Form elements (FormElementInterface
) extend render elements (ElementInterface
) and integrate with the render system. // @todo add link to theming entry
The best way to discover how to use a particular form element (or render element for that mater) is to inspect the class and its documentation. For example, the textfield
form element is defined in Drupal\Core\Render\Element\Textfield
and an example of how it's used can be found in the class documentation.
There are 2 main ways to build and render a form: from a route definition (form page) or programmatically.
Forms can be mapped to a route by using the _form
key inside the defaults
section of the route definition. See this example and read more about the routing system.
Forms can also be retrieved and rendered from controllers and other places. The Drupal\Core\Form\FormBuilder
service can be used for this (service key: form_builder
). See an example here.
Just like in Drupal 7, the forms can be altered using hook_form_alter(), hook_form_FORM_ID_alter() and hook_form_BASE_FORM_ID_alter().
Typically, forms in Drupal 8 extend Drupal\Core\Form\FormBase
. However, there are a few other base classes that can be used depending on the purpose of the form:
Drupal\Core\Form\ConfigFormBase
-> provides defaults for interacting with the configuration API for storing config defined via the formDrupal\Core\Form\ConfirmFormBase
-> provides defaults for creating a confirmation form (see here an example on how to use this)