FormBuilder::prepareForm

public FormBuilder::prepareForm($form_id, &$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.

Parameters

string $form_id: A unique string identifying the form for validation, submission, theming, and hook_form_alter functions.

array $form: An associative array containing the structure of the form.

\Drupal\Core\Form\FormStateInterface $form_state: The current state of the form. Passed in here so that hook_form_alter() calls can use it, as well.

Overrides FormBuilderInterface::prepareForm

File

core/lib/Drupal/Core/Form/FormBuilder.php, line 675

Class

FormBuilder
Provides form building and processing.

Namespace

Drupal\Core\Form

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
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
    $placeholder = 'form_action_' . hash('crc32b', __METHOD__);
 
    $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') {
    // Merges in a default, this means if you've explicitly set #token to the
    // the $form_id on a GET form, which we don't recommend, it will work.
    $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'] = array(
    '#type' => 'hidden',
    '#value' => $form['#build_id'],
    '#id' => $form['#build_id'],
    '#name' => 'form_build_id',
    // Form processing and validation requires this value, so ensure the
    // submitted form value appears literally, regardless of custom #tree
    // and #parents being set elsewhere.
    '#parents' => array('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 based on the form id.
      // Generates a placeholder based on the form ID.
      $placeholder = 'form_token_placeholder_' . hash('crc32b', $form_id);
      $form['#token'] = $placeholder;
 
      $form['form_token'] = array(
        '#id' => Html::getUniqueId('edit-' . $form_id . '-form-token'),
        '#type' => 'token',
        '#default_value' => $placeholder,
        // Form processing and validation requires this value, so ensure the
        // submitted form value appears literally, regardless of custom #tree
        // and #parents being set elsewhere.
        '#parents' => array('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. This ensures forms with a CSRF
        // token don't have poor cacheability.
        '#attached' => [
          'placeholders' => [
            $placeholder => [
              '#lazy_builder' => ['form_builder:renderFormTokenPlaceholder', [$placeholder]]
            ]
          ]
        ],
        '#cache' => [
          'max-age' => 0,
        ],
      );
    }
  }
 
  if (isset($form_id)) {
    $form['form_id'] = array(
      '#type' => 'hidden',
      '#value' => $form_id,
      '#id' => Html::getUniqueId("edit-$form_id"),
      // Form processing and validation requires this value, so ensure the
      // submitted form value appears literally, regardless of custom #tree
      // and #parents being set elsewhere.
      '#parents' => array('form_id'),
    );
  }
  if (!isset($form['#id'])) {
    $form['#id'] = Html::getUniqueId($form_id);
    // Provide a selector usable by JavaScript. As the ID is unique, its not
    // possible to rely on it in JavaScript.
    $form['#attributes']['data-drupal-selector'] = Html::getId($form_id);
  }
 
  $form += $this->elementInfo->getInfo('form');
  $form += array('#tree' => FALSE, '#parents' => array());
  $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'] = array($form_id);
    if (isset($build_info['base_form_id'])) {
      $form['#theme'][] = $build_info['base_form_id'];
    }
  }
 
  // Invoke hook_form_alter(), hook_form_BASE_FORM_ID_alter(), and
  // hook_form_FORM_ID_alter() implementations.
  $hooks = array('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);
}
doc_Drupal
2025-01-10 15:47:30
Comments
Leave a Comment

Please login to continue.