1
|
|
|
<?php |
|
|
|
|
2
|
|
|
|
3
|
|
|
namespace DigitalWand\AdminHelper\Widget; |
4
|
|
|
|
5
|
|
|
use Bitrix\Main\Localization\Loc; |
6
|
|
|
|
7
|
|
|
Loc::loadMessages(__FILE__); |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* Виджет "галочка" |
11
|
|
|
* |
12
|
|
|
* Доступные опции: |
13
|
|
|
* <ul> |
14
|
|
|
* <li> <b>FIELD_TYPE</b> - Тип данных для хранения булевых значений (строка, целые числа, булево) </li> |
15
|
|
|
* </ul> |
16
|
|
|
*/ |
17
|
|
|
class CheckboxWidget extends HelperWidget |
18
|
|
|
{ |
19
|
|
|
/** |
20
|
|
|
* Строковый тип чекбокса (Y/N) |
21
|
|
|
* FIXME: если верить битриксу, мжет быть ещё и экзотичный случай со строками "true" и "false"! |
22
|
|
|
*/ |
23
|
|
|
const TYPE_STRING = 'string'; |
24
|
|
|
/** |
25
|
|
|
* Целочисленный тип чекбокса (1/0) |
26
|
|
|
*/ |
27
|
|
|
const TYPE_INT = 'integer'; |
28
|
|
|
/** |
29
|
|
|
* Булевый тип чекбокса |
30
|
|
|
*/ |
31
|
|
|
const TYPE_BOOLEAN = 'boolean'; |
32
|
|
|
/** |
33
|
|
|
* Значение положительного варианта для строкового чекбокса |
34
|
|
|
*/ |
35
|
|
|
const TYPE_STRING_YES = 'Y'; |
36
|
|
|
/** |
37
|
|
|
* Значение отрицательного варианта для строкового чекбокса |
38
|
|
|
*/ |
39
|
|
|
const TYPE_STRING_NO = 'N'; |
40
|
|
|
/** |
41
|
|
|
* Значение положительного варианта для целочисленного чекбокса |
42
|
|
|
*/ |
43
|
|
|
const TYPE_INT_YES = 1; |
44
|
|
|
/** |
45
|
|
|
* Значение отрицательного варианта для целочисленного чекбокса |
46
|
|
|
*/ |
47
|
|
|
const TYPE_INT_NO = 0; |
48
|
|
|
|
49
|
|
|
protected static $defaults = array( |
50
|
|
|
'EDIT_IN_LIST' => true |
51
|
|
|
); |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @inheritdoc |
55
|
|
|
*/ |
56
|
|
|
public function generateRow(&$row, $data) |
57
|
|
|
{ |
58
|
|
|
$modeType = $this->getCheckboxType(); |
59
|
|
|
|
60
|
|
|
$globalYes = ''; |
61
|
|
|
$globalNo = ''; |
62
|
|
|
|
63
|
|
|
switch ($modeType) { |
64
|
|
|
case self::TYPE_STRING: { |
|
|
|
|
65
|
|
|
$globalYes = self::TYPE_STRING_YES; |
66
|
|
|
$globalNo = self::TYPE_STRING_NO; |
67
|
|
|
break; |
68
|
|
|
} |
69
|
|
|
case self::TYPE_INT: |
70
|
|
|
case self::TYPE_BOOLEAN: { |
|
|
|
|
71
|
|
|
$globalYes = self::TYPE_INT_YES; |
72
|
|
|
$globalNo = self::TYPE_INT_NO; |
73
|
|
|
break; |
74
|
|
|
} |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
if ($this->getSettings('EDIT_IN_LIST') AND !$this->getSettings('READONLY')) { |
|
|
|
|
78
|
|
|
$checked = intval($this->getValue() == $globalYes) ? 'checked' : ''; |
79
|
|
|
$js = 'var input = document.getElementsByName(\'' . $this->getEditableListInputName() . '\')[0]; |
80
|
|
|
input.value = this.checked ? \'' . $globalYes . '\' : \'' . $globalNo . '\';'; |
81
|
|
|
$editHtml = '<input type="checkbox" |
82
|
|
|
value="' . static::prepareToTagAttr($this->getValue()) . '" ' . $checked . ' |
83
|
|
|
onchange="' . $js . '"/> |
84
|
|
|
<input type="hidden" |
85
|
|
|
value="' . static::prepareToTagAttr($this->getValue()) . '" |
86
|
|
|
name="' . $this->getEditableListInputName() . '" />'; |
87
|
|
|
$row->AddEditField($this->getCode(), $editHtml); |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
if (intval($this->getValue() == $globalYes)) { |
91
|
|
|
$value = Loc::getMessage('DIGITALWAND_AH_CHECKBOX_YES'); |
92
|
|
|
} else { |
93
|
|
|
$value = Loc::getMessage('DIGITALWAND_AH_CHECKBOX_NO'); |
94
|
|
|
} |
95
|
|
|
|
96
|
|
|
$row->AddViewField($this->getCode(), $value); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* @inheritdoc |
101
|
|
|
*/ |
102
|
|
|
public function showFilterHtml() |
103
|
|
|
{ |
104
|
|
|
$filterHtml = '<tr>'; |
105
|
|
|
$filterHtml .= '<td>' . $this->getSettings('TITLE') . '</td>'; |
106
|
|
|
$filterHtml .= '<td> <select name="' . $this->getFilterInputName() . '">'; |
107
|
|
|
$filterHtml .= '<option value=""></option>'; |
108
|
|
|
|
109
|
|
|
$modeType = $this->getCheckboxType(); |
110
|
|
|
|
111
|
|
|
$langYes = Loc::getMessage('DIGITALWAND_AH_CHECKBOX_YES'); |
112
|
|
|
$langNo = Loc::getMessage('DIGITALWAND_AH_CHECKBOX_NO'); |
113
|
|
|
|
114
|
|
|
switch ($modeType) { |
115
|
|
View Code Duplication |
case self::TYPE_STRING: { |
|
|
|
|
116
|
|
|
$filterHtml .= '<option value="' . self::TYPE_STRING_YES . '">' . $langYes . '</option>'; |
117
|
|
|
$filterHtml .= '<option value="' . self::TYPE_STRING_NO . '">' . $langNo . '</option>'; |
118
|
|
|
break; |
119
|
|
|
} |
120
|
|
|
case self::TYPE_INT: |
121
|
|
View Code Duplication |
case self::TYPE_BOOLEAN: { |
|
|
|
|
122
|
|
|
$filterHtml .= '<option value="' . self::TYPE_INT_YES . '">' . $langYes . '</option>'; |
123
|
|
|
$filterHtml .= '<option value="' . self::TYPE_INT_NO . '">' . $langNo . '</option>'; |
124
|
|
|
break; |
125
|
|
|
} |
126
|
|
|
} |
127
|
|
|
|
128
|
|
|
$filterHtml .= '</select></td>'; |
129
|
|
|
$filterHtml .= '</tr>'; |
130
|
|
|
|
131
|
|
|
print $filterHtml; |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @inheritdoc |
136
|
|
|
*/ |
137
|
|
|
public function getValueReadonly() |
138
|
|
|
{ |
139
|
|
|
$code = $this->getCode(); |
140
|
|
|
$value = isset($this->data[$code]) ? $this->data[$code] : null; |
141
|
|
|
$modeType = $this->getCheckboxType(); |
142
|
|
|
|
143
|
|
|
switch ($modeType) { |
144
|
|
|
case static::TYPE_STRING: { |
|
|
|
|
145
|
|
|
$value = $value == 'Y' ? Loc::getMessage('DIGITALWAND_AH_CHECKBOX_YES') : Loc::getMessage('DIGITALWAND_AH_CHECKBOX_NO'); |
146
|
|
|
break; |
147
|
|
|
} |
148
|
|
|
case static::TYPE_INT: |
149
|
|
|
case static::TYPE_BOOLEAN: { |
|
|
|
|
150
|
|
|
$value = $value ? Loc::getMessage('DIGITALWAND_AH_CHECKBOX_YES') : Loc::getMessage('DIGITALWAND_AH_CHECKBOX_NO'); |
151
|
|
|
break; |
152
|
|
|
} |
153
|
|
|
} |
154
|
|
|
|
155
|
|
|
return static::prepareToOutput($value); |
156
|
|
|
} |
157
|
|
|
|
158
|
|
|
/** |
159
|
|
|
* @inheritdoc |
160
|
|
|
*/ |
161
|
|
|
public function processEditAction() |
162
|
|
|
{ |
163
|
|
|
parent::processEditAction(); |
164
|
|
|
|
165
|
|
|
if ($this->getCheckboxType() === static::TYPE_BOOLEAN) { |
166
|
|
|
$this->data[$this->getCode()] = (bool)$this->data[$this->getCode()]; |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
|
170
|
|
|
/** |
171
|
|
|
* @inheritdoc |
172
|
|
|
*/ |
173
|
|
|
protected function getEditHtml() |
174
|
|
|
{ |
175
|
|
|
$html = ''; |
176
|
|
|
|
177
|
|
|
$modeType = $this->getCheckboxType(); |
178
|
|
|
|
179
|
|
|
switch ($modeType) { |
180
|
|
View Code Duplication |
case static::TYPE_STRING: { |
|
|
|
|
181
|
|
|
$checked = $this->getValue() == self::TYPE_STRING_YES ? 'checked' : ''; |
182
|
|
|
|
183
|
|
|
$html = '<input type="hidden" name="' . $this->getEditInputName() . '" value="' . self::TYPE_STRING_NO . '" />'; |
184
|
|
|
$html .= '<input type="checkbox" name="' . $this->getEditInputName() . '" value="' . self::TYPE_STRING_YES . '" ' . $checked . ' />'; |
185
|
|
|
break; |
186
|
|
|
} |
187
|
|
|
case static::TYPE_INT: |
188
|
|
View Code Duplication |
case static::TYPE_BOOLEAN: { |
|
|
|
|
189
|
|
|
$checked = $this->getValue() == self::TYPE_INT_YES ? 'checked' : ''; |
190
|
|
|
|
191
|
|
|
$html = '<input type="hidden" name="' . $this->getEditInputName() . '" value="' . self::TYPE_INT_NO . '" />'; |
192
|
|
|
$html .= '<input type="checkbox" name="' . $this->getEditInputName() . '" value="' . self::TYPE_INT_YES . '" ' . $checked . ' />'; |
193
|
|
|
break; |
194
|
|
|
} |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
return $html; |
198
|
|
|
} |
199
|
|
|
|
200
|
|
|
/** |
201
|
|
|
* Получить тип чекбокса по типу поля. |
202
|
|
|
* По-умолчанию возвращает TYPE_STRING |
203
|
|
|
* @return mixed |
204
|
|
|
*/ |
205
|
|
|
public function getCheckboxType() |
206
|
|
|
{ |
207
|
|
|
$settingsFieldType = $this->getSettings('FIELD_TYPE'); |
208
|
|
|
$checkTypes = array(static::TYPE_STRING, static::TYPE_BOOLEAN, static::TYPE_INT); |
209
|
|
|
$columnName = $this->getCode(); |
210
|
|
|
|
211
|
|
|
if ($settingsFieldType AND in_array($settingsFieldType, $checkTypes)) { |
|
|
|
|
212
|
|
|
return $settingsFieldType; |
213
|
|
|
|
214
|
|
|
} else { |
215
|
|
|
$entity = $this->getEntityName(); |
216
|
|
|
$entityMap = $entity::getMap(); |
217
|
|
|
|
218
|
|
|
if (!isset($entityMap[$columnName])) { |
219
|
|
|
foreach ($entityMap as $field/** @var \Bitrix\Main\Entity\ScalarField $field */) { |
220
|
|
|
if($field instanceof \Bitrix\Main\Entity\ReferenceField) |
221
|
|
|
continue; |
222
|
|
|
if (is_object($field) AND $field->getColumnName() === $columnName) { |
|
|
|
|
223
|
|
|
return $field->getDataType(); //FIXME: deprecated? На что нужно заменить? |
224
|
|
|
} |
225
|
|
|
} |
226
|
|
|
|
227
|
|
|
} elseif (isset($entityMap[$columnName]['values']) AND |
|
|
|
|
228
|
|
|
is_array($entityMap[$columnName]['values']) AND |
|
|
|
|
229
|
|
|
count($entityMap[$columnName]['values']) == 2 |
230
|
|
|
) { |
231
|
|
|
$value = reset($entityMap[$columnName]['values']); |
232
|
|
|
if (is_string($value)) { |
233
|
|
|
return static::TYPE_STRING; |
234
|
|
|
} elseif (is_bool($value) OR is_integer($value)) { |
|
|
|
|
235
|
|
|
return static::TYPE_BOOLEAN; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
} elseif (isset($entityMap[$columnName]['data_type'])) { |
239
|
|
|
return $entityMap[$columnName]['data_type']; |
240
|
|
|
|
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Теоретически, рзработчик мог ввести полную хрень, указывая варианты значений для сущности |
245
|
|
|
* В этом случае ни одна проверка выше не сработает. |
246
|
|
|
* FIXME: а нужен ли эксепшн? |
247
|
|
|
*/ |
248
|
|
|
// throw new \Bitrix\Main\ArgumentTypeException("Unknown checkbox type"); |
|
|
|
|
249
|
|
|
} |
250
|
|
|
|
251
|
|
|
return static::TYPE_STRING; |
252
|
|
|
} |
253
|
|
|
} |
254
|
|
|
|
The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.
The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.
To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.