OpenApi Gen: add toString method for easier testing
[dokuwiki.git] / inc / Form / DropdownElement.php
blob4e892734c988e50e69d1daa16fc9df121f3e3bfb
1 <?php
3 namespace dokuwiki\Form;
5 /**
6 * Class DropdownElement
8 * Represents a HTML select. Please not that prefilling with input data only works for single values.
10 * @package dokuwiki\Form
12 class DropdownElement extends InputElement
14 /** @var array OptGroup[] */
15 protected $optGroups = [];
17 /** @var string[] the currently set values */
18 protected $values = [];
20 /**
21 * @param string $name The name of this form element
22 * @param array $options The available options
23 * @param string $label The label text for this element (will be autoescaped)
25 public function __construct($name, $options, $label = '')
27 parent::__construct('dropdown', $name, $label);
28 $this->rmattr('type');
29 $this->optGroups[''] = new OptGroup(null, $options);
30 $this->val('');
33 /**
34 * Add an `<optgroup>` and respective options
36 * @param string $label
37 * @param array $options
38 * @return OptGroup a reference to the added optgroup
39 * @throws \InvalidArgumentException
41 public function addOptGroup($label, $options)
43 if (empty($label)) {
44 throw new \InvalidArgumentException(hsc('<optgroup> must have a label!'));
46 $this->optGroups[$label] = new OptGroup($label, $options);
47 return end($this->optGroups);
50 /**
51 * Set or get the optgroups of an Dropdown-Element.
53 * optgroups have to be given as associative array
54 * * the key being the label of the group
55 * * the value being an array of options as defined in @param null|array $optGroups
56 * @return OptGroup[]|DropdownElement
57 * @see OptGroup::options()
60 public function optGroups($optGroups = null)
62 if ($optGroups === null) {
63 return $this->optGroups;
65 if (!is_array($optGroups)) {
66 throw new \InvalidArgumentException(hsc('Argument must be an associative array of label => [options]!'));
68 $this->optGroups = [];
69 foreach ($optGroups as $label => $options) {
70 $this->addOptGroup($label, $options);
72 return $this;
75 /**
76 * Get or set the options of the Dropdown
78 * Options can be given as associative array (value => label) or as an
79 * indexd array (label = value) or as an array of arrays. In the latter
80 * case an element has to look as follows:
81 * option-value => array (
82 * 'label' => option-label,
83 * 'attrs' => array (
84 * attr-key => attr-value, ...
85 * )
86 * )
88 * @param null|array $options
89 * @return $this|array
91 public function options($options = null)
93 if ($options === null) {
94 return $this->optGroups['']->options();
96 $this->optGroups[''] = new OptGroup(null, $options);
97 return $this;
101 * Get or set the current value
103 * When setting a value that is not defined in the options, the value is ignored
104 * and the first option's value is selected instead
106 * @param null|string|string[] $value The value to set
107 * @return $this|string|string[]
109 public function val($value = null)
111 // getter
112 if ($value === null) {
113 if (isset($this->attributes['multiple'])) {
114 return $this->values;
115 } else {
116 return $this->values[0];
120 // setter
121 $this->values = $this->setValuesInOptGroups((array) $value);
122 if (!$this->values) {
123 // unknown value set, select first option instead
124 $this->values = $this->setValuesInOptGroups((array) $this->getFirstOptionKey());
127 return $this;
131 * Returns the first option's key
133 * @return string
135 protected function getFirstOptionKey()
137 $options = $this->options();
138 if (!empty($options)) {
139 $keys = array_keys($options);
140 return (string)array_shift($keys);
142 foreach ($this->optGroups as $optGroup) {
143 $options = $optGroup->options();
144 if (!empty($options)) {
145 $keys = array_keys($options);
146 return (string)array_shift($keys);
150 return ''; // should not happen
154 * Set the value in the OptGroups, including the optgroup for the options without optgroup.
156 * @param string[] $values The values to be set
157 * @return string[] The values actually set
159 protected function setValuesInOptGroups($values)
161 $valueset = [];
163 /** @var OptGroup $optGroup */
164 foreach ($this->optGroups as $optGroup) {
165 $found = $optGroup->storeValues($values);
166 $values = array_diff($values, $found);
167 $valueset = array_merge($valueset, $found);
170 return $valueset;
174 * Create the HTML for the select it self
176 * @return string
178 protected function mainElementHTML()
180 $attr = $this->attrs();
181 if (isset($attr['multiple'])) {
182 // use array notation when multiple values are allowed
183 $attr['name'] .= '[]';
184 } elseif ($this->useInput) {
185 // prefilling is only supported for non-multi fields
186 $this->prefillInput();
189 $html = '<select ' . buildAttributes($attr) . '>';
190 $html = array_reduce(
191 $this->optGroups,
192 static fn($html, OptGroup $optGroup) => $html . $optGroup->toHTML(),
193 $html
195 $html .= '</select>';
197 return $html;