-
-
Notifications
You must be signed in to change notification settings - Fork 131
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
Added new type-safe API that allows validating a given value against a given class-string<Enum>
#143
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 all commits
96598da
ec76a45
6262a50
74b9e22
be511e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,10 +1,11 @@ | ||
<?xml version="1.0"?> | ||
<psalm | ||
totallyTyped="true" | ||
resolveFromConfigFile="true" | ||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xmlns="https://getpsalm.org/schema/config" | ||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd" | ||
restrictReturnTypes="true" | ||
findUnusedPsalmSuppress="true" | ||
totallyTyped="true" | ||
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. Psalm docs say this is deprecated, might be dropped as level is max already https://psalm.dev/docs/running_psalm/configuration/#totallytyped 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. With 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. Agree, it's a bit out of scope but has been touched already so 🤷🏾 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. Yeah, I generally remove |
||
> | ||
<projectFiles> | ||
<directory name="src" /> | ||
|
@@ -16,8 +17,6 @@ | |
</projectFiles> | ||
|
||
<issueHandlers> | ||
<MixedAssignment errorLevel="info" /> | ||
|
||
<ImpureStaticProperty> | ||
<!-- self::$... usages in Enum are used to populate an internal cache, and cause no side-effects --> | ||
<errorLevel type="suppress"> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -93,9 +93,10 @@ public function __wakeup() | |
} | ||
|
||
/** | ||
* @psalm-pure | ||
* @param mixed $value | ||
* @return static | ||
* @psalm-return static<T> | ||
* @psalm-return static | ||
*/ | ||
public static function from($value): self | ||
{ | ||
|
@@ -127,7 +128,6 @@ public function getKey() | |
|
||
/** | ||
* @psalm-pure | ||
* @psalm-suppress InvalidCast | ||
* @return string | ||
*/ | ||
public function __toString() | ||
|
@@ -187,7 +187,6 @@ public static function values() | |
* Returns all possible values as an array | ||
* | ||
* @psalm-pure | ||
* @psalm-suppress ImpureStaticProperty | ||
* | ||
* @psalm-return array<string, mixed> | ||
* @return array Constant name in key, constant value in value | ||
|
@@ -212,8 +211,9 @@ public static function toArray() | |
* @param $value | ||
* @psalm-param mixed $value | ||
* @psalm-pure | ||
* @psalm-assert-if-true T $value | ||
* @return bool | ||
* | ||
* deprecated use {@see Enum::isValidEnumValue()} instead | ||
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) | ||
{ | ||
|
@@ -224,8 +224,23 @@ public static function isValid($value) | |
* Asserts valid enum value | ||
* | ||
* @psalm-pure | ||
* @psalm-assert T $value | ||
* @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 | ||
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 | ||
{ | ||
|
@@ -236,7 +251,20 @@ public static function assertValidValue($value): void | |
* Asserts valid enum value | ||
* | ||
* @psalm-pure | ||
* @psalm-assert T $value | ||
* @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 | ||
* | ||
* @psalm-pure | ||
* @param mixed $value | ||
* @return string | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace MyCLabs\Tests\Enum\StaticAnalysis; | ||
|
||
use MyCLabs\Enum\Enum; | ||
|
||
/** | ||
* @psalm-immutable | ||
* @psalm-template T of 'A'|'C' | ||
* @template-extends Enum<T> | ||
*/ | ||
final class InstantiatedEnum extends Enum | ||
{ | ||
const A = 'A'; | ||
const C = 'C'; | ||
} | ||
|
||
/** | ||
* @psalm-pure | ||
* @psalm-return InstantiatedEnum<'A'> | ||
*/ | ||
function canCallConstructorWithConstantValue(): InstantiatedEnum | ||
{ | ||
return new InstantiatedEnum('A'); | ||
} | ||
|
||
/** | ||
* @psalm-pure | ||
* @psalm-return InstantiatedEnum<'C'> | ||
*/ | ||
function canCallConstructorWithConstantReference(): InstantiatedEnum | ||
{ | ||
return new InstantiatedEnum(InstantiatedEnum::C); | ||
} | ||
|
||
/** @psalm-pure */ | ||
function canCallFromWithKnownValue(): InstantiatedEnum | ||
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. Notice how we CANNOT infer |
||
{ | ||
return InstantiatedEnum::from('C'); | ||
} | ||
|
||
/** @psalm-pure */ | ||
function canCallFromWithUnknownValue(): InstantiatedEnum | ||
{ | ||
return InstantiatedEnum::from(123123); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,7 @@ | |
* @method static PureEnum C() | ||
* | ||
* @psalm-immutable | ||
* @psalm-template T of 'A'|'B' | ||
* @psalm-template T of 'A'|'C' | ||
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 was a bug with this file - otherwise all good. |
||
* @template-extends Enum<T> | ||
*/ | ||
final class PureEnum extends Enum | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
|
||
namespace MyCLabs\Tests\Enum\StaticAnalysis; | ||
|
||
use MyCLabs\Enum\Enum; | ||
|
||
/** | ||
* @psalm-immutable | ||
* @psalm-template T of 'A'|'C' | ||
* @template-extends Enum<T> | ||
*/ | ||
final class ValidationEnum extends Enum | ||
{ | ||
const A = 'A'; | ||
const C = 'C'; | ||
} | ||
|
||
/** | ||
* @psalm-pure | ||
* @param mixed $input | ||
* @psalm-return 'A'|'C' | ||
* | ||
* @psalm-suppress MixedReturnStatement | ||
* @psalm-suppress MixedInferredReturnType at the time of this writing, we did not yet find | ||
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 comment is kinda oudated - perhaps I can drop the static analysis check overall, now that I designed |
||
* a proper approach to constraint input values through | ||
* validation via static methods. | ||
*/ | ||
function canValidateValue($input): string | ||
{ | ||
ValidationEnum::assertValidValue($input); | ||
|
||
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 | ||
* @psalm-return 'A'|'C' | ||
* | ||
* @psalm-suppress MixedReturnStatement | ||
* @psalm-suppress MixedInferredReturnType at the time of this writing, we did not yet find | ||
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 comment is kinda oudated - perhaps I can drop the static analysis check overall, now that I designed |
||
* a proper approach to constraint input values through | ||
* validation via static methods. | ||
*/ | ||
function canValidateValueThroughIsValid($input): string | ||
{ | ||
if (! ValidationEnum::isValid($input)) { | ||
throw new \InvalidArgumentException('Value not valid'); | ||
} | ||
|
||
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 | ||
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; | ||
} |
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.