-
Notifications
You must be signed in to change notification settings - Fork 811
Expand file tree
/
Copy pathSelectField.php
More file actions
274 lines (242 loc) · 7.05 KB
/
Copy pathSelectField.php
File metadata and controls
274 lines (242 loc) · 7.05 KB
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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
<?php
namespace SilverStripe\Forms;
use SilverStripe\ORM\SS_List;
use SilverStripe\ORM\Map;
use ArrayAccess;
/**
* Represents a field that allows users to select one or more items from a list
*/
abstract class SelectField extends FormField
{
/**
* Associative or numeric array of all dropdown items,
* with array key as the submitted field value, and the array value as a
* natural language description shown in the interface element.
*
* @var array|ArrayAccess
*/
protected $source;
/**
* The values for items that should be disabled (greyed out) in the dropdown.
* This is a non-associative array
*
* @var array
*/
protected $disabledItems = [];
/**
* @param string $name The field name
* @param string $title The field title
* @param array|ArrayAccess $source A map of the dropdown items
* @param mixed $value The current value
*/
public function __construct($name, $title = null, $source = [], $value = null)
{
$this->setSource($source);
if (!isset($title)) {
$title = $name;
}
parent::__construct($name, $title, $value);
}
public function getSchemaStateDefaults()
{
$data = parent::getSchemaStateDefaults();
$disabled = $this->getDisabledItems();
// Add options to 'data'
$source = $this->getSource();
$data['source'] = (is_array($source))
? array_map(function ($value, $title) use ($disabled) {
return [
'value' => $value,
'title' => $title,
'disabled' => in_array($value, $disabled),
];
}, array_keys($source), $source)
: [];
return $data;
}
/**
* Mark certain elements as disabled,
* regardless of the {@link setDisabled()} settings.
*
* These should be items that appear in the source list, not in addition to them.
*
* @param array|SS_List $items Collection of values or items
* @return $this
*/
public function setDisabledItems($items)
{
$this->disabledItems = $this->getListValues($items);
return $this;
}
/**
* Non-associative list of disabled item values
*
* @return array
*/
public function getDisabledItems()
{
return $this->disabledItems;
}
/**
* Check if the given value is disabled
*
* @param string $value
* @return bool
*/
protected function isDisabledValue($value)
{
if ($this->isDisabled()) {
return true;
}
return in_array($value, $this->getDisabledItems() ?? []);
}
public function getAttributes()
{
return array_merge(
parent::getAttributes(),
['type' => null, 'value' => null]
);
}
/**
* Retrieve all values in the source array
*
* @return array
*/
protected function getSourceValues()
{
return array_keys($this->getSource() ?? []);
}
/**
* Gets all valid values for this field.
*
* Does not include "empty" value if specified
*
* @return array
*/
public function getValidValues()
{
$valid = array_diff($this->getSourceValues() ?? [], $this->getDisabledItems());
// Renumber indexes from 0
return array_values($valid ?? []);
}
/**
* Gets the source array not including any empty default values.
*
* @return array|ArrayAccess
*/
public function getSource()
{
return $this->source;
}
/**
* Set the source for this list
*
* @param mixed $source
* @return $this
*/
public function setSource($source)
{
$this->source = $this->getListMap($source);
return $this;
}
/**
* Given a list of values, extract the associative map of id => title
*
* @param mixed $source
* @return array Associative array of ids and titles
*/
protected function getListMap($source)
{
// Extract source as an array
if ($source instanceof SS_List) {
$source = $source->map();
}
if ($source instanceof Map) {
$source = $source->toArray();
}
if (!is_array($source) && !($source instanceof ArrayAccess)) {
throw new \InvalidArgumentException('$source passed in as invalid type');
}
return $source;
}
/**
* Given a non-array collection, extract the non-associative list of ids
* If passing as array, treat the array values (not the keys) as the ids
*
* @param mixed $values
* @return array Non-associative list of values
*/
protected function getListValues($values)
{
// Empty values
if (empty($values)) {
return [];
}
// Direct array
if (is_array($values)) {
return array_values($values ?? []);
}
// Extract lists
if ($values instanceof SS_List) {
return $values->column('ID');
}
return [trim($values ?? '')];
}
/**
* Determine if the current value of this field matches the given option value
*
* @param mixed $dataValue The value as extracted from the source of this field (or empty value if available)
* @param mixed $userValue The value as submitted by the user
* @return boolean True if the selected value matches the given option value
*/
public function isSelectedValue($dataValue, $userValue)
{
if ($dataValue === $userValue) {
return true;
}
// Allow null to match empty strings
if ($dataValue === '' && $userValue === null) {
return true;
}
// Safety check against casting arrays as strings in PHP>5.4
if (is_array($dataValue) || is_array($userValue)) {
return false;
}
// For non-falsey values do loose comparison
if ($dataValue) {
return $dataValue == $userValue;
}
// For empty values, use string comparison to perform visible value match
return ((string) $dataValue) === ((string) $userValue);
}
public function performReadonlyTransformation()
{
/** @var LookupField $field */
$field = $this->castedCopy('SilverStripe\\Forms\\LookupField');
$field->setSource($this->getSource());
$field->setReadonly(true);
return $field;
}
public function performDisabledTransformation()
{
$clone = clone $this;
$clone->setDisabled(true);
return $clone;
}
/**
* Returns another instance of this field, but "cast" to a different class.
*
* @see FormField::castedCopy()
*
* @param string $classOrCopy
* @return FormField
*/
public function castedCopy($classOrCopy)
{
$field = parent::castedCopy($classOrCopy);
if ($field instanceof SelectField) {
$field->setSource($this->getSource());
}
return $field;
}
}