1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace SilverStripe\ORM\FieldType; |
4
|
|
|
|
5
|
|
|
use SilverStripe\Core\Config\Config; |
6
|
|
|
use SilverStripe\Forms\DropdownField; |
7
|
|
|
use SilverStripe\ORM\ArrayLib; |
8
|
|
|
use SilverStripe\ORM\DB; |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Class Enum represents an enumeration of a set of strings. |
12
|
|
|
* |
13
|
|
|
* See {@link DropdownField} for a {@link FormField} to select enum values. |
14
|
|
|
*/ |
15
|
|
|
class DBEnum extends DBString |
16
|
|
|
{ |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* List of enum values |
20
|
|
|
* |
21
|
|
|
* @var array |
22
|
|
|
*/ |
23
|
|
|
protected $enum = []; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* Default value |
27
|
|
|
* |
28
|
|
|
* @var string|null |
29
|
|
|
*/ |
30
|
|
|
protected $default = null; |
31
|
|
|
|
32
|
|
|
private static $default_search_filter_class = 'ExactMatchFilter'; |
|
|
|
|
33
|
|
|
|
34
|
|
|
/** |
35
|
|
|
* Internal cache for obsolete enum values. The top level keys are the table, each of which contains |
36
|
|
|
* nested arrays with keys mapped to field names. The values of the lowest level array are the enum values |
37
|
|
|
* |
38
|
|
|
* @var array |
39
|
|
|
*/ |
40
|
|
|
protected static $enum_cache = []; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Clear all cached enum values. |
44
|
|
|
*/ |
45
|
|
|
public static function flushCache() |
46
|
|
|
{ |
47
|
|
|
self::$enum_cache = []; |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Create a new Enum field, which is a value within a defined set, with an optional default. |
52
|
|
|
* |
53
|
|
|
* Example field specification strings: |
54
|
|
|
* |
55
|
|
|
* <code> |
56
|
|
|
* "MyField" => "Enum('Val1, Val2, Val3')" // First item 'Val1' is default implicitly |
57
|
|
|
* "MyField" => "Enum('Val1, Val2, Val3', 'Val2')" // 'Val2' is default explicitly |
58
|
|
|
* "MyField" => "Enum('Val1, Val2, Val3', null)" // Force empty (no) default |
59
|
|
|
* "MyField" => "Enum(array('Val1', 'Val2', 'Val3'), 'Val1')" // Supports array notation as well |
60
|
|
|
* </code> |
61
|
|
|
* |
62
|
|
|
* @param string $name |
63
|
|
|
* @param string|array $enum A string containing a comma separated list of options or an array of Vals. |
64
|
|
|
* @param string|int|null $default The default option, which is either NULL or one of the items in the enumeration. |
65
|
|
|
* If passing in an integer (non-string) it will default to the index of that item in the list. |
66
|
|
|
* Set to null or empty string to allow empty values |
67
|
|
|
* @param array $options Optional parameters for this DB field |
68
|
|
|
*/ |
69
|
|
|
public function __construct($name = null, $enum = null, $default = 0, $options = []) |
70
|
|
|
{ |
71
|
|
|
if ($enum) { |
72
|
|
|
$this->setEnum($enum); |
73
|
|
|
$enum = $this->getEnum(); |
74
|
|
|
|
75
|
|
|
// If there's a default, then use this |
76
|
|
|
if ($default && !is_int($default)) { |
77
|
|
|
if (in_array($default, $enum)) { |
78
|
|
|
$this->setDefault($default); |
79
|
|
|
} else { |
80
|
|
|
user_error( |
81
|
|
|
"Enum::__construct() The default value '$default' does not match any item in the enumeration", |
82
|
|
|
E_USER_ERROR |
83
|
|
|
); |
84
|
|
|
} |
85
|
|
|
} elseif (is_int($default) && $default < count($enum)) { |
86
|
|
|
// Set to specified index if given |
87
|
|
|
$this->setDefault($enum[$default]); |
88
|
|
|
} else { |
89
|
|
|
// Set to null if specified |
90
|
|
|
$this->setDefault(null); |
91
|
|
|
} |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
parent::__construct($name, $options); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* @return void |
99
|
|
|
*/ |
100
|
|
|
public function requireField() |
101
|
|
|
{ |
102
|
|
|
$charset = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'charset'); |
103
|
|
|
$collation = Config::inst()->get('SilverStripe\ORM\Connect\MySQLDatabase', 'collation'); |
104
|
|
|
|
105
|
|
|
$parts = array( |
106
|
|
|
'datatype' => 'enum', |
107
|
|
|
'enums' => $this->getEnumObsolete(), |
108
|
|
|
'character set' => $charset, |
109
|
|
|
'collate' => $collation, |
110
|
|
|
'default' => $this->getDefault(), |
111
|
|
|
'table' => $this->getTable(), |
112
|
|
|
'arrayValue' => $this->arrayValue |
113
|
|
|
); |
114
|
|
|
|
115
|
|
|
$values = array( |
116
|
|
|
'type' => 'enum', |
117
|
|
|
'parts' => $parts |
118
|
|
|
); |
119
|
|
|
|
120
|
|
|
DB::require_field($this->getTable(), $this->getName(), $values); |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Return a dropdown field suitable for editing this field. |
125
|
|
|
* |
126
|
|
|
* @param string $title |
127
|
|
|
* @param string $name |
128
|
|
|
* @param bool $hasEmpty |
129
|
|
|
* @param string $value |
130
|
|
|
* @param string $emptyString |
131
|
|
|
* @return DropdownField |
132
|
|
|
*/ |
133
|
|
|
public function formField($title = null, $name = null, $hasEmpty = false, $value = "", $emptyString = null) |
134
|
|
|
{ |
135
|
|
|
|
136
|
|
|
if (!$title) { |
137
|
|
|
$title = $this->getName(); |
138
|
|
|
} |
139
|
|
|
if (!$name) { |
140
|
|
|
$name = $this->getName(); |
141
|
|
|
} |
142
|
|
|
|
143
|
|
|
$field = new DropdownField($name, $title, $this->enumValues(false), $value); |
144
|
|
|
if ($hasEmpty) { |
145
|
|
|
$field->setEmptyString($emptyString); |
146
|
|
|
} |
147
|
|
|
|
148
|
|
|
return $field; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
public function scaffoldFormField($title = null, $params = null) |
152
|
|
|
{ |
153
|
|
|
return $this->formField($title); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* @param string |
158
|
|
|
* |
159
|
|
|
* @return DropdownField |
160
|
|
|
*/ |
161
|
|
|
public function scaffoldSearchField($title = null) |
162
|
|
|
{ |
163
|
|
|
$anyText = _t('SilverStripe\\ORM\\FieldType\\DBEnum.ANY', 'Any'); |
164
|
|
|
return $this->formField($title, null, true, '', "($anyText)"); |
165
|
|
|
} |
166
|
|
|
|
167
|
|
|
/** |
168
|
|
|
* Returns the values of this enum as an array, suitable for insertion into |
169
|
|
|
* a {@link DropdownField} |
170
|
|
|
* |
171
|
|
|
* @param boolean |
172
|
|
|
* |
173
|
|
|
* @return array |
174
|
|
|
*/ |
175
|
|
|
public function enumValues($hasEmpty = false) |
176
|
|
|
{ |
177
|
|
|
return ($hasEmpty) |
178
|
|
|
? array_merge(array('' => ''), ArrayLib::valuekey($this->getEnum())) |
179
|
|
|
: ArrayLib::valuekey($this->getEnum()); |
180
|
|
|
} |
181
|
|
|
|
182
|
|
|
/** |
183
|
|
|
* Get list of enum values |
184
|
|
|
* |
185
|
|
|
* @return array |
186
|
|
|
*/ |
187
|
|
|
public function getEnum() |
188
|
|
|
{ |
189
|
|
|
return $this->enum; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
|
193
|
|
|
/** |
194
|
|
|
* Get the list of enum values, including obsolete values still present in the database |
195
|
|
|
* |
196
|
|
|
* If table or name are not set, or if it is not a valid field on the given table, |
197
|
|
|
* then only known enum values are returned. |
198
|
|
|
* |
199
|
|
|
* Values cached in this method can be cleared via `DBEnum::flushCache();` |
200
|
|
|
* |
201
|
|
|
* @return array |
202
|
|
|
*/ |
203
|
|
|
public function getEnumObsolete() |
204
|
|
|
{ |
205
|
|
|
// Without a table or field specified, we can only retrieve known enum values |
206
|
|
|
$table = $this->getTable(); |
207
|
|
|
$name = $this->getName(); |
208
|
|
|
if (empty($table) || empty($name)) { |
209
|
|
|
return $this->getEnum(); |
210
|
|
|
} |
211
|
|
|
|
212
|
|
|
// Ensure the table level cache exists |
213
|
|
|
if (empty(self::$enum_cache[$table])) { |
214
|
|
|
self::$enum_cache[$table] = array(); |
215
|
|
|
} |
216
|
|
|
|
217
|
|
|
// Check existing cache |
218
|
|
|
if (!empty(self::$enum_cache[$table][$name])) { |
219
|
|
|
return self::$enum_cache[$table][$name]; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
// Get all enum values |
223
|
|
|
$enumValues = $this->getEnum(); |
224
|
|
|
if (DB::get_schema()->hasField($table, $name)) { |
225
|
|
|
$existing = DB::query("SELECT DISTINCT \"{$name}\" FROM \"{$table}\"")->column(); |
226
|
|
|
$enumValues = array_unique(array_merge($enumValues, $existing)); |
227
|
|
|
} |
228
|
|
|
|
229
|
|
|
// Cache and return |
230
|
|
|
self::$enum_cache[$table][$name] = $enumValues; |
231
|
|
|
return $enumValues; |
232
|
|
|
} |
233
|
|
|
|
234
|
|
|
/** |
235
|
|
|
* Set enum options |
236
|
|
|
* |
237
|
|
|
* @param string|array $enum |
238
|
|
|
* @return $this |
239
|
|
|
*/ |
240
|
|
|
public function setEnum($enum) |
241
|
|
|
{ |
242
|
|
|
if (!is_array($enum)) { |
243
|
|
|
$enum = preg_split( |
244
|
|
|
'/\s*,\s*/', |
245
|
|
|
// trim commas only if they are on the right with a newline following it |
246
|
|
|
ltrim(preg_replace('/,\s*\n\s*$/', '', $enum)) |
247
|
|
|
); |
248
|
|
|
} |
249
|
|
|
$this->enum = array_values($enum); |
|
|
|
|
250
|
|
|
return $this; |
251
|
|
|
} |
252
|
|
|
|
253
|
|
|
/** |
254
|
|
|
* Get default vwalue |
255
|
|
|
* |
256
|
|
|
* @return string|null |
257
|
|
|
*/ |
258
|
|
|
public function getDefault() |
259
|
|
|
{ |
260
|
|
|
return $this->default; |
261
|
|
|
} |
262
|
|
|
|
263
|
|
|
/** |
264
|
|
|
* Set default value |
265
|
|
|
* |
266
|
|
|
* @param string $default |
267
|
|
|
* @return $this |
268
|
|
|
*/ |
269
|
|
|
public function setDefault($default) |
270
|
|
|
{ |
271
|
|
|
$this->default = $default; |
272
|
|
|
$this->setDefaultValue($default); |
273
|
|
|
return $this; |
274
|
|
|
} |
275
|
|
|
} |
276
|
|
|
|