-
-
Notifications
You must be signed in to change notification settings - Fork 131
Added new type-safe API that allows validating a given value against a given class-string<Enum>
#143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Added new type-safe API that allows validating a given value against a given class-string<Enum>
#143
Changes from 1 commit
96598da
ec76a45
6262a50
74b9e22
be511e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
…a given `class-string<Enum>` This patch introduces two new methods: * `Enum::isValidEnumValue()` * `Enum::assertValidEnumValue()` The `Enum::isValidEnumValue()` is still wonky due to vimeo/psalm#5372, but overall, this allows for matching against other `Enum` sub-types, by validating that a given `$value` is effectively a subtype of `T` within an `Enum<T>`. The previous approach did **not** work, because static method types are not coupled with the class they are put on (they are effectively namespaced functions, and not much else). In here, we also: * completed test coverage for `Enum::from()` * pinned `vimeo/psalm:4.6.2`, mostly for build stability * added coverage mapping for `phpunit.xml`
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -212,23 +212,55 @@ public static function toArray() | |
| * @psalm-param mixed $value | ||
| * @psalm-pure | ||
| * @return bool | ||
| * | ||
| * deprecated use {@see Enum::isValidEnumValue()} instead | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not yet |
||
| */ | ||
| public static function isValid($value) | ||
| { | ||
| return \in_array($value, static::toArray(), true); | ||
| } | ||
|
|
||
| /** | ||
| * Asserts valid enum value | ||
| * | ||
| * @psalm-pure | ||
| * @psalm-template CheckedValueType | ||
| * @psalm-param class-string<self<CheckedValueType>> $enumType | ||
| * @param mixed $value | ||
| * @psalm-assert-if-true CheckedValueType $value | ||
| */ | ||
| public static function isValidEnumValue(string $enumType, $value): bool | ||
| { | ||
| return $enumType::isValid($value); | ||
| } | ||
|
|
||
| /** | ||
| * Asserts valid enum value | ||
| * | ||
| * @psalm-pure | ||
| * @param mixed $value | ||
| * | ||
| * deprecated use {@see Enum::assertValidEnumValue()} instead | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not yet |
||
| */ | ||
| public static function assertValidValue($value): void | ||
| { | ||
| self::assertValidValueReturningKey($value); | ||
| } | ||
|
|
||
| /** | ||
| * Asserts valid enum value | ||
| * | ||
| * @psalm-pure | ||
| * @psalm-template ValueType | ||
| * @psalm-param class-string<self<ValueType>> $enumType | ||
| * @param mixed $value | ||
| * @psalm-assert ValueType $value | ||
| */ | ||
| public static function assertValidEnumValue(string $enumType, $value): void | ||
| { | ||
| $enumType::assertValidValue($value); | ||
| } | ||
|
|
||
| /** | ||
| * Asserts valid enum value | ||
| * | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -34,6 +34,18 @@ function canValidateValue($input): string | |
| return $input; | ||
| } | ||
|
|
||
| /** | ||
| * @psalm-pure | ||
| * @param mixed $input | ||
| * @psalm-return 'A'|'C' | ||
| */ | ||
| function canAssertValidEnumValue($input): string | ||
| { | ||
| ValidationEnum::assertValidEnumValue(ValidationEnum::class, $input); | ||
|
|
||
| return $input; | ||
| } | ||
|
|
||
| /** | ||
| * @psalm-pure | ||
| * @param mixed $input | ||
|
|
@@ -52,3 +64,20 @@ function canValidateValueThroughIsValid($input): string | |
|
|
||
| return $input; | ||
| } | ||
|
|
||
| /** | ||
| * @psalm-pure | ||
| * @param mixed $input | ||
| * @psalm-return 'A'|'C'|1 | ||
| * | ||
| * @psalm-suppress InvalidReturnType https://github.com/vimeo/psalm/issues/5372 | ||
| * @psalm-suppress InvalidReturnStatement https://github.com/vimeo/psalm/issues/5372 | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. vimeo/psalm#5372 is still kinda blocking this |
||
| */ | ||
| function canValidateValueThroughIsValidEnumValue($input) | ||
| { | ||
| if (! ValidationEnum::isValidEnumValue(ValidationEnum::class, $input)) { | ||
| return 1; | ||
| } | ||
|
|
||
| return $input; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,6 +6,8 @@ | |
|
|
||
| namespace MyCLabs\Tests\Enum; | ||
|
|
||
| use MyCLabs\Enum\Enum; | ||
|
|
||
| /** | ||
| * @author Matthieu Napoli <[email protected]> | ||
| * @author Daniel Costa <[email protected]> | ||
|
|
@@ -59,6 +61,27 @@ public function testFailToCreateEnumWithInvalidValueThroughNamedConstructor($val | |
| EnumFixture::from($value); | ||
| } | ||
|
|
||
| /** | ||
| * @dataProvider invalidValueProvider | ||
| * @param mixed $value | ||
| */ | ||
| public function testRejectInvalidEnumValueWhenAssertingOnIt($value): void | ||
| { | ||
| $this->expectException(\UnexpectedValueException::class); | ||
| $this->expectExceptionMessage('is not part of the enum MyCLabs\Tests\Enum\EnumFixture'); | ||
|
|
||
| Enum::assertValidEnumValue(EnumFixture::class, $value); | ||
| } | ||
|
|
||
| /** | ||
| * @dataProvider invalidValueProvider | ||
| * @param mixed $value | ||
| */ | ||
| public function testReportsFalseOnNonValidEnumValueUponChecking($value): void | ||
| { | ||
| self::assertFalse(Enum::isValidEnumValue(EnumFixture::class, $value)); | ||
| } | ||
|
|
||
| public function testFailToCreateEnumWithEnumItselfThroughNamedConstructor(): void | ||
| { | ||
| $this->expectException(\UnexpectedValueException::class); | ||
|
|
@@ -67,6 +90,11 @@ public function testFailToCreateEnumWithEnumItselfThroughNamedConstructor(): voi | |
| EnumFixture::from(EnumFixture::FOO()); | ||
| } | ||
|
|
||
| public function testCreateEnumWithValidEnumValueThroughNamedConstructor(): void | ||
| { | ||
| self::assertEquals(EnumFixture::FOO(), EnumFixture::from('foo')); | ||
| } | ||
|
|
||
| /** | ||
| * Contains values not existing in EnumFixture | ||
| * @return array | ||
|
|
@@ -179,7 +207,8 @@ public function testBadStaticAccess() | |
| */ | ||
| public function testIsValid($value, $isValid) | ||
| { | ||
| $this->assertSame($isValid, EnumFixture::isValid($value)); | ||
| self::assertSame($isValid, EnumFixture::isValid($value)); | ||
| self::assertSame($isValid, Enum::isValidEnumValue(EnumFixture::class, $value)); | ||
| } | ||
|
|
||
| public function isValidProvider() | ||
|
|
@@ -381,4 +410,19 @@ public function testAssertValidValue($value, $isValid): void | |
|
|
||
| self::assertTrue(EnumFixture::isValid($value)); | ||
| } | ||
|
|
||
| /** | ||
| * @dataProvider isValidProvider | ||
| */ | ||
| public function testAssertValidValueWithTypedApi($value, $isValid): void | ||
| { | ||
| if (!$isValid) { | ||
| $this->expectException(\UnexpectedValueException::class); | ||
| $this->expectExceptionMessage("Value '$value' is not part of the enum " . EnumFixture::class); | ||
| } | ||
|
|
||
| Enum::assertValidEnumValue(EnumFixture::class, $value); | ||
|
|
||
| self::assertTrue(Enum::isValidEnumValue(EnumFixture::class, $value)); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pinned: changing this dependency is too fragile for builds to be kept stable.
My suggestion is to instead use dependabot to regularly keep it updated.