From b0729e89f3015354361d6fdb05a001a7e2909f35 Mon Sep 17 00:00:00 2001 From: calavera Date: Fri, 19 Dec 2025 08:19:03 +0100 Subject: [PATCH 1/2] feat: non breaking strict mode for EnumFrom@wrap --- src/Traits/EnumFrom.php | 49 +++++++++++++++++++++++++---------------- tests/EnumFromTest.php | 10 +++++++++ 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/src/Traits/EnumFrom.php b/src/Traits/EnumFrom.php index 436b7cb..fd07905 100644 --- a/src/Traits/EnumFrom.php +++ b/src/Traits/EnumFrom.php @@ -11,29 +11,40 @@ trait EnumFrom use EnumEquality; /** - * Gets the Enum by name, value or another enum. - */ - public static function wrap(self|string|int|null $value): ?self - { - if ($value instanceof self || is_null($value)) { - return $value; - } - - $enum = null; - if (is_string($value) && self::isIntBacked()) { - if(is_numeric($value)){ - $enum = self::tryFrom(intval($value)); - } - } else { - $enum = self::tryFrom($value); - } + * Gets the Enum by name, value or another enum. + * + * @param self|string|int|null $value The value to wrap as the enum. If an instance of the enum is passed it is returned unchanged. + * Strings are treated as either backing values (for int-backed enums) or names. + * @param bool $strict When true, the method throws a {@see ValueError} if the given value cannot be converted to a valid enum. + * When false (default), the method returns null on failure. + * @return ?self The matched enum instance, or null if no match is found and `$strict` is false. + * @throws \ValueError If `$strict` is true and the value is not a valid enum name or backing value. + */ +public static function wrap(self|string|int|null $value, bool $strict = false): ?self +{ + if ($value instanceof self || is_null($value)) { + return $value; + } - if ($enum === null && is_string($value)) { - $enum = self::tryFromName($value); + $enum = null; + if (is_string($value) && self::isIntBacked()) { + if(is_numeric($value)){ + $enum = self::tryFrom(intval($value)); } + } else { + $enum = self::tryFrom($value); + } - return $enum; + if ($enum === null && is_string($value)) { + $enum = self::tryFromName($value); } + + if (is_null($enum) and $strict) { + throw new ValueError('"'.$value.'" is not a valid backing value for enum "'.self::class.'"'); + } + + return $enum; +} /** * Gets the Enum by name, if it exists, for "Pure" enums. diff --git a/tests/EnumFromTest.php b/tests/EnumFromTest.php index fd1344b..bbe4a08 100644 --- a/tests/EnumFromTest.php +++ b/tests/EnumFromTest.php @@ -46,6 +46,16 @@ 'String Backed Enum' => [StringBackedEnum::class, 'M'], ]); +it('throws ValueError for invalid backing value in strict mode', function () { + expect(fn () => StringBackedEnum::wrap('non-existent-value', true)) + ->toThrow(ValueError::class); +}); + +it('returns null for invalid backing value when not in strict mode', function() { + expect(StringBackedEnum::wrap('non-existent-value')) + ->toBeNull(); +}); + it('does work with tryFrom method', function ($enumCass, $value, $result) { expect($enumCass::tryFrom($value))->toBe($result)->not->toThrow(ValueError::class); })->with([ From b496a66b1c815c361ed97e22fae264b5037077f8 Mon Sep 17 00:00:00 2001 From: calavera Date: Fri, 19 Dec 2025 08:20:50 +0100 Subject: [PATCH 2/2] composer format --- src/Traits/EnumFrom.php | 42 ++++++++++++++++++------------------ src/Traits/EnumInvokable.php | 2 +- tests/EnumFromTest.php | 2 +- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/src/Traits/EnumFrom.php b/src/Traits/EnumFrom.php index fd07905..51b75a5 100644 --- a/src/Traits/EnumFrom.php +++ b/src/Traits/EnumFrom.php @@ -20,31 +20,31 @@ trait EnumFrom * @return ?self The matched enum instance, or null if no match is found and `$strict` is false. * @throws \ValueError If `$strict` is true and the value is not a valid enum name or backing value. */ -public static function wrap(self|string|int|null $value, bool $strict = false): ?self -{ - if ($value instanceof self || is_null($value)) { - return $value; - } + public static function wrap(self|string|int|null $value, bool $strict = false): ?self + { + if ($value instanceof self || is_null($value)) { + return $value; + } - $enum = null; - if (is_string($value) && self::isIntBacked()) { - if(is_numeric($value)){ - $enum = self::tryFrom(intval($value)); + $enum = null; + if (is_string($value) && self::isIntBacked()) { + if (is_numeric($value)) { + $enum = self::tryFrom(intval($value)); + } + } else { + $enum = self::tryFrom($value); } - } else { - $enum = self::tryFrom($value); - } - if ($enum === null && is_string($value)) { - $enum = self::tryFromName($value); - } - - if (is_null($enum) and $strict) { - throw new ValueError('"'.$value.'" is not a valid backing value for enum "'.self::class.'"'); - } + if ($enum === null && is_string($value)) { + $enum = self::tryFromName($value); + } - return $enum; -} + if (is_null($enum) and $strict) { + throw new ValueError('"'.$value.'" is not a valid backing value for enum "'.self::class.'"'); + } + + return $enum; + } /** * Gets the Enum by name, if it exists, for "Pure" enums. diff --git a/src/Traits/EnumInvokable.php b/src/Traits/EnumInvokable.php index 7e28ce4..3727e30 100644 --- a/src/Traits/EnumInvokable.php +++ b/src/Traits/EnumInvokable.php @@ -26,7 +26,7 @@ public static function __callStatic(string $enumName, array $args): string|int { foreach (self::cases() as $case) { $check1 = strtolower($case->name); - $check2 = str_replace('_', '',strtolower($case->name)); + $check2 = str_replace('_', '', strtolower($case->name)); if ( $check1 === strtolower($enumName) || $check1 === strtolower(self::snake($enumName)) diff --git a/tests/EnumFromTest.php b/tests/EnumFromTest.php index bbe4a08..f278282 100644 --- a/tests/EnumFromTest.php +++ b/tests/EnumFromTest.php @@ -51,7 +51,7 @@ ->toThrow(ValueError::class); }); -it('returns null for invalid backing value when not in strict mode', function() { +it('returns null for invalid backing value when not in strict mode', function () { expect(StringBackedEnum::wrap('non-existent-value')) ->toBeNull(); });