diff --git a/src/Validator/BindForm.php b/src/Validator/BindForm.php index b76a3ad..98cca76 100644 --- a/src/Validator/BindForm.php +++ b/src/Validator/BindForm.php @@ -5,9 +5,14 @@ namespace Kiri\Router\Validator; use Exception; use Kiri\Di\Interface\InjectParameterInterface; use Kiri\Router\Base\Middleware; -use Kiri\Router\Interface\ValidatorInterface; -use Kiri\Router\Validator\Inject\Binding; -use ReflectionException; +use Kiri\Router\Validator\RequestFilter\RequestFilterInterface; +use Kiri\Router\Validator\Types\ArrayProxy; +use Kiri\Router\Validator\Types\BoolProxy; +use Kiri\Router\Validator\Types\FloatProxy; +use Kiri\Router\Validator\Types\IntProxy; +use Kiri\Router\Validator\Types\MixedProxy; +use Kiri\Router\Validator\Types\StringProxy; +use Kiri\Router\Validator\Types\TypesProxy; use ReflectionNamedType; use ReflectionUnionType; @@ -42,14 +47,13 @@ class BindForm implements InjectParameterInterface continue; } $rule = \inject($attribute->newInstance()); - if ($rule instanceof ValidatorInterface) { - $validator->addRule($property->getName(), $rule); + if ($rule instanceof RequestFilterInterface) { + $validator->addRule($property->getName(), $rule->dispatch($object, $property->getName())); } } - $validator->setTypes($property->getName(), $property->getType()); - if (!$property->hasDefaultValue()) { - $this->insertDefaultValue($property->getType(), $object, $property->getName()); - } + + $typeProxy = $this->_typeValidator($property); + $validator->addRule($property->getName(), [$typeProxy, false]); } $middleware = \instance(ValidatorMiddleware::class); @@ -61,39 +65,43 @@ class BindForm implements InjectParameterInterface /** - * @param ReflectionNamedType|ReflectionUnionType $reflectionProperty - * @param object $object - * @param string $property - * @return void - * @throws + * @param \ReflectionProperty $property + * @return object + * @throws Exception */ - private function insertDefaultValue(ReflectionNamedType|ReflectionUnionType $reflectionProperty, object $object, string $property): void + private function _typeValidator(\ReflectionProperty $property): TypesProxy { - if ($reflectionProperty->allowsNull()) { - $object->{$property} = null; - } else if ($reflectionProperty instanceof ReflectionUnionType) { - $object->{$property} = $this->defaultValue($reflectionProperty->getTypes()[0]); - } else { - $object->{$property} = $this->defaultValue($reflectionProperty); + $getType = $property->getType(); + $array = ['allowsNull' => $property->getType()->allowsNull()]; + if (!$getType instanceof ReflectionUnionType) { + return \Kiri::createObject(array_merge($array, [ + 'class' => $this->_typeProxy($getType) + ])); } + $types = []; + foreach ($getType->getTypes() as $type) { + $types[] = $type->getName(); + } + return \Kiri::createObject(array_merge($array, [ + 'types' => $types, + 'class' => MixedProxy::class + ])); } /** * @param ReflectionNamedType $type - * @return array|false|int|string - * @throws + * @return string */ - private function defaultValue(ReflectionNamedType $type): array|false|int|string + private function _typeProxy(ReflectionNamedType $type): string { return match ($type->getName()) { - 'array' => [], - 'int' => 0, - 'bool' => false, - 'string' => '', - default => throw new Exception('暂不支持的类型') + 'array' => ArrayProxy::class, + 'bool' => BoolProxy::class, + 'float' => FloatProxy::class, + 'int' => IntProxy::class, + 'string' => StringProxy::class, }; } - } diff --git a/src/Validator/Binding.php b/src/Validator/Binding.php new file mode 100644 index 0000000..b1cd614 --- /dev/null +++ b/src/Validator/Binding.php @@ -0,0 +1,100 @@ + ['class' => RequiredValidatorFilter::class], + 'length' => ['class' => LengthValidatorFilter::class], + 'minLength' => ['class' => MinLengthValidatorFilter::class], + 'maxLength' => ['class' => MaxLengthValidatorFilter::class], + 'in' => ['class' => InValidatorFilter::class], + 'notIn' => ['class' => NotInValidatorFilter::class], + 'between' => ['class' => BetweenValidatorFilter::class], + 'notBetween' => ['class' => NotBetweenValidatorFilter::class], + 'max' => ['class' => MaxValidatorFilter::class], + 'min' => ['class' => MinValidatorFilter::class], + 'round' => ['class' => RoundValidatorFilter::class], + 'must' => ['class' => MustValidatorFilter::class], + 'email' => ['class' => EmailValidatorFilter::class], + 'phone' => ['class' => PhoneValidatorFilter::class], + ]; + + + /** + * @param string $field + * @param array $rules + * @param mixed $defaultValue + */ + public function __construct(public string $field, public array $rules, public mixed $defaultValue = null) + { + } + + + /** + * @param object $class + * @param string $property + * @return array + */ + public function dispatch(object $class, string $property): array + { + // TODO: Implement dispatch() method. + $array = []; + foreach ($this->rules as $key => $rule) { + if (is_string($key)) { + $array[] = $this->getValidator($key, $rule); + } else if (method_exists($this, $rule)) { + $array[] = [$class, $rule, false]; + } else { + $array[] = $this->getValidator($key, $rule); + } + } + if (!is_null($this->defaultValue)) { + $class->{$property} = $this->defaultValue; + } + return $array; + } + + + /** + * @param $key + * @param $rule + * @return array + * @throws + */ + protected function getValidator($key, $rule): array + { + $class = array_merge(self::TYPES[$key], ['value' => $rule, 'field' => $key]); + $isFirst = false; + if ($class['class'] === RequiredValidatorFilter::class) { + $isFirst = true; + } + return [Kiri::createObject($class), $isFirst]; + } + +} \ No newline at end of file diff --git a/src/Validator/FormBase.php b/src/Validator/FormBase.php deleted file mode 100644 index 157ef34..0000000 --- a/src/Validator/FormBase.php +++ /dev/null @@ -1,9 +0,0 @@ -value); - } -} diff --git a/src/Validator/Inject/Length.php b/src/Validator/Inject/Length.php deleted file mode 100644 index ba54882..0000000 --- a/src/Validator/Inject/Length.php +++ /dev/null @@ -1,33 +0,0 @@ -value; - } -} diff --git a/src/Validator/Inject/Matching.php b/src/Validator/Inject/Matching.php deleted file mode 100644 index 8f18cf0..0000000 --- a/src/Validator/Inject/Matching.php +++ /dev/null @@ -1,34 +0,0 @@ -value) . '/', $data); - } else { - return false; - } - } -} \ No newline at end of file diff --git a/src/Validator/Inject/Max.php b/src/Validator/Inject/Max.php deleted file mode 100644 index 59bd0cd..0000000 --- a/src/Validator/Inject/Max.php +++ /dev/null @@ -1,33 +0,0 @@ -value; - } -} diff --git a/src/Validator/Inject/MaxLength.php b/src/Validator/Inject/MaxLength.php deleted file mode 100644 index 9f649c1..0000000 --- a/src/Validator/Inject/MaxLength.php +++ /dev/null @@ -1,34 +0,0 @@ -value; - } -} diff --git a/src/Validator/Inject/Min.php b/src/Validator/Inject/Min.php deleted file mode 100644 index afe738f..0000000 --- a/src/Validator/Inject/Min.php +++ /dev/null @@ -1,33 +0,0 @@ -= $this->value; - } -} diff --git a/src/Validator/Inject/MinLength.php b/src/Validator/Inject/MinLength.php deleted file mode 100644 index 954c7eb..0000000 --- a/src/Validator/Inject/MinLength.php +++ /dev/null @@ -1,33 +0,0 @@ -value; - } -} diff --git a/src/Validator/Inject/Must.php b/src/Validator/Inject/Must.php deleted file mode 100644 index 84c4845..0000000 --- a/src/Validator/Inject/Must.php +++ /dev/null @@ -1,31 +0,0 @@ -value; - } - -} diff --git a/src/Validator/Inject/NotEmpty.php b/src/Validator/Inject/NotEmpty.php deleted file mode 100644 index f92bc18..0000000 --- a/src/Validator/Inject/NotEmpty.php +++ /dev/null @@ -1,22 +0,0 @@ -value); - } -} diff --git a/src/Validator/Inject/NotNull.php b/src/Validator/Inject/NotNull.php deleted file mode 100644 index 069e509..0000000 --- a/src/Validator/Inject/NotNull.php +++ /dev/null @@ -1,22 +0,0 @@ -value) === $data; - } -} diff --git a/src/Validator/RequestFilter/BetweenValidatorFilter.php b/src/Validator/RequestFilter/BetweenValidatorFilter.php new file mode 100644 index 0000000..cebabc8 --- /dev/null +++ b/src/Validator/RequestFilter/BetweenValidatorFilter.php @@ -0,0 +1,19 @@ +value; + + return $value >= $min && $value <= $max; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/EmailValidatorFilter.php b/src/Validator/RequestFilter/EmailValidatorFilter.php new file mode 100644 index 0000000..08de5b1 --- /dev/null +++ b/src/Validator/RequestFilter/EmailValidatorFilter.php @@ -0,0 +1,20 @@ +value); + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/LengthValidatorFilter.php b/src/Validator/RequestFilter/LengthValidatorFilter.php new file mode 100644 index 0000000..97e4c32 --- /dev/null +++ b/src/Validator/RequestFilter/LengthValidatorFilter.php @@ -0,0 +1,17 @@ +value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/MaxLengthValidatorFilter.php b/src/Validator/RequestFilter/MaxLengthValidatorFilter.php new file mode 100644 index 0000000..8924fb7 --- /dev/null +++ b/src/Validator/RequestFilter/MaxLengthValidatorFilter.php @@ -0,0 +1,20 @@ +value; + } + return mb_strlen((string)$value) <= $this->value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/MaxValidatorFilter.php b/src/Validator/RequestFilter/MaxValidatorFilter.php new file mode 100644 index 0000000..f6e835e --- /dev/null +++ b/src/Validator/RequestFilter/MaxValidatorFilter.php @@ -0,0 +1,17 @@ +value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/MinLengthValidatorFilter.php b/src/Validator/RequestFilter/MinLengthValidatorFilter.php new file mode 100644 index 0000000..763d5d1 --- /dev/null +++ b/src/Validator/RequestFilter/MinLengthValidatorFilter.php @@ -0,0 +1,20 @@ += $this->value; + } + return mb_strlen((string)$value) >= $this->value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/MinValidatorFilter.php b/src/Validator/RequestFilter/MinValidatorFilter.php new file mode 100644 index 0000000..8191c95 --- /dev/null +++ b/src/Validator/RequestFilter/MinValidatorFilter.php @@ -0,0 +1,17 @@ += $this->value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/MustValidatorFilter.php b/src/Validator/RequestFilter/MustValidatorFilter.php new file mode 100644 index 0000000..e5a126c --- /dev/null +++ b/src/Validator/RequestFilter/MustValidatorFilter.php @@ -0,0 +1,17 @@ +value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/NotBetweenValidatorFilter.php b/src/Validator/RequestFilter/NotBetweenValidatorFilter.php new file mode 100644 index 0000000..cf746b4 --- /dev/null +++ b/src/Validator/RequestFilter/NotBetweenValidatorFilter.php @@ -0,0 +1,19 @@ +value; + + return $value <= $min || $value >= $max; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/NotInValidatorFilter.php b/src/Validator/RequestFilter/NotInValidatorFilter.php new file mode 100644 index 0000000..30b8ccb --- /dev/null +++ b/src/Validator/RequestFilter/NotInValidatorFilter.php @@ -0,0 +1,17 @@ +value); + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/PhoneValidatorFilter.php b/src/Validator/RequestFilter/PhoneValidatorFilter.php new file mode 100644 index 0000000..9c46d30 --- /dev/null +++ b/src/Validator/RequestFilter/PhoneValidatorFilter.php @@ -0,0 +1,20 @@ +value) === $value; + } + +} \ No newline at end of file diff --git a/src/Validator/RequestFilter/ValidatorFilter.php b/src/Validator/RequestFilter/ValidatorFilter.php new file mode 100644 index 0000000..77a1f8b --- /dev/null +++ b/src/Validator/RequestFilter/ValidatorFilter.php @@ -0,0 +1,28 @@ +{$field} = $value); + } + } \ No newline at end of file diff --git a/src/Validator/Types/BoolProxy.php b/src/Validator/Types/BoolProxy.php index 8ca6b76..5ec89a5 100644 --- a/src/Validator/Types/BoolProxy.php +++ b/src/Validator/Types/BoolProxy.php @@ -1,8 +1,28 @@ {$field} = $value === 'true'; + } else if (in_array($value, ['0', '1'])) { + $form->{$field} = $value === '1'; + } else { + return false; + } + return true; + } + } \ No newline at end of file diff --git a/src/Validator/Types/FloatProxy.php b/src/Validator/Types/FloatProxy.php index 8c353af..09b60b0 100644 --- a/src/Validator/Types/FloatProxy.php +++ b/src/Validator/Types/FloatProxy.php @@ -2,7 +2,17 @@ namespace Kiri\Router\Validator\Types; -class FloatProxy +class FloatProxy extends TypesProxy { + + /** + * @param object $form + * @param mixed $value + * @return bool + */ + public function dispatch(object $form, string $field, mixed $value): bool + { + return $value == ($form->{$field} = (float)$value); + } } \ No newline at end of file diff --git a/src/Validator/Types/IntProxy.php b/src/Validator/Types/IntProxy.php index 2d54ec4..b6fa2bd 100644 --- a/src/Validator/Types/IntProxy.php +++ b/src/Validator/Types/IntProxy.php @@ -2,7 +2,19 @@ namespace Kiri\Router\Validator\Types; -class IntProxy +class IntProxy extends TypesProxy { + + /** + * @param object $form + * @param string $field + * @param mixed $value + * @return bool + */ + public function dispatch(object $form, string $field, mixed $value): bool + { + return $value == ($form->{$field} = (int)$value); + } + } \ No newline at end of file diff --git a/src/Validator/Types/MixedProxy.php b/src/Validator/Types/MixedProxy.php new file mode 100644 index 0000000..a6641d7 --- /dev/null +++ b/src/Validator/Types/MixedProxy.php @@ -0,0 +1,28 @@ +{$field} = $value); + } catch (\Throwable $throwable) { + return false; + } + } + +} \ No newline at end of file diff --git a/src/Validator/Types/StringProxy.php b/src/Validator/Types/StringProxy.php index 18c3652..a277bb0 100644 --- a/src/Validator/Types/StringProxy.php +++ b/src/Validator/Types/StringProxy.php @@ -2,7 +2,19 @@ namespace Kiri\Router\Validator\Types; -class StringProxy + +class StringProxy extends TypesProxy { + + /** + * @param object $form + * @param mixed $value + * @return bool + */ + public function dispatch(object $form, string $field, mixed $value): bool + { + return $value == ($form->{$field} = (string)$value); + } + } \ No newline at end of file diff --git a/src/Validator/Types/TypesProxy.php b/src/Validator/Types/TypesProxy.php new file mode 100644 index 0000000..0446e25 --- /dev/null +++ b/src/Validator/Types/TypesProxy.php @@ -0,0 +1,23 @@ +> */ protected array $rules = []; @@ -38,6 +40,12 @@ class Validator protected object $formData; + /** + * @var array + */ + protected array $ignoring = []; + + /** * @var array */ @@ -55,17 +63,6 @@ class Validator } - /** - * @param string $property - * @param ReflectionNamedType|ReflectionUnionType $types - * @return void - */ - public function setTypes(string $property, ReflectionNamedType|ReflectionUnionType $types): void - { - $this->types[$property] = $types; - } - - /** * @return object */ @@ -76,15 +73,22 @@ class Validator /** * @param string $name - * @param ValidatorInterface $rule + * @param array $rule * @return void */ - public function addRule(string $name, ValidatorInterface $rule): void + public function addRule(string $name, array $rule): void { if (!isset($this->rules[$name])) { $this->rules[$name] = []; } - $this->rules[$name][] = $rule; + foreach ($rule as $item) { + [$dispatch, $isFirst] = $item; + if ($isFirst) { + array_unshift($this->rules[$name], $dispatch); + } else { + $this->rules[$name][] = $dispatch; + } + } } @@ -99,84 +103,40 @@ class Validator return false; } $params = !$request->isPost() ? $request->getQueryParams() : $request->getParsedBody(); - - foreach ($params as $name => $value) { - if (!isset($this->types[$name])) { - continue; - } - $rules = $this->rules[$name] ?? []; - foreach ($rules as $item) { - /** @var ValidatorInterface $item */ - if (!$item->dispatch($value, $this->formData)) { - return $this->addError($name); + foreach ($this->rules as $name => $rules) { + /** @var TypesProxy $typeValidator */ + if (!isset($params[$name])) { + if ($rules[0] instanceof RequiredValidatorFilter) { + return $this->addError('The request field ' . $name . ' is mandatory and indispensable'); + } + if (!$typeValidator->allowsNull) { + return $this->addError('The request field ' . $name . ' parameter cannot be null'); } } - /** @var ReflectionNamedType|ReflectionUnionType $property */ - $property = $this->types[$name]; - if ($property instanceof ReflectionUnionType) { - foreach ($property->getTypes() as $type) { - $typeName = $type->getName(); - if ($typeName == 'string' && is_string($value)) { - $this->formData->{$name} = $value; - break; - } else if ($typeName == 'int' && $value == ($int = intval($value))) { - $this->formData->{$name} = $int; - break; - } else if ($typeName == 'bool' && in_array($value, ['true', 'false'])) { - $this->formData->{$name} = $value == 'true'; - break; - } else if ($typeName == 'float' && $value == ($flo = floatval($value))) { - $this->formData->{$name} = $flo; - break; - } else if ($typeName == 'array' && is_array($value)) { - $this->formData->{$name} = $value; - break; - } + $typeValidator = array_pop($rules); + if (!$typeValidator->dispatch($this->formData, $name, $params[$name])) { + return $this->addError('The parameter type used in the request field ' . $name . ' is incorrect'); + } + + /** @var RValidator $rule */ + foreach ($rules as $rule) { + if (!$rule->dispatch($this->formData->{$name})) { + return $this->addError('Request field ' . $name . ' value format error'); } - if ($this->formData->{$name} != $value) { - throw new Exception('Fail type value.'); - } - } else { - $this->formData->{$name} = match ($property->getName()) { - 'int' => (int)$value, - 'float' => (float)$value, - 'bool' => $value == 'true', - 'array' => $this->arrayCheck($property, $name, $value), - default => $value - }; } } return true; } - /** - * @param ReflectionNamedType $property - * @param string $name - * @param string|array $value - * @return array|null - * @throws Exception - */ - protected function arrayCheck(ReflectionNamedType $property, string $name, string|array $value): ?array - { - if (empty($value) || !is_array($value)) { - if ($property->allowsNull()) { - return null; - } - throw new Exception('Cannot assign non null values to property ' . $name . ' of type array'); - } - return $value; - } - - /** * @param $field * @return bool */ private function addError($field): bool { - $this->message = 'Field ' . $field . ' value format fail.'; + $this->message = $field; return false; }