File modules/util/Hydrator.class.php
Last commit: Wed Oct 14 01:41:42 2026 +0200 Jan Dankert Saving values with the new object-oriented ui objects.
1 <?php 2 declare(strict_types=1); 3 4 namespace util; 5 6 use cms\api\ArrayOf; 7 use InvalidArgumentException; 8 use ReflectionClass; 9 use ReflectionNamedType; 10 use ReflectionType; 11 use UnitEnum; 12 13 class Hydrator { 14 /** 15 * Konvertiert ein Objekt (und alle darin enthaltenen Objekte/Arrays) rekursiv in ein Array. 16 */ 17 public static function toArray($data) { 18 // Wenn es ein Objekt ist, holen wir uns die sichtbaren Eigenschaften 19 if (is_object($data)) { 20 $data = get_object_vars($data); 21 } 22 23 // Wenn es ein Array ist (oder durch get_object_vars dazu wurde), gehen wir tiefer 24 if (is_array($data)) { 25 $result = []; 26 foreach ($data as $key => $value) { 27 $result[$key] = self::toArray($value); // Rekursiver Aufruf 28 } 29 return $result; 30 } 31 32 // Skalare Werte (string, int, bool) werden einfach zurückgegeben 33 return $data; 34 } 35 36 37 public static function map(string $targetClass, array $data): object 38 { 39 $reflection = new ReflectionClass($targetClass); 40 $constructor = $reflection->getConstructor(); 41 42 if (!$constructor) { 43 $instance = $reflection->newInstanceWithoutConstructor(); 44 foreach ($data as $key => $value) { 45 if ($reflection->hasProperty($key)) { 46 $property = $reflection->getProperty($key); 47 $property->setValue($instance, self::mapValue($property->getType(), $value)); 48 } 49 } 50 return $instance; 51 } 52 53 $arguments = []; 54 foreach ($constructor->getParameters() as $parameter) { 55 $name = $parameter->getName(); 56 $type = $parameter->getType(); 57 58 if (array_key_exists($name, $data)) { 59 // PRÜFUNG: Hat der Parameter das #[MapArray]-Attribut? 60 $mapArrayAttr = $parameter->getAttributes(ArrayOf::class); 61 62 if (!empty($mapArrayAttr) && is_array($data[$name])) { 63 // Wenn ja, mappen wir jedes Element im Array rekursiv 64 $targetInnerClass = $mapArrayAttr[0]->newInstance()->className; 65 $arguments[] = array_map( 66 fn($item) => is_array($item) ? self::map($targetInnerClass, $item) : $item, 67 $data[$name] 68 ); 69 } else { 70 // Normales Mapping für Einzelwerte/Objekte 71 $arguments[] = self::mapValue($type, $data[$name]); 72 } 73 } elseif ($parameter->isDefaultValueAvailable()) { 74 $arguments[] = $parameter->getDefaultValue(); 75 } else { 76 if ( $parameter->allowsNull() ) 77 $arguments[] = null; 78 else 79 throw new InvalidArgumentException("Missing value '$name' in type '$targetClass'"); 80 } 81 } 82 83 return $reflection->newInstanceArgs($arguments); 84 } 85 86 private static function mapValue(?ReflectionType $type, mixed $value): mixed 87 { 88 if (!$type || $value === null) { 89 return $value; 90 } 91 92 if ($type instanceof ReflectionNamedType && !$type->isBuiltin()) { 93 $className = $type->getName(); 94 95 if (is_subclass_of($className, UnitEnum::class)) { 96 return $className::from($value); 97 } 98 99 if (is_array($value)) { 100 return self::map($className, $value); 101 } 102 } 103 104 return $value; 105 } 106 107 }
Downloadmodules/util/Hydrator.class.php
History Wed, 14 Oct 2026 01:41:42 +0200 Jan Dankert Saving values with the new object-oriented ui objects. Tue, 13 Oct 2026 22:52:59 +0200 Jan Dankert New: The UI is now able to send hierarchical form data and the server is converting it into an object. This is a very nice feature, because this enables a better OpenAPI interface. Tue, 13 Oct 2026 00:25:36 +0200 Jan Dankert New: Using Objects as return value in Action methods. With this change the creation of OpenAPI is much easier. This is a POC, the other methods follow from time to time.