v1.2.2
This commit is contained in:
parent
3a25585090
commit
80a2202d6e
18 changed files with 305 additions and 122 deletions
66
vendor/nette/schema/src/Schema/Helpers.php
vendored
66
vendor/nette/schema/src/Schema/Helpers.php
vendored
|
|
@ -9,7 +9,7 @@ namespace Nette\Schema;
|
|||
|
||||
use Nette;
|
||||
use Nette\Utils\Reflection;
|
||||
use function count, explode, get_debug_type, implode, in_array, is_array, is_float, is_int, is_object, is_scalar, is_string, method_exists, preg_match, preg_quote, preg_replace, preg_replace_callback, settype, str_replace, strlen, trim, var_export;
|
||||
use function array_map, count, explode, get_debug_type, implode, in_array, is_array, is_float, is_int, is_object, is_scalar, is_string, is_subclass_of, method_exists, preg_match, preg_quote, preg_replace, preg_replace_callback, settype, str_replace, strlen, trim, var_export;
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -54,6 +54,9 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the type of a property or parameter as a string, or null if not determinable.
|
||||
*/
|
||||
public static function getPropertyType(\ReflectionProperty|\ReflectionParameter $prop): ?string
|
||||
{
|
||||
if ($type = Nette\Utils\Type::fromReflection($prop)) {
|
||||
|
|
@ -89,6 +92,9 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Formats a value for use in error messages (e.g., 'hello', true, object stdClass).
|
||||
*/
|
||||
public static function formatValue(mixed $value): string
|
||||
{
|
||||
if ($value instanceof DynamicParameter) {
|
||||
|
|
@ -105,6 +111,9 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a TypeMismatch error to the context if the value does not match the expected type.
|
||||
*/
|
||||
public static function validateType(mixed $value, string $expected, Context $context): void
|
||||
{
|
||||
if (!Nette\Utils\Validators::is($value, $expected)) {
|
||||
|
|
@ -119,7 +128,10 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/** @param array{?float, ?float} $range */
|
||||
/**
|
||||
* Adds a range error to the context if the value (or its length for strings/arrays) is outside the given range.
|
||||
* @param array{?float, ?float} $range
|
||||
*/
|
||||
public static function validateRange(mixed $value, array $range, Context $context, string $types = ''): void
|
||||
{
|
||||
if (is_array($value) || is_string($value)) {
|
||||
|
|
@ -146,7 +158,10 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/** @param array{?float, ?float} $range */
|
||||
/**
|
||||
* Checks whether a value falls within the given [min, max] range (null means no bound).
|
||||
* @param array{?float, ?float} $range
|
||||
*/
|
||||
public static function isInRange(mixed $value, array $range): bool
|
||||
{
|
||||
return ($range[0] === null || $value >= $range[0])
|
||||
|
|
@ -154,6 +169,9 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a PatternMismatch error to the context if the value does not match the pattern.
|
||||
*/
|
||||
public static function validatePattern(string $value, string $pattern, Context $context): void
|
||||
{
|
||||
if (!preg_match("\x01^(?:$pattern)$\x01Du", $value)) {
|
||||
|
|
@ -166,7 +184,10 @@ final class Helpers
|
|||
}
|
||||
|
||||
|
||||
/** @return \Closure(mixed): mixed */
|
||||
/**
|
||||
* Returns a closure that casts a value to the given type (built-in, backed enum, class with constructor, or plain class).
|
||||
* @return \Closure(mixed, Context): mixed
|
||||
*/
|
||||
public static function getCastStrategy(string $type): \Closure
|
||||
{
|
||||
if (Nette\Utils\Validators::isBuiltinType($type)) {
|
||||
|
|
@ -174,12 +195,37 @@ final class Helpers
|
|||
settype($value, $type);
|
||||
return $value;
|
||||
};
|
||||
} elseif (method_exists($type, '__construct')) {
|
||||
return static fn($value) => is_array($value) || $value instanceof \stdClass
|
||||
? new $type(...(array) $value)
|
||||
: new $type($value);
|
||||
} else {
|
||||
return static fn($value) => Nette\Utils\Arrays::toObject((array) $value, new $type);
|
||||
|
||||
} elseif (is_subclass_of($type, \BackedEnum::class)) {
|
||||
return static function ($value, Context $context) use ($type) {
|
||||
try {
|
||||
return $type::from($value);
|
||||
} catch (\TypeError | \ValueError) {
|
||||
$context->addError(
|
||||
'The %label% %path% expects to be %expected%, %value% given.',
|
||||
Message::TypeMismatch,
|
||||
['value' => $value, 'expected' => implode('|', array_map(fn(\BackedEnum $case) => self::formatValue($case->value), $type::cases()))],
|
||||
);
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
} elseif (is_subclass_of($type, \UnitEnum::class)) {
|
||||
throw new Nette\InvalidStateException("Cannot cast value to pure enum $type.");
|
||||
}
|
||||
|
||||
$factory = method_exists($type, '__construct')
|
||||
? static fn($value) => is_array($value) || $value instanceof \stdClass
|
||||
? new $type(...(array) $value)
|
||||
: new $type($value)
|
||||
: static fn($value) => Nette\Utils\Arrays::toObject((array) $value, new $type);
|
||||
|
||||
return static function ($value) use ($factory, $type) {
|
||||
try {
|
||||
return $factory($value);
|
||||
} catch (\Error $e) {
|
||||
throw new Nette\InvalidStateException("Unable to cast value to $type: " . $e->getMessage(), 0, $e);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue