1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* @link http://www.newicon.net/neon |
4
|
|
|
* @copyright Copyright (c) 2018- Newicon Ltd |
5
|
|
|
* @license http://www.newicon.net/neon/license/ |
6
|
|
|
*/ |
7
|
|
|
|
8
|
|
|
namespace neon\phoebe\services\adapters\appforms; |
9
|
|
|
|
10
|
|
|
use neon\phoebe\services\adapters\common\PhoebeClassBase; |
11
|
|
|
use neon\phoebe\interfaces\forms\IPhoebeFormClass; |
12
|
|
|
use neon\core\helpers\Hash; |
13
|
|
|
|
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Provides a applicationForm phoebe class |
17
|
|
|
*/ |
18
|
|
|
class PhoebeClass extends PhoebeClassBase |
19
|
|
|
implements IPhoebeFormClass |
20
|
|
|
{ |
21
|
|
|
use PhoebeTrait; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* @inheritdoc |
25
|
|
|
*/ |
26
|
2 |
|
public function getClassFormDefinition(array $fields=[]) |
27
|
|
|
{ |
28
|
|
|
// if there is no definition return an empty form |
29
|
2 |
|
if (empty($this->definition)) |
30
|
|
|
return []; |
31
|
|
|
|
32
|
|
|
// TODO - NJ20180426 - see if we can get Phoebe to listen to $fields |
33
|
|
|
|
34
|
|
|
// create the form |
35
|
2 |
|
$definition = $this->replaceDefinitionFromDds($this->definition); |
|
|
|
|
36
|
2 |
|
$this->setMemberFieldNames($definition); |
37
|
2 |
|
return $this->convertToForm($definition); |
38
|
|
|
} |
39
|
|
|
|
40
|
|
|
public function getClassBuilderDefinition() |
41
|
|
|
{ |
42
|
|
|
return $this->definition; |
43
|
|
|
} |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @inheritdoc |
47
|
|
|
*/ |
48
|
|
|
public function getObjectGridDefinition($additionalColumns = []) |
49
|
|
|
{ |
50
|
|
|
return parent::getObjectGridDefinition($additionalColumns); |
51
|
|
|
} |
52
|
|
|
|
53
|
|
|
/** |
54
|
|
|
* @inheritdoc |
55
|
|
|
*/ |
56
|
|
|
public function editClass($changes) |
57
|
|
|
{ |
58
|
|
|
if (isset($changes['definition'])) |
59
|
|
|
$changes['definition'] = $this->prepareDefinition($changes['definition']); |
60
|
|
|
parent::editClass($changes); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @inheritdoc |
65
|
|
|
*/ |
66
|
|
|
public function getRequiredDataSources() |
67
|
|
|
{ |
68
|
|
|
$dataSources = isset($this->definition['dataSources']) ? $this->definition['dataSources'] : []; |
69
|
|
|
$returnedDataSources = []; |
70
|
|
|
foreach ($dataSources as $dataSource) { |
71
|
|
|
$key = $dataSource['label']; |
72
|
|
|
$returnedDataSources[$key] = [ |
73
|
|
|
'class_type'=>$dataSource['class_type'], |
74
|
|
|
'key'=>$key |
75
|
|
|
]; |
76
|
|
|
} |
77
|
|
|
return $returnedDataSources; |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* @inheritdoc |
82
|
|
|
*/ |
83
|
|
|
public function findPhoebeKeysForClassTypesInDefinition($ddsClassTypes) |
84
|
|
|
{ |
85
|
|
|
$definition = $this->definition; |
86
|
|
|
$applicationDataPhoebeUuids = []; |
87
|
|
|
foreach ($ddsClassTypes as $ct) |
88
|
|
|
$applicationDataPhoebeUuids[$ct] = null; |
89
|
|
|
foreach ($definition['renderables'] as $k=>$r) { |
90
|
|
|
if ($r['type'] == 'ClassComponent' && in_array($r['class_type'], $ddsClassTypes)) { |
91
|
|
|
$applicationDataPhoebeUuids[$r['class_type']] = $k; |
92
|
|
|
} |
93
|
|
|
} |
94
|
|
|
return $applicationDataPhoebeUuids; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
// ---------------------------------------- // |
98
|
|
|
// ---------- Additional Methods ---------- // |
99
|
|
|
|
100
|
|
|
/** |
101
|
|
|
* Set the definition on the model - used when merging the stored definition |
102
|
|
|
* with that from Daedalus |
103
|
|
|
* |
104
|
|
|
* @param array $definition |
105
|
|
|
*/ |
106
|
2 |
|
public function setDefinition($definition) |
107
|
|
|
{ |
108
|
2 |
|
$this->getModel()->definition = $definition; |
109
|
2 |
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Keep the model's definition here - overrides are applied in convertToForm |
113
|
|
|
* level and not in the phoebe class definition |
114
|
|
|
* @return array |
115
|
|
|
*/ |
116
|
2 |
|
public function getDefinition() |
117
|
|
|
{ |
118
|
2 |
|
return $this->getModel()->definition; |
119
|
|
|
} |
120
|
|
|
|
121
|
2 |
|
protected function convertToForm($definition) |
122
|
|
|
{ |
123
|
2 |
|
$form = []; |
124
|
2 |
|
$form['name'] = $this->canonicaliseRef($definition['name']); |
125
|
2 |
|
$fields = $this->convertRenderablesToFields($definition['rootNode'], $definition['renderables']); |
126
|
2 |
|
$form['fields'] = $fields['fields']; |
127
|
|
|
// apply any overrides to the form |
128
|
2 |
|
if ($this->_overrides) |
|
|
|
|
129
|
|
|
$form = array_replace_recursive($form, $this->_overrides); |
130
|
2 |
|
return $form; |
131
|
|
|
} |
132
|
|
|
|
133
|
2 |
|
protected function convertRenderablesToFields($key, $renderables) { |
134
|
2 |
|
if (!isset($renderables[$key])) { |
135
|
|
|
dd("Key $key doesn't exist in the form definition", $renderables); |
136
|
|
|
throw new \RuntimeException("Key $key doesn't exist in the form definition");} |
137
|
2 |
|
$rend = $renderables[$key]; |
138
|
2 |
|
$field=[]; |
139
|
2 |
|
if (!empty($rend['type'])) { |
140
|
2 |
|
$field = []; |
141
|
2 |
|
switch($rend['type']) { |
142
|
2 |
|
case 'FormComponent': |
143
|
2 |
|
if (isset($rend['items'])) |
144
|
2 |
|
$field['fields'] = $this->addItems($rend['items'], $renderables); |
145
|
2 |
|
break; |
146
|
2 |
|
case 'ClassComponent': |
147
|
2 |
|
$classDefinition = isset($rend['definition']) ? $rend['definition'] : []; |
148
|
2 |
|
if (count($rend['items'])>0) { |
149
|
2 |
|
$field['fields'] = []; |
150
|
2 |
|
$field['label'] = ''; |
151
|
2 |
|
if (isset($classDefinition['showLabel']) && $classDefinition['showLabel']) |
152
|
2 |
|
$field['label'] = isset($classDefinition['label']) ? $classDefinition['label'] : $rend['label']; |
153
|
2 |
|
$field['description'] = ''; |
154
|
2 |
|
if (isset($classDefinition['showDescription']) && $classDefinition['showDescription']) |
155
|
|
|
$field['description'] = isset($classDefinition['description']) ? $classDefinition['description'] : $rend['description']; |
156
|
2 |
|
if ($this->isRepeater($rend)) { |
157
|
2 |
|
$this->addRepeaterHeader($field, $rend['definition'], $key); |
158
|
2 |
|
if (isset($classDefinition['showLabel']) && $classDefinition['showLabel']) |
159
|
2 |
|
$field['template']['label'] = isset($classDefinition['label']) ? $classDefinition['label'] : $rend['label']; |
160
|
2 |
|
$field['template']['fields'] = $this->addItems($rend['items'], $renderables); |
161
|
2 |
|
$field['template']['fields'][] = $this->createHiddenField('_renderable', $key); |
162
|
2 |
|
$field['template']['fields'][] = $this->createHiddenField('_classType', $rend['class_type']); |
163
|
2 |
|
$field['template']['fields'][] = $this->createHiddenField('_uuid'); |
164
|
|
|
} else { |
165
|
2 |
|
$field['class'] = '\\neon\\core\\form\\Form'; |
166
|
2 |
|
$field['name'] = $key; |
167
|
2 |
|
$field['dataKey'] = $field['name']; |
168
|
2 |
|
$field['fields'] = $this->addItems($rend['items'], $renderables); |
169
|
2 |
|
$field['fields'][] = $this->createHiddenField('_renderable', $key); |
170
|
2 |
|
$field['fields'][] = $this->createHiddenField('_classType', $rend['class_type']); |
171
|
2 |
|
$field['fields'][] = $this->createHiddenField('_uuid'); |
172
|
|
|
} |
173
|
|
|
} |
174
|
2 |
|
break; |
175
|
2 |
|
case 'MemberComponent': |
176
|
|
|
case 'ElementComponent': |
177
|
2 |
|
$field = $rend['definition']; |
178
|
|
|
// not all components have names but the form requires everything to have one |
179
|
2 |
|
if (empty($field['name'])) { |
180
|
2 |
|
$field['name'] = $this->createFieldName($field); |
181
|
|
|
} |
182
|
2 |
|
break; |
183
|
|
|
} |
184
|
|
|
} |
185
|
2 |
|
return $field; |
186
|
|
|
} |
187
|
|
|
|
188
|
2 |
|
protected function addItems($items, $renderables) |
189
|
|
|
{ |
190
|
2 |
|
$field = []; |
191
|
2 |
|
$order = 1; |
192
|
2 |
|
foreach ($items as $rKey) { |
193
|
2 |
|
$subField = $this->convertRenderablesToFields($rKey, $renderables, 1); |
|
|
|
|
194
|
2 |
|
if (isset($subField[$rKey])) |
195
|
2 |
|
$field[$rKey] = $subField[$rKey]; |
196
|
|
|
else |
197
|
2 |
|
$field[$rKey] = $subField; |
198
|
2 |
|
$field[$rKey]['order'] = $order++; |
199
|
|
|
} |
200
|
2 |
|
return $field; |
201
|
|
|
} |
202
|
|
|
|
203
|
2 |
|
protected function isRepeater($renderable) |
204
|
|
|
{ |
205
|
2 |
|
return (isset($renderable['definition']['isRepeater']) && $renderable['definition']['isRepeater'] == true); |
206
|
|
|
} |
207
|
|
|
|
208
|
2 |
|
protected function addRepeaterHeader(&$field, $repeat, $key) |
|
|
|
|
209
|
|
|
{ |
210
|
|
|
// set the rpeater header part |
211
|
2 |
|
$field['class'] = "neon\\core\\form\\FormRepeater"; |
212
|
2 |
|
$field['count'] = isset($repeat['defaultInstances']) ? (integer) $repeat['defaultInstances'] : 1; |
213
|
2 |
|
$field['countMax'] = isset($repeat['maxInstances']) ? (integer) $repeat['maxInstances'] : 0; |
214
|
2 |
|
$field['countMin'] = isset($repeat['minInstances']) ? (integer) $repeat['minInstances'] : 1; |
215
|
2 |
|
$allowChangeOfRepeats = ($field['countMin'] != $field['countMax']); |
216
|
2 |
|
$field['allowAdd'] = $allowChangeOfRepeats; |
217
|
2 |
|
$field['allowRemove'] = $allowChangeOfRepeats; |
218
|
|
|
|
219
|
|
|
// now set the template header part |
220
|
2 |
|
$field['template']['class'] = "neon\\core\\form\\Form"; |
221
|
2 |
|
} |
222
|
|
|
|
223
|
|
|
/** |
224
|
|
|
* Create a hidden object id field required when sending back the data |
225
|
|
|
* so we know what object it belongs to if set |
226
|
|
|
* @return array |
227
|
|
|
*/ |
228
|
2 |
|
protected function createHiddenField($name, $value=null) |
229
|
|
|
{ |
230
|
|
|
return [ |
231
|
2 |
|
'class' => "neon\\core\\form\\fields\\Hidden", |
232
|
2 |
|
'name' => $name, |
233
|
2 |
|
'order' => 0, |
234
|
2 |
|
'value' => $value |
235
|
|
|
]; |
236
|
|
|
} |
237
|
|
|
|
238
|
2 |
|
protected function createFieldName($field) |
239
|
|
|
{ |
240
|
2 |
|
$uuid = isset($field['id']) ? $field['id'] : Hash::uuid64(); |
241
|
2 |
|
return str_replace(['-','_'],['a','Z'], $uuid); |
242
|
|
|
} |
243
|
|
|
|
244
|
|
|
} |