FormBuilderInterface
interface FormBuilderInterface (View source)
Provides an interface for form building and processing.
Constants
| AJAX_FORM_REQUEST |
Request key for AJAX forms that submit to the form's original route. This constant is distinct from a "drupal_ajax" value for \Drupal\Core\EventSubscriber\MainContentViewSubscriber::WRAPPER_FORMAT, because that one is set for all AJAX submissions, including ones with dedicated routes for which self::buildForm() should not exit early via a \Drupal\Core\Form\FormAjaxException. |
Methods
Determines the ID of a form.
Builds and processes a form for a given form ID.
Constructs a new $form from the information in $form_state.
Retrieves, populates, and processes a form.
Retrieves the structured array that defines a given form.
Processes a form submission.
Prepares a structured form array.
Builds and processes all elements in the structured form array.
Details
string
getFormId(FormInterface|string $form_arg, FormStateInterface $form_state)
Determines the ID of a form.
array
getForm(FormInterface|string $form_arg)
Gets a renderable form array.
This function should be used instead of self::buildForm() when $form_state is not needed (i.e., when initially rendering the form) and is often used as a menu callback.
array
buildForm(FormInterface|string $form_arg, FormStateInterface $form_state)
Builds and processes a form for a given form ID.
The form may also be retrieved from the cache if the form was built in a previous page load. The form is then passed on for processing, validation, and submission if there is proper input.
array
rebuildForm(string $form_id, FormStateInterface $form_state, array|null $old_form = NULL)
Constructs a new $form from the information in $form_state.
This is the key function for making multi-step forms advance from step to step. It is called by self::processForm() when all user input processing, including calling validation and submission handlers, for the request is finished. If a validate or submit handler set $form_state->isRebuilding() to TRUE, and if other conditions don't preempt a rebuild from happening, then this function is called to generate a new $form, the next step in the form workflow, to be returned for rendering.
Ajax form submissions are almost always multi-step workflows, so that is one common use-case during which form rebuilding occurs.
submitForm(FormInterface|string $form_arg, FormStateInterface $form_state)
Retrieves, populates, and processes a form.
This function allows you to supply values for form elements and submit a form for processing. Compare to self::getForm(), which also builds and processes a form, but does not allow you to supply values.
There is no return value, but you can check to see if there are errors by calling $form_state->getErrors().
For example:
mixed|Response
retrieveForm(string $form_id, FormStateInterface $form_state)
Retrieves the structured array that defines a given form.
RedirectResponse|null
processForm(string $form_id, array $form, FormStateInterface $form_state)
Processes a form submission.
This function is the heart of form API. The form gets built, validated and in appropriate cases, submitted and rebuilt.
prepareForm(string $form_id, array $form, FormStateInterface $form_state)
Prepares a structured form array.
Adds required elements, executes any hook_form_alter functions, and optionally inserts a validation token to prevent tampering.
array
doBuildForm(string $form_id, array $element, FormStateInterface $form_state)
Builds and processes all elements in the structured form array.
Adds any required properties to each element, maps the incoming input data to the proper elements, and executes any #process handlers attached to a specific element.
This is one of the three primary functions that recursively iterates a form array. This one does it for completing the form building process. The other two are self::doValidateForm() (invoked via self::validateForm() and used to invoke validation logic for each element) and RendererInterface::render() (for rendering each element). Each of these three pipelines provides ample opportunity for modules to customize what happens. For example, during this function's life cycle, the following functions get called for each element:
- $element['#value_callback']: A callable that implements how user input is mapped to an element's #value property. This defaults to a function named 'form_type_TYPE_value' where TYPE is $element['#type'].
- $element['#process']: An array of functions called after user input has been mapped to the element's #value property. These functions can be used to dynamically add child elements: for example, for the 'date' element type, one of the functions in this array is form_process_datetime(), which adds the individual 'date', and 'time'. child elements. These functions can also be used to set additional properties or implement special logic other than adding child elements: for example, for the 'details' element type, one of the functions in this array is form_process_details(), which adds the attributes and JavaScript needed to make the details work in older browsers. The #process functions are called in preorder traversal, meaning they are called for the parent element first, then for the child elements.
- $element['#after_build']: An array of callables called after self::doBuildForm() is done with its processing of the element. These are called in postorder traversal, meaning they are called for the child elements first, then for the parent element. There are similar properties containing callback functions invoked by self::doValidateForm() and RendererInterface::render(), appropriate for those operations.
Developers are strongly encouraged to integrate the functionality needed by their form or module within one of these three pipelines, using the appropriate callback property, rather than implementing their own recursive traversal of a form array. This facilitates proper integration between multiple modules. For example, module developers are familiar with the relative order in which hook_form_alter() implementations and #process functions run. A custom traversal function that affects the building of a form is likely to not integrate with hook_form_alter() and #process in the expected way. Also, deep recursion within PHP is both slow and memory intensive, so it is best to minimize how often it's done.
As stated above, each element's #process functions are executed after its
value has been set. This enables those functions to execute conditional
logic based on the current value. However, all of self::doBuildForm() runs before self::validateForm() is called, so during #process function execution, the element's #value has not yet been validated, so any code that requires validated values must reside within a submit handler.
As a security measure, user input is used for an element's #value only if the element exists within $form, is not disabled (as per the #disabled property), and can be accessed (as per the #access property, except that forms submitted using self::submitForm() bypass #access restrictions). When user input is ignored due to #disabled and #access restrictions, the element's default value is used.
Because of the preorder traversal, where #process functions of an element run before user input for its child elements is processed, and because of the Form API security of user input processing with respect to #access and
disabled described above, this generally means that #process functions
should not use an element's (unvalidated) #value to affect the #disabled or
access of child elements. Use-cases where a developer may be tempted to
implement such conditional logic usually fall into one of two categories:
- Where user input from the current submission must affect the structure of a form, including properties like #access and #disabled that affect how the next submission needs to be processed, a multi-step workflow is needed. This is most commonly implemented with a submit handler setting persistent data within $form_state based on validated values in $form_state->getValues() and checking $form_state->isRebuilding(). The form building functions must then be implemented to use the $form_state to rebuild the form with the structure appropriate for the new state.
- Where user input must affect the rendering of the form without affecting
its structure, the necessary conditional rendering logic should reside
within functions that run during the rendering phase (#pre_render,
theme, #theme_wrappers, and #post_render).