3 namespace Drupal\Core\Render\Element;
5 use Drupal\Core\Form\FormStateInterface;
6 use Drupal\Core\Render\Element;
9 * Provides a form element for a drop-down menu or scrolling selection box.
12 * - #options: An associative array, where the keys are the values for each
13 * option, and the values are the option labels to be shown in the drop-down
14 * list. If a value is an array, it will be rendered similarly, but as an
15 * optgroup. The key of the sub-array will be used as the label for the
16 * optgroup. Nesting optgroups is not allowed.
17 * - #empty_option: (optional) The label to show for the first default option.
18 * By default, the label is automatically set to "- Select -" for a required
19 * field and "- None -" for an optional field.
20 * - #empty_value: (optional) The value for the first default option, which is
21 * used to determine whether the user submitted a value or not.
22 * - If #required is TRUE, this defaults to '' (an empty string).
23 * - If #required is not TRUE and this value isn't set, then no extra option
24 * is added to the select control, leaving the control in a slightly
25 * illogical state, because there's no way for the user to select nothing,
26 * since all user agents automatically preselect the first available
27 * option. But people are used to this being the behavior of select
29 * @todo Address the above issue in Drupal 8.
30 * - If #required is not TRUE and this value is set (most commonly to an
31 * empty string), then an extra option (see #empty_option above)
32 * representing a "non-selection" is added with this as its value.
33 * - #multiple: (optional) Indicates whether one or more options can be
34 * selected. Defaults to FALSE.
35 * - #default_value: Must be NULL or not set in case there is no value for the
36 * element yet, in which case a first default option is inserted by default.
37 * Whether this first option is a valid option depends on whether the field
38 * is #required or not.
39 * - #required: (optional) Whether the user needs to select an option (TRUE)
40 * or not (FALSE). Defaults to FALSE.
41 * - #size: The size of the input element in characters.
45 * $form['example_select'] = [
46 * '#type' => 'select',
47 * '#title' => $this->t('Select element'),
49 * '1' => $this->t('One'),
51 * '2.1' => $this->t('Two point one'),
52 * '2.2' => $this->t('Two point two'),
54 * '3' => $this->t('Three'),
59 * @FormElement("select")
61 class Select extends FormElement {
66 public function getInfo() {
67 $class = get_class($this);
72 [$class, 'processSelect'],
73 [$class, 'processAjaxForm'],
76 [$class, 'preRenderSelect'],
79 '#theme_wrappers' => ['form_element'],
85 * Processes a select list form element.
87 * This process callback is mandatory for select fields, since all user agents
88 * automatically preselect the first available option of single (non-multiple)
91 * @param array $element
92 * The form element to process.
93 * @param \Drupal\Core\Form\FormStateInterface $form_state
94 * The current state of the form.
95 * @param array $complete_form
96 * The complete form structure.
99 * The processed element.
101 * @see _form_validate()
103 public static function processSelect(&$element, FormStateInterface $form_state, &$complete_form) {
104 // #multiple select fields need a special #name.
105 if ($element['#multiple']) {
106 $element['#attributes']['multiple'] = 'multiple';
107 $element['#attributes']['name'] = $element['#name'] . '[]';
109 // A non-#multiple select needs special handling to prevent user agents from
110 // preselecting the first option without intention. #multiple select lists do
111 // not get an empty option, as it would not make sense, user interface-wise.
113 // If the element is set to #required through #states, override the
114 // element's #required setting.
115 $required = isset($element['#states']['required']) ? TRUE : $element['#required'];
116 // If the element is required and there is no #default_value, then add an
117 // empty option that will fail validation, so that the user is required to
118 // make a choice. Also, if there's a value for #empty_value or
119 // #empty_option, then add an option that represents emptiness.
120 if (($required && !isset($element['#default_value'])) || isset($element['#empty_value']) || isset($element['#empty_option'])) {
122 '#empty_value' => '',
123 '#empty_option' => $required ? t('- Select -') : t('- None -'),
125 // The empty option is prepended to #options and purposively not merged
126 // to prevent another option in #options mistakenly using the same value
128 $empty_option = [$element['#empty_value'] => $element['#empty_option']];
129 $element['#options'] = $empty_option + $element['#options'];
138 public static function valueCallback(&$element, $input, FormStateInterface $form_state) {
139 if ($input !== FALSE) {
140 if (isset($element['#multiple']) && $element['#multiple']) {
141 // If an enabled multi-select submits NULL, it means all items are
142 // unselected. A disabled multi-select always submits NULL, and the
143 // default value should be used.
144 if (empty($element['#disabled'])) {
145 return (is_array($input)) ? array_combine($input, $input) : [];
148 return (isset($element['#default_value']) && is_array($element['#default_value'])) ? $element['#default_value'] : [];
151 // Non-multiple select elements may have an empty option prepended to them
152 // (see \Drupal\Core\Render\Element\Select::processSelect()). When this
153 // occurs, usually #empty_value is an empty string, but some forms set
154 // #empty_value to integer 0 or some other non-string constant. PHP
155 // receives all submitted form input as strings, but if the empty option
156 // is selected, set the value to match the empty value exactly.
157 elseif (isset($element['#empty_value']) && $input === (string) $element['#empty_value']) {
158 return $element['#empty_value'];
167 * Prepares a select render element.
169 public static function preRenderSelect($element) {
170 Element::setAttributes($element, ['id', 'name', 'size']);
171 static::setAttributes($element, ['form-select']);