1
|
|
|
<?php
|
2
|
|
|
//-------------------------------------------------------------------------
|
3
|
|
|
// OVIDENTIA http://www.ovidentia.org
|
4
|
|
|
// Ovidentia is free software; you can redistribute it and/or modify
|
5
|
|
|
// it under the terms of the GNU General Public License as published by
|
6
|
|
|
// the Free Software Foundation; either version 2, or (at your option)
|
7
|
|
|
// any later version.
|
8
|
|
|
//
|
9
|
|
|
// This program is distributed in the hope that it will be useful, but
|
10
|
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
11
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
12
|
|
|
// See the GNU General Public License for more details.
|
13
|
|
|
//
|
14
|
|
|
// You should have received a copy of the GNU General Public License
|
15
|
|
|
// along with this program; if not, write to the Free Software
|
16
|
|
|
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
|
17
|
|
|
// USA.
|
18
|
|
|
//-------------------------------------------------------------------------
|
19
|
|
|
/**
|
20
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)
|
21
|
|
|
* @copyright Copyright (c) 2018 by CANTICO ({@link http://www.cantico.fr})
|
22
|
|
|
*/
|
23
|
|
|
|
24
|
|
|
|
25
|
|
|
$App = app_App();
|
26
|
|
|
$App->includeTraceableRecordSet();
|
27
|
|
|
|
28
|
|
|
/**
|
29
|
|
|
* @property ORM_StringField $name
|
30
|
|
|
* @property ORM_StringField $fieldname
|
31
|
|
|
* @property ORM_TextField $description
|
32
|
|
|
* @property ORM_EnumField $object
|
33
|
|
|
* @property ORM_EnumField $fieldtype
|
34
|
|
|
* @property ORM_TextField $enumvalues
|
35
|
|
|
* @property ORM_BoolField $mandatory
|
36
|
|
|
*
|
37
|
|
|
* @method app_CustomField get(mixed $criteria)
|
38
|
|
|
* @method app_CustomField request(mixed $criteria)
|
39
|
|
|
* @method app_CustomField[] select(\ORM_Criteria $criteria = null)
|
40
|
|
|
* @method app_CustomField newRecord()
|
41
|
|
|
*
|
42
|
|
|
* @method Func_App App()
|
43
|
|
|
*/
|
44
|
|
|
class app_CustomFieldSet extends app_TraceableRecordSet
|
45
|
|
|
{
|
46
|
|
|
/**
|
47
|
|
|
* @param Func_App $App
|
48
|
|
|
*/
|
49
|
|
|
public function __construct(Func_App $App = null)
|
50
|
|
|
{
|
51
|
|
|
parent::__construct($App);
|
|
|
|
|
52
|
|
|
|
53
|
|
|
$this->setDescription('Custom field');
|
54
|
|
|
|
55
|
|
|
$this->setPrimaryKey('id');
|
56
|
|
|
|
57
|
|
|
$this->addFields(
|
58
|
|
|
ORM_StringField('name')
|
59
|
|
|
->setDescription('Field label'),
|
60
|
|
|
ORM_StringField('fieldname')
|
61
|
|
|
->setDescription('Name of field used in table, not modifiable'),
|
62
|
|
|
ORM_TextField('description')
|
63
|
|
|
->setDescription('Description'),
|
64
|
|
|
ORM_EnumField('object', $this->getObjects())
|
65
|
|
|
->setDescription('Applies to'),
|
66
|
|
|
ORM_EnumField('fieldtype', $this->getFieldTypes())
|
67
|
|
|
->setDescription('Field type'),
|
68
|
|
|
ORM_TextField('enumvalues')
|
69
|
|
|
->setDescription('serialized array of values for enum fields'),
|
70
|
|
|
ORM_BoolField('mandatory')
|
71
|
|
|
->setDescription('Mandatory'),
|
72
|
|
|
|
73
|
|
|
ORM_StringField('section')
|
74
|
|
|
->setDescription($App->translate('Section')),
|
|
|
|
|
75
|
|
|
ORM_BoolField('importable')
|
76
|
|
|
->setOutputOptions($App->translate('No'), $App->translate('Yes'))
|
77
|
|
|
->setDescription($App->translate('Importable')),
|
78
|
|
|
ORM_BoolField('searchable')
|
79
|
|
|
->setOutputOptions($App->translate('No'), $App->translate('Yes'))
|
80
|
|
|
->setDescription($App->translate('Searchable')),
|
81
|
|
|
ORM_BoolField('visible')
|
82
|
|
|
->setOutputOptions($App->translate('No'), $App->translate('Yes'))
|
83
|
|
|
->setDescription($App->translate('Column in list'))
|
84
|
|
|
);
|
85
|
|
|
|
86
|
|
|
if ($App->onlineShop) {
|
|
|
|
|
87
|
|
|
$this->addFields(
|
88
|
|
|
ORM_BoolField('visible_in_shop')
|
89
|
|
|
);
|
90
|
|
|
}
|
91
|
|
|
}
|
92
|
|
|
|
93
|
|
|
|
94
|
|
|
|
95
|
|
|
public function save(ORM_Record $record, $noTrace = false)
|
96
|
|
|
{
|
97
|
|
|
if (!$record->fieldname) {
|
98
|
|
|
$record->fieldname = $this->getFieldName($record->name);
|
99
|
|
|
}
|
100
|
|
|
|
101
|
|
|
return parent::save($record, $noTrace);
|
102
|
|
|
}
|
103
|
|
|
|
104
|
|
|
|
105
|
|
|
/**
|
106
|
|
|
* Get a field name from a custom field name
|
107
|
|
|
* @param string $name
|
108
|
|
|
* @throws app_SaveException
|
109
|
|
|
* @return string
|
110
|
|
|
*/
|
111
|
|
|
public function getFieldName($name)
|
112
|
|
|
{
|
113
|
|
|
// create the field name automatically
|
114
|
|
|
$name = bab_removeDiacritics($name);
|
115
|
|
|
$name = preg_replace('/[^a-zA-Z0-9]+/', '', $name);
|
116
|
|
|
$name = mb_strtolower($name);
|
117
|
|
|
|
118
|
|
|
if (empty($name)) {
|
119
|
|
|
throw new app_SaveException($this->App()->translate('The name is mandatory'));
|
120
|
|
|
}
|
121
|
|
|
|
122
|
|
|
return '_' . $name;
|
123
|
|
|
}
|
124
|
|
|
|
125
|
|
|
|
126
|
|
|
|
127
|
|
|
/**
|
128
|
|
|
* List of objects where custom fields are applicable.
|
129
|
|
|
*
|
130
|
|
|
* @return string[]
|
131
|
|
|
*/
|
132
|
|
|
public function getObjects()
|
133
|
|
|
{
|
134
|
|
|
$App = $this->App();
|
135
|
|
|
|
136
|
|
|
$arr = array();
|
137
|
|
|
|
138
|
|
|
if (isset($App->Article)) {
|
|
|
|
|
139
|
|
|
$arr['Article'] = $App->translate('Products database');
|
140
|
|
|
}
|
141
|
|
|
|
142
|
|
|
return $arr;
|
143
|
|
|
}
|
144
|
|
|
|
145
|
|
|
/**
|
146
|
|
|
* list of ORM fields to use for a custom field
|
147
|
|
|
*/
|
148
|
|
|
public function getFieldTypes()
|
149
|
|
|
{
|
150
|
|
|
$App = $this->App();
|
151
|
|
|
|
152
|
|
|
return array(
|
153
|
|
|
'String' => $App->translate('Line edit'),
|
154
|
|
|
'Text' => $App->translate('Text edit'),
|
155
|
|
|
'Bool' => $App->translate('Checkbox'),
|
156
|
|
|
'Int' => $App->translate('Integer number'),
|
157
|
|
|
'Decimal' => $App->translate('Decimal number'),
|
158
|
|
|
'Date' => $App->translate('Date'),
|
159
|
|
|
'DateTime' => $App->translate('Date and time'),
|
160
|
|
|
'Time' => $App->translate('Time'),
|
161
|
|
|
'Enum' => $App->translate('Selection list'),
|
162
|
|
|
'Set' => $App->translate('Multi-selection list'),
|
163
|
|
|
'Url' => $App->translate('Url'),
|
164
|
|
|
'Email' => $App->translate('Email address'),
|
165
|
|
|
'File' => $App->translate('File'),
|
166
|
|
|
);
|
167
|
|
|
}
|
168
|
|
|
|
169
|
|
|
|
170
|
|
|
|
171
|
|
|
/**
|
172
|
|
|
* {@inheritDoc}
|
173
|
|
|
* @see app_RecordSet::isCreatable()
|
174
|
|
|
*/
|
175
|
|
|
public function isCreatable()
|
176
|
|
|
{
|
177
|
|
|
return true;
|
178
|
|
|
}
|
179
|
|
|
|
180
|
|
|
/**
|
181
|
|
|
* @return ORM_Criteria
|
182
|
|
|
*/
|
183
|
|
|
public function isReadable()
|
184
|
|
|
{
|
185
|
|
|
return $this->all();
|
186
|
|
|
}
|
187
|
|
|
|
188
|
|
|
/**
|
189
|
|
|
* @return ORM_Criteria
|
190
|
|
|
*/
|
191
|
|
|
public function isUpdatable()
|
192
|
|
|
{
|
193
|
|
|
return $this->all();
|
194
|
|
|
}
|
195
|
|
|
|
196
|
|
|
/**
|
197
|
|
|
* @return ORM_Criteria
|
198
|
|
|
*/
|
199
|
|
|
public function isDeletable()
|
200
|
|
|
{
|
201
|
|
|
return $this->isUpdatable();
|
202
|
|
|
}
|
203
|
|
|
}
|
204
|
|
|
|
205
|
|
|
|
206
|
|
|
|
207
|
|
|
|
208
|
|
|
/**
|
209
|
|
|
* @property string $name
|
210
|
|
|
* @property string $fieldname
|
211
|
|
|
* @property string $description
|
212
|
|
|
* @property string $object
|
213
|
|
|
* @property string $fieldtype
|
214
|
|
|
* @property string $enumvalues
|
215
|
|
|
* @property bool $mandatory
|
216
|
|
|
*
|
217
|
|
|
* @method Func_App App()
|
218
|
|
|
*/
|
219
|
|
|
class app_CustomField extends app_TraceableRecord
|
220
|
|
|
{
|
221
|
|
|
|
222
|
|
|
/**
|
223
|
|
|
* @return ORM_Field
|
224
|
|
|
*/
|
225
|
|
|
public function getORMField()
|
226
|
|
|
{
|
227
|
|
|
switch ($this->fieldtype) {
|
228
|
|
|
case 'Enum':
|
229
|
|
|
$field = ORM_EnumField($this->fieldname, $this->getEnumValues());
|
230
|
|
|
break;
|
231
|
|
|
|
232
|
|
|
case 'Decimal':
|
233
|
|
|
$field = ORM_DecimalField($this->fieldname, 2);
|
234
|
|
|
break;
|
235
|
|
|
|
236
|
|
|
case 'Bool':
|
237
|
|
|
$field = ORM_BoolField($this->fieldname);
|
238
|
|
|
$field->setOutputOptions(
|
239
|
|
|
$this->App()->translate('No'),
|
240
|
|
|
$this->App()->translate('Yes')
|
241
|
|
|
);
|
242
|
|
|
break;
|
243
|
|
|
|
244
|
|
|
default:
|
245
|
|
|
$function = 'ORM_'.$this->fieldtype.'Field';
|
246
|
|
|
$field = $function($this->fieldname);
|
247
|
|
|
break;
|
248
|
|
|
}
|
249
|
|
|
|
250
|
|
|
$field->setDescription($this->description);
|
251
|
|
|
|
252
|
|
|
return $field;
|
253
|
|
|
}
|
254
|
|
|
|
255
|
|
|
|
256
|
|
|
/**
|
257
|
|
|
* @return string[]
|
258
|
|
|
*/
|
259
|
|
|
public function getEnumValues()
|
260
|
|
|
{
|
261
|
|
|
return unserialize($this->enumvalues);
|
262
|
|
|
}
|
263
|
|
|
|
264
|
|
|
|
265
|
|
|
/**
|
266
|
|
|
* @return Widget_LabelledWidget
|
267
|
|
|
*/
|
268
|
|
|
public function getWidget()
|
269
|
|
|
{
|
270
|
|
|
$W = bab_Widgets();
|
271
|
|
|
$App = $this->App();
|
272
|
|
|
|
273
|
|
|
switch ($this->fieldtype) {
|
274
|
|
|
case 'Text':
|
275
|
|
|
$widget = $W->TextEdit()->setLines(3)->setColumns(70);
|
276
|
|
|
break;
|
277
|
|
|
|
278
|
|
|
case 'Bool':
|
279
|
|
|
$widget = $W->Checkbox();
|
280
|
|
|
break;
|
281
|
|
|
|
282
|
|
|
case 'Enum':
|
283
|
|
|
$options = array('' => '') + $this->getEnumValues();
|
284
|
|
|
$widget = $W->Select()->setOptions($options);
|
285
|
|
|
break;
|
286
|
|
|
|
287
|
|
|
case 'Date':
|
288
|
|
|
$widget = $W->DatePicker();
|
289
|
|
|
break;
|
290
|
|
|
|
291
|
|
|
case 'DateTime':
|
292
|
|
|
$widget = $W->DateTimePicker();
|
293
|
|
|
break;
|
294
|
|
|
|
295
|
|
|
case 'Int':
|
296
|
|
|
$widget = $W->RegExpLineEdit();
|
297
|
|
|
$widget->setRegExp(Widget_RegExpLineEdit::INT_FORMAT)
|
298
|
|
|
->setSubmitMessage(sprintf($App->translate('The field %s should be a integer number'), $this->name))
|
299
|
|
|
->setSize(10);
|
300
|
|
|
break;
|
301
|
|
|
|
302
|
|
|
case 'Decimal':
|
303
|
|
|
$widget = $W->RegExpLineEdit();
|
304
|
|
|
$widget->setRegExp(Widget_RegExpLineEdit::FLOAT_FORMAT)
|
305
|
|
|
->setSubmitMessage(sprintf($App->translate('The field %s should be a decimal number'), $this->name))
|
306
|
|
|
->setSize(10);
|
307
|
|
|
break;
|
308
|
|
|
|
309
|
|
|
case 'Url':
|
310
|
|
|
$widget = $W->UrlLineEdit();
|
311
|
|
|
break;
|
312
|
|
|
|
313
|
|
|
case 'Email':
|
314
|
|
|
$widget = $W->EmailLineEdit();
|
315
|
|
|
break;
|
316
|
|
|
|
317
|
|
|
default:
|
318
|
|
|
case 'String':
|
319
|
|
|
$widget = $W->LineEdit()->setSize(70)->setMaxSize(255);
|
320
|
|
|
break;
|
321
|
|
|
}
|
322
|
|
|
|
323
|
|
|
$labelledItem = $W->LabelledWidget($this->name, $widget, null);
|
324
|
|
|
$labelledItem->setName($this->fieldname);
|
325
|
|
|
|
326
|
|
|
if (!empty($this->description)) {
|
327
|
|
|
$labelledItem->setDescription($this->description);
|
328
|
|
|
}
|
329
|
|
|
|
330
|
|
|
return $labelledItem;
|
331
|
|
|
}
|
332
|
|
|
}
|
333
|
|
|
|