1<?php 2 3 4namespace ComboStrap; 5 6use http\Exception\RuntimeException; 7 8/** 9 * Class FormMeta 10 * @package ComboStrap 11 * 12 * Represents form metadata sends via an ajax request 13 * 14 * It makes sure that the data send 15 * is coherent 16 */ 17class FormMeta 18{ 19 20 const FORM_TYPES = [self::FORM_NAV_TABS_TYPE, self::FORM_LIST_GROUP_TYPE]; 21 const FORM_NAV_TABS_TYPE = "nav-tabs"; 22 const FORM_LIST_GROUP_TYPE = "list-group"; 23 const FIELDS_ATTRIBUTE = "fields"; 24 25 private $name; 26 27 /** 28 * @var FormMetaField[] 29 */ 30 private $fields; 31 /** 32 * @var FormMetaTab[]|string[] 33 */ 34 private $tabs; 35 /** 36 * @var string 37 */ 38 private $type; 39 40 /** 41 * @throws ExceptionComboRuntime 42 */ 43 public function __construct($name) 44 { 45 Html::validNameGuard($name); 46 $this->name = $name; 47 } 48 49 50 public static function create($name): FormMeta 51 { 52 return new FormMeta($name); 53 } 54 55 public function addField(FormMetaField $formField): FormMeta 56 { 57 $this->fields[] = $formField; 58 $tab = $formField->getTab(); 59 if (!empty($tab) && !isset($this->tabs[$tab])) { 60 $this->tabs[$tab] = $tab; 61 } 62 return $this; 63 } 64 65 public function addTab(FormMetaTab $tab): FormMeta 66 { 67 $this->tabs[$tab->getName()] = $tab; 68 return $this; 69 } 70 71 public function toAssociativeArray(): array 72 { 73 74 $fieldsArray = []; 75 foreach ($this->fields as $element) { 76 /** 77 * The order is kept even if we add a key 78 */ 79 $fieldsArray[$element->getName()] = $element->toAssociativeArray(); 80 } 81 $tabs = []; 82 foreach ($this->tabs as $element) { 83 if (!($element instanceof FormMetaTab)) { 84 $tab = FormMetaTab::create($element); 85 } else { 86 $tab = $element; 87 } 88 /** 89 * The order is kept even if we add a key 90 */ 91 $tabs[$tab->getName()] = $tab->toAssociativeArray(); 92 } 93 return [ 94 self::FIELDS_ATTRIBUTE => $fieldsArray, 95 "tabs" => $tabs 96 ]; 97 } 98 99 /** 100 * ie nav-tabs versus list-group: 101 * https://getbootstrap.com/docs/5.0/components/list-group/#javascript-behavior 102 * 103 * @param string $type 104 * @return FormMeta 105 */ 106 public function setType(string $type): FormMeta 107 { 108 if (!in_array($type, self::FORM_TYPES)) { 109 LogUtility::msg("The form type ($type) is unknown"); 110 return $this; 111 } 112 $this->type = $type; 113 return $this; 114 } 115 116 /** 117 * The data as if it was send by a HTML form to the 118 * post endpoint 119 * 120 * It transforms the fields to an associative array 121 * that should be send with a post request 122 * 123 * ie Equivalent to the javascript api formdata output 124 * (Used in test to simulate a post) 125 * 126 * TODO: Not sure but with the {@link MetadataStore}, this should move to the class 127 * where the target/read store is a {@link MetadataFormDataStore} ? 128 */ 129 public function toFormData(): array 130 { 131 $data = []; 132 $this->toFormDataRecurse($data, $this->fields); 133 return $data; 134 } 135 136 /** 137 * @param $data 138 * @param FormMetaField[] $fields 139 */ 140 private function toFormDataRecurse(&$data, array $fields) 141 { 142 143 foreach ($fields as $field) { 144 145 if ($field->isMutable()) { 146 147 $value = $field->getValue(); 148 if ($field->getType() === DataType::BOOLEAN_TYPE_VALUE) { 149 if ($value === $field->getDefaultValue() || $value === null) { 150 continue; 151 } 152 } 153 if ($value === null) { 154 // A form would return empty string 155 $value = ""; 156 } 157 if (is_array($value)) { 158 $temp = []; 159 foreach ($value as $subValue) { 160 if ($subValue === null) { 161 $temp[] = ""; 162 } else { 163 if (is_array($subValue) && $field->isMultiple()) { 164 $temp[] = implode(",", $subValue); 165 } else { 166 $temp[] = $subValue; 167 } 168 } 169 } 170 $value = $temp; 171 } 172 $data[$field->getName()] = $value; 173 174 } 175 $formMetaChildren = $field->getChildren(); 176 if ($formMetaChildren != null) { 177 $this->toFormDataRecurse($data, $formMetaChildren); 178 } 179 } 180 181 } 182 183 /** 184 * @param Metadata $metadata 185 * @return FormMeta 186 * @throws ExceptionCombo 187 */ 188 public function addFormFieldFromMetadata(Metadata $metadata): FormMeta 189 { 190 $field = FormMetaField::createFromMetadata($metadata); 191 $this->addField($field); 192 return $this; 193 } 194 195 196} 197