3 namespace Drupal\Core\Render\Element;
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\Core\Render\BubbleableMetadata;
10 * Provides a base class for form element plugins.
12 * Form elements are a subset of render elements, representing elements for
13 * HTML forms, which can be referenced in form arrays. See the
14 * @link theme_render Render API topic @endlink for an overview of render
15 * arrays and render elements, and the @link form_api Form API topic @endlink
16 * for an overview of forms and form arrays.
18 * The elements of form arrays are divided up into properties (whose keys
19 * start with #) and children (whose keys do not start with #). The properties
20 * provide data or settings that are used in rendering and form processing.
21 * Some properties are specific to a particular type of form/render element,
22 * some are available for any render element, and some are available for any
23 * form input element. A list of the properties that are available for all form
24 * elements follows; see \Drupal\Core\Render\Element\RenderElement for some
25 * additional information, as well as a list of properties that are common to
26 * all render elements (including form elements). Properties specific to a
27 * particular element are documented on that element's class.
29 * Here is a list of properties that are used during the rendering and form
30 * processing of form elements:
31 * - #after_build: (array) Array of callables or function names, which are
32 * called after the element is built. Arguments: $element, $form_state.
33 * - #ajax: (array) Array of elements to specify Ajax behavior. See
34 * the @link ajax Ajax API topic @endlink for more information.
35 * - #array_parents: (string[], read-only) Array of names of all the element's
36 * parents (including itself) in the render array. See also #parents, #tree.
37 * - #default_value: Default value for the element. See also #value.
38 * - #description: (string) Help or description text for the element. In an
39 * ideal user interface, the #title should be enough to describe the element,
40 * so most elements should not have a description; if you do need one, make
41 * sure it is translated. If it is not already wrapped in a safe markup
42 * object, it will be filtered for XSS safety.
43 * - #disabled: (bool) If TRUE, the element is shown but does not accept
45 * - #element_validate: (array) Array of callables or function names, which
46 * are called to validate the input. Arguments: $element, $form_state, $form.
47 * - #field_prefix: (string) Prefix to display before the HTML input element.
48 * Should be translated, normally. If it is not already wrapped in a safe
49 * markup object, will be filtered for XSS safety.
50 * - #field_suffix: (string) Suffix to display after the HTML input element.
51 * Should be translated, normally. If it is not already wrapped in a safe
52 * markup object, will be filtered for XSS safety.
53 * - #input: (bool, internal) Whether or not the element accepts input.
54 * - #parents: (string[], read-only) Array of names of the element's parents
55 * for purposes of getting values out of $form_state. See also
56 * #array_parents, #tree.
57 * - #process: (array) Array of callables or function names, which are
58 * called during form building. Arguments: $element, $form_state, $form.
59 * - #processed: (bool, internal) Set to TRUE when the element is processed.
60 * - #required: (bool) Whether or not input is required on the element.
61 * - #states: (array) Information about JavaScript states, such as when to
62 * hide or show the element based on input on other elements.
63 * See drupal_process_states() for documentation.
64 * - #title: (string) Title of the form element. Should be translated.
65 * - #title_display: (string) Where and how to display the #title. Possible
67 * - before: Label goes before the element (default for most elements).
68 * - after: Label goes after the element (default for radio elements).
69 * - invisible: Label is there but is made invisible using CSS.
70 * - attribute: Make it the title attribute (hover tooltip).
71 * - #tree: (bool) TRUE if the values of this element and its children should
72 * be hierarchical in $form_state; FALSE if the values should be flat.
73 * See also #parents, #array_parents.
74 * - #value_callback: (callable) Callable or function name, which is called
75 * to transform the raw user input to the element's value. Arguments:
76 * $element, $input, $form_state.
78 * @see \Drupal\Core\Render\Annotation\FormElement
79 * @see \Drupal\Core\Render\Element\FormElementInterface
80 * @see \Drupal\Core\Render\ElementInfoManager
83 * @ingroup theme_render
85 abstract class FormElement extends RenderElement implements FormElementInterface {
90 public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
95 * #process callback for #pattern form element property.
97 * @param array $element
98 * An associative array containing the properties and children of the
99 * generic input element.
100 * @param \Drupal\Core\Form\FormStateInterface $form_state
101 * The current state of the form.
102 * @param array $complete_form
103 * The complete form structure.
106 * The processed element.
108 public static function processPattern(&$element, FormStateInterface $form_state, &$complete_form) {
109 if (isset($element['#pattern']) && !isset($element['#attributes']['pattern'])) {
110 $element['#attributes']['pattern'] = $element['#pattern'];
111 $element['#element_validate'][] = [get_called_class(), 'validatePattern'];
118 * #element_validate callback for #pattern form element property.
121 * An associative array containing the properties and children of the
122 * generic form element.
124 * The current state of the form.
125 * @param array $complete_form
126 * The complete form structure.
128 public static function validatePattern(&$element, FormStateInterface $form_state, &$complete_form) {
129 if ($element['#value'] !== '') {
130 // The pattern must match the entire string and should have the same
131 // behavior as the RegExp object in ECMA 262.
132 // - Use bracket-style delimiters to avoid introducing a special delimiter
133 // character like '/' that would have to be escaped.
134 // - Put in brackets so that the pattern can't interfere with what's
135 // prepended and appended.
136 $pattern = '{^(?:' . $element['#pattern'] . ')$}';
138 if (!preg_match($pattern, $element['#value'])) {
139 $form_state->setError($element, t('%name field is not in the right format.', ['%name' => $element['#title']]));
145 * Adds autocomplete functionality to elements.
147 * This sets up autocomplete functionality for elements with an
148 * #autocomplete_route_name property, using the #autocomplete_route_parameters
149 * property if present.
151 * For example, suppose your autocomplete route name is
152 * 'mymodule.autocomplete' and its path is
153 * '/mymodule/autocomplete/{a}/{b}'. In a form array, you would create a text
154 * field with properties:
156 * '#autocomplete_route_name' => 'mymodule.autocomplete',
157 * '#autocomplete_route_parameters' => array('a' => $some_key, 'b' => $some_id),
159 * If the user types "keywords" in that field, the full path called would be:
160 * 'mymodule_autocomplete/$some_key/$some_id?q=keywords'
162 * @param array $element
163 * The form element to process. Properties used:
164 * - #autocomplete_route_name: A route to be used as callback URL by the
165 * autocomplete JavaScript library.
166 * - #autocomplete_route_parameters: The parameters to be used in
167 * conjunction with the route name.
168 * @param \Drupal\Core\Form\FormStateInterface $form_state
169 * The current state of the form.
170 * @param array $complete_form
171 * The complete form structure.
176 public static function processAutocomplete(&$element, FormStateInterface $form_state, &$complete_form) {
180 if (!empty($element['#autocomplete_route_name'])) {
181 $parameters = isset($element['#autocomplete_route_parameters']) ? $element['#autocomplete_route_parameters'] : [];
182 $url = Url::fromRoute($element['#autocomplete_route_name'], $parameters)->toString(TRUE);
183 /** @var \Drupal\Core\Access\AccessManagerInterface $access_manager */
184 $access_manager = \Drupal::service('access_manager');
185 $access = $access_manager->checkNamedRoute($element['#autocomplete_route_name'], $parameters, \Drupal::currentUser(), TRUE);
189 $metadata = BubbleableMetadata::createFromRenderArray($element);
190 if ($access->isAllowed()) {
191 $element['#attributes']['class'][] = 'form-autocomplete';
192 $metadata->addAttachments(['library' => ['core/drupal.autocomplete']]);
193 // Provide a data attribute for the JavaScript behavior to bind to.
194 $element['#attributes']['data-autocomplete-path'] = $url->getGeneratedUrl();
195 $metadata = $metadata->merge($url);
198 ->merge(BubbleableMetadata::createFromObject($access))