diff --git a/src/ValidationRuleset.php b/src/ValidationRuleset.php index c8ec9c3..7917ba0 100644 --- a/src/ValidationRuleset.php +++ b/src/ValidationRuleset.php @@ -47,6 +47,7 @@ class ValidationRuleset 'integer' => 100, 'string' => 100, 'array' => 100, + 'boolean' => 100, 'min' => 10, 'max' => 10, 'in' => 10, @@ -75,7 +76,13 @@ class ValidationRuleset 'integer', 'numeric', 'string', - 'array' + 'array', + 'boolean' + ]; + + protected static array $stringToBoolMap = [ + '1' => true, '0' => false, + 'true' => true, 'false' => false, ]; /** @var int base flags */ @@ -184,6 +191,15 @@ protected function __construct(array $ruleMap) case 'ipv6': $rules[] = ValidationRule::make($rule, static::getClosure('validate' . strtoupper($rule))); break; + case 'boolean': + if (count($ruleArgs) === 0) { + $rules[] = ValidationRule::make('boolean', static::getClosure('validateBoolean')); + } elseif (count($ruleArgs) === 1 && $ruleArgs[0] === 'strict') { + $rules[] = ValidationRule::make('boolean:strict', static::getClosure('validateBooleanStrict')); + } else { + throw new InvalidArgumentException("Rule 'boolean' only supports 'strict' parameter"); + } + break; case 'bail': /* compatibility */ break; @@ -561,4 +577,23 @@ public static function validateIPV6(string $value, array $attributes): bool { return filter_var($value, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== false; } + + protected static function validateBoolean(mixed $value, array $attributes): bool + { + return match (true) { + is_bool($value), $value === 1, $value === 0 => true, + is_string($value) => isset(static::$stringToBoolMap[strtolower($value)]), + default => false, + }; + } + + protected static function validateBooleanStrict(mixed $value, array $attributes): bool + { + return is_bool($value); + } + + protected static function validateRequiredBoolean(bool $value, array $attributes): bool + { + return true; + } } diff --git a/tests/HyperfValidatorTest.php b/tests/HyperfValidatorTest.php index fe2d57b..eb0b0bf 100644 --- a/tests/HyperfValidatorTest.php +++ b/tests/HyperfValidatorTest.php @@ -125,6 +125,203 @@ public function testValidatedAndErrors() $this->assertEquals($errors, $errors2); } + public function testBoolean() + { + // 测试普通 boolean 验证 - 应该通过的值 + $validator = $this->makeValidator(['flag' => true], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => false], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 1], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 0], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => '1'], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => '0'], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'true'], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'false'], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'TRUE'], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'FALSE'], ['flag' => 'boolean']); + $this->assertFalse($validator->fails()); + + // 测试普通 boolean 验证 - 应该失败的值 + $validator = $this->makeValidator(['flag' => 'yes'], ['flag' => 'boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'no'], ['flag' => 'boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => '2'], ['flag' => 'boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 2], ['flag' => 'boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => []], ['flag' => 'boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'invalid'], ['flag' => 'boolean']); + $this->assertTrue($validator->fails()); + } + + public function testBooleanStrict() + { + // 测试严格 boolean 验证 - 应该通过的值 + $validator = $this->makeValidator(['flag' => true], ['flag' => 'boolean:strict']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => false], ['flag' => 'boolean:strict']); + $this->assertFalse($validator->fails()); + + // 测试严格 boolean 验证 - 应该失败的值 + $validator = $this->makeValidator(['flag' => 1], ['flag' => 'boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 0], ['flag' => 'boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => '1'], ['flag' => 'boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => '0'], ['flag' => 'boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'true'], ['flag' => 'boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'false'], ['flag' => 'boolean:strict']); + $this->assertTrue($validator->fails()); + } + + public function testRequiredBoolean() + { + // 测试 required boolean 组合 - 应该通过的值 + $validator = $this->makeValidator(['flag' => true], ['flag' => 'required|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => false], ['flag' => 'required|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 1], ['flag' => 'required|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 0], ['flag' => 'required|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => '1'], ['flag' => 'required|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => '0'], ['flag' => 'required|boolean']); + $this->assertFalse($validator->fails()); + + // 测试 required boolean 组合 - 应该失败的值 + $validator = $this->makeValidator([], ['flag' => 'required|boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => null], ['flag' => 'required|boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => ''], ['flag' => 'required|boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'invalid'], ['flag' => 'required|boolean']); + $this->assertTrue($validator->fails()); + } + + public function testRequiredBooleanStrict() + { + // 测试 required boolean:strict 组合 - 应该通过的值 + $validator = $this->makeValidator(['flag' => true], ['flag' => 'required|boolean:strict']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => false], ['flag' => 'required|boolean:strict']); + $this->assertFalse($validator->fails()); + + // 测试 required boolean:strict 组合 - 应该失败的值 + $validator = $this->makeValidator([], ['flag' => 'required|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => null], ['flag' => 'required|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 1], ['flag' => 'required|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 0], ['flag' => 'required|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => '1'], ['flag' => 'required|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'true'], ['flag' => 'required|boolean:strict']); + $this->assertTrue($validator->fails()); + } + + public function testNullableBoolean() + { + // 测试 nullable boolean 组合 - null 值应该通过 + $validator = $this->makeValidator(['flag' => null], ['flag' => 'nullable|boolean']); + $this->assertFalse($validator->fails()); + + // 测试 nullable boolean 组合 - 有效的 boolean 值应该通过 + $validator = $this->makeValidator(['flag' => true], ['flag' => 'nullable|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => false], ['flag' => 'nullable|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => 1], ['flag' => 'nullable|boolean']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => '0'], ['flag' => 'nullable|boolean']); + $this->assertFalse($validator->fails()); + + // 测试 nullable boolean 组合 - 无效值应该失败 + $validator = $this->makeValidator(['flag' => 'invalid'], ['flag' => 'nullable|boolean']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => []], ['flag' => 'nullable|boolean']); + $this->assertTrue($validator->fails()); + } + + public function testNullableBooleanStrict() + { + // 测试 nullable boolean:strict 组合 - null 值应该通过 + $validator = $this->makeValidator(['flag' => null], ['flag' => 'nullable|boolean:strict']); + $this->assertFalse($validator->fails()); + + // 测试 nullable boolean:strict 组合 - 只有真正的 boolean 值应该通过 + $validator = $this->makeValidator(['flag' => true], ['flag' => 'nullable|boolean:strict']); + $this->assertFalse($validator->fails()); + + $validator = $this->makeValidator(['flag' => false], ['flag' => 'nullable|boolean:strict']); + $this->assertFalse($validator->fails()); + + // 测试 nullable boolean:strict 组合 - 非严格 boolean 值应该失败 + $validator = $this->makeValidator(['flag' => 1], ['flag' => 'nullable|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => '1'], ['flag' => 'nullable|boolean:strict']); + $this->assertTrue($validator->fails()); + + $validator = $this->makeValidator(['flag' => 'true'], ['flag' => 'nullable|boolean:strict']); + $this->assertTrue($validator->fails()); + } + protected function makeValidator(array $data, array $rules, array $messages = [], array $customAttributes = []) { $factory = new ValidatorFactory($this->getTranslator(), $this->getContainer());