From b17fa5831e8903fadd32585d85bb6233b401206e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milo=C5=A1=20Brecher?= <34324008+mildabre@users.noreply.github.com> Date: Sat, 3 Aug 2024 23:00:32 +0200 Subject: [PATCH] Automatic conversion enum/int - when mapping to class Nette forms doesnt support data type Enum when mapping form values to class. This makes problems when using forms - see error reported here: https://forum.nette.org/cs/36594-prevod-vybraneho-optionu-v-selectu-na-enum-type The fix isnt complicated and makes no BC break. The case is in more details discussed here: https://forum.nette.org/cs/36601-rfc-konverze-na-datovy-typ-enum-a-int-pri-mapovani-hodnot-formulare --- src/Forms/Container.php | 37 +++++++++++++++++++++++++++++++++++-- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/src/Forms/Container.php b/src/Forms/Container.php index 4369d79a..51cd9939 100644 --- a/src/Forms/Container.php +++ b/src/Forms/Container.php @@ -153,7 +153,13 @@ public function getUntrustedValues(string|object|null $returnType = null, ?array && $allowed && !$control->isOmitted() ) { - $obj->$name = $control->getValue(); + $value = $control->getValue(); + $property = $rc->hasProperty($name)? $rc->getProperty($name) : null; + $obj->$name = $property ? match(true){ + static::isPropertyEnum($property) => static::getEnumCaseByName($property->getType()->getName(), $value), + Helpers::getSingleType($property) === 'int' => static::stringToInt($value, $name), + default => $value, + } : $value; } elseif ($control instanceof self) { $type = $returnType === self::Array && !$control->mappedType @@ -172,7 +178,34 @@ public function getUntrustedValues(string|object|null $returnType = null, ?array : $obj; } - + + private static function isPropertyEnum(ReflectionProperty $property): bool + { + return !$property->getType()->isBuiltin() && (new ReflectionClass($property->getType()->getName()))->isEnum(); + } + + + private static function getEnumCaseByName(string $class, ?string $name): ?object + { + foreach($class::cases() as $case){ + if($case->name === $name){ + return $case; + } + } + return null; + } + + + private static function stringToInt(?string $value, string $name): ?int + { + if($value === null){ + return $value; + } + $intValue = (int)$value; + return $value === (string)$intValue ? $intValue : throw new InvalidValueException("Value '$value' of field '$name' is not valid integer number"); + } + + /** @deprecated use getUntrustedValues() */ public function getUnsafeValues($returnType, ?array $controls = null) {