1<?php
2
3
4namespace ComboStrap;
5
6
7/**
8 * Class FormField
9 * @package ComboStrap
10 *
11 * A class that represents a tree of form field.
12 *
13 * Each field can be a scalar, a list or
14 * tabular by adding child fields.
15 *
16 *
17 */
18class FormMetaField
19{
20
21
22    /**
23     * The JSON attribute
24     */
25    public const TAB_ATTRIBUTE = "tab";
26    public const LABEL_ATTRIBUTE = "label";
27    public const URL_ATTRIBUTE = "url";
28    public const MUTABLE_ATTRIBUTE = "mutable";
29    /**
30     * A value may be a scalar or an array
31     */
32    public const VALUE_ATTRIBUTE = "value";
33    public const DEFAULT_VALUE_ATTRIBUTE = "default";
34
35    public const DOMAIN_VALUES_ATTRIBUTE = "domain-values";
36    public const WIDTH_ATTRIBUTE = "width";
37    public const CHILDREN_ATTRIBUTE = "children";
38    const DESCRIPTION_ATTRIBUTE = "description";
39    const NAME_ATTRIBUTE = "name";
40    const MULTIPLE_ATTRIBUTE = "multiple";
41
42
43    private $name;
44    /**
45     * @var bool
46     */
47    private $mutable;
48    /**
49     * @var string
50     */
51    private $tab;
52    /**
53     * @var string
54     */
55    private $label;
56    private $description;
57    /**
58     * If canonical is set, an url is also send
59     */
60    private $canonical;
61    private $values = [];
62    private $defaults = [];
63    /**
64     * @var string
65     */
66    private $type;
67    /**
68     * @var array
69     */
70    private $domainValues;
71    /**
72     * @var FormMetaField[]
73     */
74    private $children;
75    /**
76     * @var int
77     */
78    private $width;
79    /**
80     * Multiple value can be chosen
81     * @var bool
82     */
83    private $multiple = false;
84
85
86    /**
87     * FormField constructor.
88     */
89    public function __construct($name)
90    {
91        $this->name = $name;
92        $this->label = ucfirst($name);
93        $this->description = $name;
94        $this->type = DataType::TEXT_TYPE_VALUE;
95        $this->mutable = true;
96    }
97
98    public static function create(string $name): FormMetaField
99    {
100        return new FormMetaField($name);
101    }
102
103    /**
104     * Almost because a form does not allow hierarchical data
105     * We send an error in this case
106     * @param Metadata $metadata
107     * @return FormMetaField
108     * @throws ExceptionCombo
109     */
110    public static function createFromMetadata(Metadata $metadata): FormMetaField
111    {
112        $field = FormMetaField::create($metadata->getName());
113
114        self::setCommonDataToFieldFromMetadata($field, $metadata);
115
116        $childrenMetadata = $metadata->getChildrenClass();
117
118        if ($metadata->getParent() === null) {
119            /**
120             * Only the top field have a tab value
121             */
122            $field->setTab($metadata->getTab());
123        }
124
125
126        /**
127         * No children
128         */
129        if ($childrenMetadata === null) {
130
131            static::setLeafDataToFieldFromMetadata($field, $metadata);
132
133            // Value
134            $value = $metadata->toStoreValue();
135            $defaultValue = $metadata->toStoreDefaultValue();
136            $field->addValue($value, $defaultValue);
137
138        } else {
139
140            if ($metadata instanceof MetadataTabular) {
141
142                $childFields = [];
143                foreach ($metadata->getChildrenClass() as $childMetadataClass) {
144
145                    $childMetadata = Metadata::toMetadataObject($childMetadataClass, $metadata);
146                    $childField = FormMetaField::create($childMetadata);
147                    static::setCommonDataToFieldFromMetadata($childField, $childMetadata);
148                    static::setLeafDataToFieldFromMetadata($childField, $childMetadata);
149                    $field->addColumn($childField);
150                    $childFields[$childMetadata::getPersistentName()] = $childField;
151                }
152                $rows = $metadata->getValue();
153                if ($rows !== null) {
154
155                    $defaultRow = null;
156                    $defaultRows = $metadata->getDefaultValue();
157                    if ($defaultRows !== null) {
158                        $defaultRow = $defaultRows[0];
159                    }
160
161                    foreach ($rows as $row) {
162                        foreach ($childFields as $childName => $childField) {
163                            $colValue = $row[$childName];
164                            if ($colValue === null) {
165                                if ($defaultRow === null) {
166                                    continue;
167                                }
168                                $colValue = $defaultRow[$childName];
169                                if ($colValue === null) {
170                                    continue;
171                                }
172                            }
173                            $childField->addValue($colValue->toStoreValue(), $colValue->toStoreDefaultValue());
174                        }
175
176                    }
177
178                    // Add an extra empty row to allow adding an image
179                    if ($defaultRow !== null) {
180                        foreach ($defaultRow as $colName => $colValue) {
181                            $defaultColValue = null;
182                            if ($colValue !== null) {
183                                $defaultColValue = $colValue->toStoreDefaultValue();
184                            }
185                            $childField = $childFields[$colName];
186                            $childField->addValue(null, $defaultColValue);
187                        }
188                    }
189
190                } else {
191
192                    // Show the default rows
193                    $rows = $metadata->getDefaultValue();
194                    if ($rows !== null) {
195                        foreach ($rows as $row) {
196                            foreach ($row as $colName => $colValue) {
197                                if ($colValue === null) {
198                                    continue;
199                                }
200                                $childField = $childFields[$colName];
201                                $childField->addValue(null, $colValue->toStoreValue());
202                            }
203                        }
204                    }
205
206                }
207
208
209            } else {
210
211                LogUtility::msg("Hierarchical data is not supported in a form. Metadata ($metadata) has children and is not tabular");
212            }
213        }
214        return $field;
215
216    }
217
218
219    public
220    function toAssociativeArray(): array
221    {
222        /**
223         * Mandatory attributes
224         */
225        $associative = [
226            ResourceName::PROPERTY_NAME => $this->name,
227            self::LABEL_ATTRIBUTE => $this->label,
228            DataType::PROPERTY_NAME => $this->type
229        ];
230        if ($this->getUrl() != null) {
231            $associative[self::URL_ATTRIBUTE] = $this->getUrl();
232        }
233        if ($this->description != null) {
234            $associative[self::DESCRIPTION_ATTRIBUTE] = $this->description;
235        }
236        /**
237         * For child form field (ie column), there is no tab
238         */
239        if ($this->tab != null) {
240            $associative[self::TAB_ATTRIBUTE] = $this->tab;
241        }
242
243
244        if ($this->width !== null) {
245            $associative[self::WIDTH_ATTRIBUTE] = $this->width;
246        }
247        if ($this->children !== null) {
248            foreach ($this->children as $column) {
249                $associative[self::CHILDREN_ATTRIBUTE][] = $column->toAssociativeArray();
250            }
251        } else {
252
253            /**
254             * Only valid for leaf field
255             */
256            if ($this->getValue() !== null) {
257                $associative[self::VALUE_ATTRIBUTE] = $this->getValue();
258            }
259
260            if ($this->getDefaultValue() !== null) {
261                $associative[self::DEFAULT_VALUE_ATTRIBUTE] = $this->getDefaultValue();
262            }
263
264            if ($this->domainValues !== null) {
265                $associative[self::DOMAIN_VALUES_ATTRIBUTE] = $this->domainValues;
266                if ($this->multiple) {
267                    $associative[self::MULTIPLE_ATTRIBUTE] = $this->multiple;
268                }
269            }
270
271            $associative[self::MUTABLE_ATTRIBUTE] = $this->mutable;
272
273
274        }
275
276
277        return $associative;
278    }
279
280    public
281    function setMutable(bool $bool): FormMetaField
282    {
283        $this->mutable = $bool;
284        return $this;
285    }
286
287
288    public
289    function setTab(string $tabName): FormMetaField
290    {
291        Html::validNameGuard($tabName);
292        $this->tab = $tabName;
293        return $this;
294    }
295
296    public
297    function setLabel(string $label): FormMetaField
298    {
299        $this->label = $label;
300        return $this;
301    }
302
303    public
304    function getUrl(): ?string
305    {
306        if ($this->canonical == null) {
307            return null;
308        }
309        $url = PluginUtility::$URL_APEX;
310        $url .= "/" . str_replace(":", "/", $this->canonical);
311        return $url;
312    }
313
314    public
315    function setCanonical(string $canonical): FormMetaField
316    {
317        $this->canonical = $canonical;
318        return $this;
319    }
320
321    public
322    function setDescription(string $string): FormMetaField
323    {
324        $this->description = $string;
325        return $this;
326    }
327
328    /**
329     * @param $value
330     * @param null $defaultValuePlaceholderOrReturned - the value set as placeholder or return value for a checked checkbox
331     * @return $this
332     */
333    public
334    function addValue($value, $defaultValuePlaceholderOrReturned = null): FormMetaField
335    {
336        $this->values[] = $value;
337        $this->defaults[] = $defaultValuePlaceholderOrReturned;
338        return $this;
339    }
340
341    public
342    function setType(string $type): FormMetaField
343    {
344        if (!in_array($type, DataType::TYPES)) {
345            LogUtility::msg("The type ($type) is not a known field type");
346            return $this;
347        }
348        $this->type = $type;
349        return $this;
350    }
351
352    public
353    function setDomainValues(array $domainValues): FormMetaField
354    {
355        $this->domainValues = $domainValues;
356        return $this;
357    }
358
359    public
360    function addColumn(FormMetaField $formField): FormMetaField
361    {
362        $this->type = DataType::TABULAR_TYPE_VALUE;
363        // A parent node is not mutable
364        $this->mutable = false;
365        $this->children[] = $formField;
366        return $this;
367    }
368
369    public
370    function setWidth(int $int): FormMetaField
371    {
372        $this->width = $int;
373        return $this;
374    }
375
376    public
377    function getTab(): string
378    {
379        return $this->tab;
380    }
381
382    public
383    function getName()
384    {
385        return $this->name;
386    }
387
388    public
389    function getValue()
390    {
391        switch (sizeof($this->values)) {
392            case 0:
393                return null;
394            case 1:
395                $value = $this->values[0];
396                if ($value !== null) {
397                    return $this->values[0];
398                }
399                return null;
400            default:
401                return $this->values;
402        }
403    }
404
405    public
406    function isMutable(): bool
407    {
408        return $this->mutable;
409    }
410
411    public
412    function getChildren(): ?array
413    {
414        return $this->children;
415    }
416
417    public
418    function getType(): string
419    {
420        return $this->type;
421    }
422
423    public
424    function getDefaultValue()
425    {
426        switch (sizeof($this->defaults)) {
427            case 0:
428                return null;
429            case 1:
430                $value = $this->defaults[0];
431                if ($value !== null) {
432                    return $value;
433                }
434                return null;
435            default:
436                return $this->defaults;
437        }
438    }
439
440    public
441    function setMultiple(bool $bool): FormMetaField
442    {
443        $this->multiple = $bool;
444        return $this;
445    }
446
447    public
448    function isMultiple(): bool
449    {
450        return $this->multiple;
451    }
452
453    /**
454     * If this is a scalar value, you can set/overwrite the value
455     * with this function
456     * @param $value
457     * @param null $default
458     * @return $this
459     */
460    public
461    function setValue($value, $default = null): FormMetaField
462    {
463        $this->values = [];
464        $this->defaults = [];
465        return $this->addValue($value, $default);
466
467    }
468
469    /**
470     * Common metadata to all field from a leaf to a tabular
471     * @param FormMetaField $field
472     * @param Metadata $metadata
473     */
474    private
475    static
476    function setCommonDataToFieldFromMetadata(FormMetaField $field, Metadata $metadata)
477    {
478        $field->setType($metadata->getDataType())
479            ->setCanonical($metadata->getCanonical())
480            ->setLabel($metadata->getLabel())
481            ->setDescription($metadata->getDescription());
482    }
483
484    /**
485     * @param FormMetaField $field
486     * @param Metadata $metadata
487     * Add the field metadata that are only available for leaf metadata
488     */
489    private
490    static
491    function setLeafDataToFieldFromMetadata(FormMetaField $field, Metadata $metadata)
492    {
493        $field->setMutable($metadata->getMutable());
494
495        $formControlWidth = $metadata->getFormControlWidth();
496        if ($formControlWidth !== null) {
497            $field->setWidth($formControlWidth);
498        }
499        $possibleValues = $metadata->getPossibleValues();
500        if ($possibleValues !== null) {
501            $field->setDomainValues($possibleValues);
502            if ($metadata instanceof MetadataMultiple) {
503                $field->setMultiple(true);
504            }
505        }
506
507    }
508
509}
510