function FormBuilder::prepareForm
Same name in other branches
- 9 core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::prepareForm()
- 8.9.x core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::prepareForm()
- 10 core/lib/Drupal/Core/Form/FormBuilder.php \Drupal\Core\Form\FormBuilder::prepareForm()
Overrides FormBuilderInterface::prepareForm
3 calls to FormBuilder::prepareForm()
- FormBuilder::buildForm in core/
lib/ Drupal/ Core/ Form/ FormBuilder.php - Builds and processes a form for a given form ID.
- FormBuilder::rebuildForm in core/
lib/ Drupal/ Core/ Form/ FormBuilder.php - Constructs a new $form from the information in $form_state.
- FormBuilder::submitForm in core/
lib/ Drupal/ Core/ Form/ FormBuilder.php - Retrieves, populates, and processes a form.
File
-
core/
lib/ Drupal/ Core/ Form/ FormBuilder.php, line 679
Class
- FormBuilder
- Provides form building and processing.
Namespace
Drupal\Core\FormCode
public function prepareForm($form_id, &$form, FormStateInterface &$form_state) {
$user = $this->currentUser();
$form['#type'] = 'form';
// Only update the action if it is not already set.
if (!isset($form['#action'])) {
// Instead of setting an actual action URL, we set the placeholder, which
// will be replaced at the very last moment. This ensures forms with
// dynamically generated action URLs don't have poor cacheability.
// Use the proper API to generate the placeholder, when we have one.
// See https://www.drupal.org/node/2562341.
// The placeholder uses a unique string that is returned by
// Crypt::hashBase64('Drupal\Core\Form\FormBuilder::prepareForm').
// cspell:disable-next-line
$placeholder = 'form_action_p_pvdeGsVG5zNF_XLGPTvYSKCf43t8qZYSwcfZl2uzM';
$form['#attached']['placeholders'][$placeholder] = [
'#lazy_builder' => [
'form_builder:renderPlaceholderFormAction',
[],
],
];
$form['#action'] = $placeholder;
}
// Fix the form method, if it is 'get' in $form_state, but not in $form.
if ($form_state->isMethodType('get') && !isset($form['#method'])) {
$form['#method'] = 'get';
}
// GET forms should not use a CSRF token.
if (isset($form['#method']) && $form['#method'] === 'get') {
$form += [
'#token' => FALSE,
];
}
// Generate a new #build_id for this form, if none has been set already.
// The form_build_id is used as key to cache a particular build of the form.
// For multi-step forms, this allows the user to go back to an earlier
// build, make changes, and re-submit.
// @see self::buildForm()
// @see self::rebuildForm()
if (!isset($form['#build_id'])) {
$form['#build_id'] = 'form-' . Crypt::randomBytesBase64();
}
$form['form_build_id'] = [
'#type' => 'hidden',
'#value' => $form['#build_id'],
'#id' => $form['#build_id'],
'#name' => 'form_build_id',
// Form processing and validation require this value. Ensure the
// submitted form value appears literally, regardless of custom #tree
// and #parents being set elsewhere.
'#parents' => [
'form_build_id',
],
];
// Add a token, based on either #token or form_id, to any form displayed to
// authenticated users. This ensures that any submitted form was actually
// requested previously by the user and protects against cross site request
// forgeries.
// This does not apply to programmatically submitted forms. Furthermore,
// since tokens are session-bound and forms displayed to anonymous users are
// very likely cached, we cannot assign a token for them.
// During installation, there is no $user yet.
// Form constructors may explicitly set #token to FALSE when cross site
// request forgery is irrelevant to the form, such as search forms.
if ($form_state->isProgrammed() || isset($form['#token']) && $form['#token'] === FALSE) {
unset($form['#token']);
}
else {
$form['#cache']['contexts'][] = 'user.roles:authenticated';
if ($user && $user->isAuthenticated()) {
// Generate a public token and placeholder based on the form ID.
$placeholder = 'form_token_placeholder_' . Crypt::hashBase64($form_id);
$form['#token'] = $placeholder;
$form['form_token'] = [
'#id' => Html::getUniqueId('edit-' . $form_id . '-form-token'),
'#type' => 'token',
'#default_value' => $placeholder,
// Form processing and validation require this value. Ensure the
// submitted form value appears literally, regardless of custom #tree
// and #parents being set elsewhere.
'#parents' => [
'form_token',
],
// Instead of setting an actual CSRF token, we've set the placeholder
// in form_token's #default_value and #placeholder. These will be
// replaced at the very last moment to ensure forms with a CSRF token
// don't have poor cacheability.
'#attached' => [
'placeholders' => [
$placeholder => [
'#lazy_builder' => [
'form_builder:renderFormTokenPlaceholder',
[
$placeholder,
],
],
],
],
],
];
// If a form hasn't explicitly opted in to caching by setting max-age at
// the top level, then make it uncacheable in case it doesn't have the
// correct cacheability metadata.
// @todo Remove this in the next major version, after the deprecation
// process from https://www.drupal.org/project/drupal/issues/3395157
// has ended.
if (!isset($form['#cache']['max-age'])) {
$form['form_token']['#cache']['max-age'] = 0;
}
}
}
if (isset($form_id)) {
$form['form_id'] = [
'#type' => 'hidden',
'#value' => $form_id,
'#id' => Html::getUniqueId("edit-{$form_id}"),
// Form processing and validation require this value. Ensure the
// submitted form value appears literally, regardless of custom #tree
// and #parents being set elsewhere.
'#parents' => [
'form_id',
],
];
}
if (!isset($form['#id'])) {
$form['#id'] = Html::getUniqueId($form_id);
// Provide a selector usable by JavaScript. As the ID is unique, it's not
// possible to rely on it in JavaScript.
$form['#attributes']['data-drupal-selector'] = Html::getId($form_id);
}
$form += $this->elementInfo
->getInfo('form');
$form += [
'#tree' => FALSE,
'#parents' => [],
];
$form['#validate'][] = '::validateForm';
$form['#submit'][] = '::submitForm';
$build_info = $form_state->getBuildInfo();
// If no #theme has been set, automatically apply theme suggestions.
// The form theme hook itself, which is rendered by form.html.twig,
// is in #theme_wrappers. Therefore, the #theme function only has to care
// for rendering the inner form elements, not the form itself.
if (!isset($form['#theme'])) {
$form['#theme'] = [
$form_id,
];
if (isset($build_info['base_form_id'])) {
$form['#theme'][] = $build_info['base_form_id'];
}
}
// Add the 'CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:form' cache tag to
// identify this render array as a form to the render cache.
$form['#cache']['tags'][] = 'CACHE_MISS_IF_UNCACHEABLE_HTTP_METHOD:form';
// Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and
// hook_form_FORM_ID_alter() implementations.
$hooks = [
'form',
];
if (isset($build_info['base_form_id'])) {
$hooks[] = 'form_' . $build_info['base_form_id'];
}
$hooks[] = 'form_' . $form_id;
$this->moduleHandler
->alter($hooks, $form, $form_state, $form_id);
$this->themeManager
->alter($hooks, $form, $form_state, $form_id);
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.