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