temkaa / simple-validator
简单的验证器实现
v0.0.5
2024-08-14 20:48 UTC
Requires
- php: 8.3.*
- psr/container: ^2.0
Requires (Dev)
- infection/infection: ^0.27.11
- phpmd/phpmd: ^2.15
- phpunit/phpunit: ^10.5
- vimeo/psalm: ^5.25
README
一个兼容PSR容器的验证器实现。
安装
composer require temkaa/simple-validator
此包提供以下约束
#[Count]
检查特定值是否与给定计数完全匹配。
#[GreaterThan]
检查特定值是否大于预期。
#[Initialized]
检查对象的特定属性是否已用任何值初始化。
#[Length]
检查特定值是否在指定的长度范围内。
#[LessThan]
检查特定值是否小于预期。
#[Negative]
检查特定值是否为负数(严格小于0)。
#[NotBlank]
检查特定值是否不为空(空数组/空字符串/未初始化)。
#[Positive]
检查特定值是否为正数(严格大于0)。
#[Range]
与Length相同,但针对int和float。
#[Regex]
检查特定值是否与给定的正则表达式匹配。
#[Cascade]
如果你的对象包含其他对象作为属性,你希望对其进行验证或数组|可迭代对象,你可以放置此属性,验证器将根据其自己的约束或对象数组验证此对象。
用法
<?php declare(strict_types=1); namespace App; use Temkaa\SimpleValidator\Constraint\Assert; use Temkaa\SimpleValidator\Constraint\ViolationInterface; use Temkaa\SimpleValidator\Constraint\ViolationListInterface; use Temkaa\SimpleValidator\Validator; final class Test { #[Assert\Length(minLength: 2, minMessage: 'min message')] #[Assert\NotBlank(message: 'message')] public string $name; #[Assert\Count(expected: 1, message: 'message')] public array $preferences; #[Assert\Positive(message: 'message')] #[Assert\GreaterThan(threshold: 18, message: 'message', allowEquality: true)] public int $age; #[Assert\Initialized(message: 'message')] public string $middleName; #[Assert\LessThan(threshold: 95.5, message: 'message')] public float $weight; #[Assert\Regex('/any_pattern/', message: 'message')] public string $username; #[Assert\Cascade] public iterable $arrayOfObjects; public function __construct() { $testObject = new TestObject(); $testObject->string = 'string'; $this->arrayOfObjects = [new TestObject()]; } } final class TestObject { #[Assert\Length(minLength: 2, minMessage: 'min message')] public string $string; } $validator = new Validator(); /** @var ViolationListInterface<ViolationInterface> $errors */ $errors = $validator->validate(new Test()); // or to perform specific assertions $validator = new Validator(); /** @var ViolationListInterface<ViolationInterface> $errors */ $errors = $validator->validate(new Test(), new CustomAssertion()); $errors = $validator->validate(new Test(), [new CustomAssertion1(), new CustomAssertion2()]);
编写自定义验证器
<?php declare(strict_types=1); namespace App; use Attribute; use Temkaa\SimpleValidator\AbstractConstraintValidator; use Temkaa\SimpleValidator\Constraint\ConstraintInterface; use Temkaa\SimpleValidator\Constraint\ConstraintValidatorInterface; use Temkaa\SimpleValidator\Constraint\ViolationInterface; use Temkaa\SimpleValidator\Constraint\ViolationListInterface; use Temkaa\SimpleValidator\Model\ValidatedValueInterface; use Temkaa\SimpleValidator\Validator; #[Attribute(Attribute::TARGET_CLASS)] final readonly class Constraint implements ConstraintInterface { public function __construct( public string $message, ) { } public function getHandler(): string { return ConstraintHandler::class; } } final class ConstraintHandler extends AbstractConstraintValidator { public function validate(ValidatedValueInterface $value, ConstraintInterface $constraint): void { if (!$constraint instanceof Constraint) { throw new UnexpectedTypeException(actualType: $constraint::class, expectedType: Constraint::class); } if ($value->isInitialized() && $value->getValue()->age !== 18) { $this->addViolation( new Violation(invalidValue: $value->getValue(), message: $constraint->message, path: $value->getPath()), ); } } } // OR final class ConstraintHandler implements ConstraintValidatorInterface { public function getViolations(): ViolationListInterface; public function validate(mixed $value, ConstraintInterface $constraint): void; public function __construct( private readonly ViolationListInterface $violationList = new ViolationList(), ) { } public function getViolations(): ViolationListInterface { return $this->violationList; } public function validate(ValidatedValueInterface $value, ConstraintInterface $constraint): void { if (!$constraint instanceof Constraint) { throw new UnexpectedTypeException(actualType: $constraint::class, expectedType: Constraint::class); } if ($value->isInitialized() && $value->getValue()->age !== 18) { $this->violationList->add( new Violation(invalidValue: $value->getValue(), message: $constraint->message, path: $value->getPath()), ); } } } #[Constraint(message: 'message')] final class Test { public int $age = 17; } $validator = new Validator(); /** @var ViolationListInterface<ViolationInterface> $errors */ $errors = $validator->validate(new Test());
向验证器类传递 Psr\Container\ContainerInterface
的选项
如果你在框架内部或具有di容器的项目中使用此验证器,可以将此容器传递给 Validator
构造函数。在这种情况下,当验证器为你的自定义约束实例化约束验证器时,它首先会检查目标约束验证器是否存在于容器中。如果不存在,它将尝试搜索你的约束验证器的所有依赖项,如果找不到任何依赖项,则将抛出异常。示例
<?php declare(strict_types=1); use Temkaa\SimpleValidator\Validator; $validator = new Validator($container);
注意
- 当将
ValidatedValueInterface
传递到验证器时,如果验证的属性未初始化,则将null
作为值传递。在这些情况下,建议添加NotBlank
或Initialized
验证器与你的自定义验证器一起使用; - 除了
NotBlank
和Initialized
之外的所有验证器都不会在未初始化的属性上触发验证错误。