mirror of
https://github.com/Respect/Validation.git
synced 2024-06-27 09:40:05 +02:00
Create "OneOf" rule
This commit is contained in:
parent
7ee4ae47d5
commit
d48b55a092
|
@ -25,6 +25,7 @@ v::allOf(
|
|||
***
|
||||
See also:
|
||||
|
||||
* [OneOf](OneOf.md)
|
||||
* [AnyOf](AnyOf.md)
|
||||
* [NoneOf](NoneOf.md)
|
||||
* [OneOf](OneOf.md)
|
||||
* [When](When.md)
|
||||
|
|
|
@ -22,4 +22,5 @@ See also:
|
|||
|
||||
* [AllOf](AllOf.md)
|
||||
* [NoneOf](NoneOf.md)
|
||||
* [OneOf](OneOf.md)
|
||||
* [When](When.md)
|
||||
|
|
|
@ -16,6 +16,7 @@ In the sample above, 'foo' isn't a integer nor a float, so noneOf returns true.
|
|||
***
|
||||
See also:
|
||||
|
||||
* [Not](Not.md)
|
||||
* [AllOf](AllOf.md)
|
||||
* [AnyOf](AnyOf.md)
|
||||
* [Not](Not.md)
|
||||
* [OneOf](OneOf.md)
|
||||
|
|
22
docs/OneOf.md
Normal file
22
docs/OneOf.md
Normal file
|
@ -0,0 +1,22 @@
|
|||
# OneOf
|
||||
|
||||
- `v::oneOf(v $v1, v $v2, v $v3...)`
|
||||
|
||||
Will validate if exactly one inner validator passes.
|
||||
|
||||
```php
|
||||
v::oneOf(v::digit(), v::alpha())->validate('AB'); // true
|
||||
v::oneOf(v::digit(), v::alpha())->validate('12'); // true
|
||||
v::oneOf(v::digit(), v::alpha())->validate('AB12'); // false
|
||||
v::oneOf(v::digit(), v::alpha())->validate('*'); // false
|
||||
```
|
||||
|
||||
The chains above validate if the input is either a digit or an alphabetic
|
||||
character, one or the other, but not neither nor both.
|
||||
|
||||
***
|
||||
See also:
|
||||
|
||||
* [AllOf](AllOf.md)
|
||||
* [AnyOf](AnyOf.md)
|
||||
* [NoneOf](NoneOf.md)
|
|
@ -136,6 +136,7 @@
|
|||
## Group Validators
|
||||
|
||||
* [AllOf](AllOf.md)
|
||||
* [AnyOf](AnyOf.md)
|
||||
* [NoneOf](NoneOf.md)
|
||||
* [OneOf](OneOf.md)
|
||||
|
||||
|
@ -209,6 +210,7 @@
|
|||
* [Alpha](Alpha.md)
|
||||
* [AlwaysInvalid](AlwaysInvalid.md)
|
||||
* [AlwaysValid](AlwaysValid.md)
|
||||
* [AnyOf](AnyOf.md)
|
||||
* [ArrayVal](ArrayVal.md)
|
||||
* [ArrayType](ArrayType.md)
|
||||
* [Attribute](Attribute.md)
|
||||
|
|
27
library/Exceptions/OneOfException.php
Normal file
27
library/Exceptions/OneOfException.php
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Exceptions;
|
||||
|
||||
/**
|
||||
* @author Bradyn Poulsen <bradyn@bradynpoulsen.com>
|
||||
*/
|
||||
class OneOfException extends NestedValidationException
|
||||
{
|
||||
public static $defaultTemplates = [
|
||||
self::MODE_DEFAULT => [
|
||||
self::STANDARD => 'Only one of these rules must pass for {{name}}',
|
||||
],
|
||||
self::MODE_NEGATIVE => [
|
||||
self::STANDARD => 'Only one of these rules must not pass for {{name}}',
|
||||
],
|
||||
];
|
||||
}
|
69
library/Rules/OneOf.php
Normal file
69
library/Rules/OneOf.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
use Respect\Validation\Exceptions\ValidationException;
|
||||
|
||||
/**
|
||||
* @author Bradyn Poulsen <bradyn@bradynpoulsen.com>
|
||||
* @author Henrique Moody <henriquemoody@gmail.com>
|
||||
*/
|
||||
class OneOf extends AbstractComposite
|
||||
{
|
||||
public function assert($input)
|
||||
{
|
||||
$validators = $this->getRules();
|
||||
$exceptions = $this->validateRules($input);
|
||||
$numRules = count($validators);
|
||||
$numExceptions = count($exceptions);
|
||||
if ($numExceptions !== $numRules - 1) {
|
||||
throw $this->reportError($input)->setRelated($exceptions);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function validate($input)
|
||||
{
|
||||
$rulesPassedCount = 0;
|
||||
foreach ($this->getRules() as $rule) {
|
||||
if (!$rule->validate($input)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
++$rulesPassedCount;
|
||||
}
|
||||
|
||||
return $rulesPassedCount === 1;
|
||||
}
|
||||
|
||||
public function check($input)
|
||||
{
|
||||
$exceptions = [];
|
||||
$rulesPassedCount = 0;
|
||||
foreach ($this->getRules() as $rule) {
|
||||
try {
|
||||
$rule->check($input);
|
||||
|
||||
++$rulesPassedCount;
|
||||
} catch (ValidationException $exception) {
|
||||
$exceptions[] = $exception;
|
||||
}
|
||||
}
|
||||
|
||||
if ($rulesPassedCount === 1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
throw (array_shift($exceptions) ?: $this->reportError($input));
|
||||
}
|
||||
}
|
|
@ -113,6 +113,7 @@ use Respect\Validation\Rules\Key;
|
|||
* @method static Validator numericVal()
|
||||
* @method static Validator objectType()
|
||||
* @method static Validator odd()
|
||||
* @method static Validator oneOf(Validatable $v1, Validatable $v_)
|
||||
* @method static Validator optional(Validatable $rule)
|
||||
* @method static Validator perfectSquare()
|
||||
* @method static Validator pesel()
|
||||
|
|
141
tests/unit/Rules/OneOfTest.php
Normal file
141
tests/unit/Rules/OneOfTest.php
Normal file
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of Respect/Validation.
|
||||
*
|
||||
* (c) Alexandre Gomes Gaigalas <alexandre@gaigalas.net>
|
||||
*
|
||||
* For the full copyright and license information, please view the "LICENSE.md"
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Respect\Validation\Rules;
|
||||
|
||||
/**
|
||||
* @group rule
|
||||
* @covers \Respect\Validation\Rules\OneOf
|
||||
* @covers \Respect\Validation\Exceptions\OneOfException
|
||||
*/
|
||||
class OneOfTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testValid()
|
||||
{
|
||||
$valid1 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
$valid2 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid3 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
$rule = new OneOf($valid1, $valid2, $valid3);
|
||||
|
||||
$this->assertTrue($rule->validate('any'));
|
||||
$this->assertTrue($rule->assert('any'));
|
||||
$this->assertTrue($rule->check('any'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\OneOfException
|
||||
*/
|
||||
public function testEmptyChain()
|
||||
{
|
||||
$rule = new OneOf();
|
||||
|
||||
$this->assertFalse($rule->validate('any'));
|
||||
$this->assertFalse($rule->check('any'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\OneOfException
|
||||
*/
|
||||
public function testInvalid()
|
||||
{
|
||||
$valid1 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
$valid2 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
$valid3 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
$rule = new OneOf($valid1, $valid2, $valid3);
|
||||
$this->assertFalse($rule->validate('any'));
|
||||
$this->assertFalse($rule->assert('any'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\OneOfException
|
||||
*/
|
||||
public function testInvalidMultipleAssert()
|
||||
{
|
||||
$valid1 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid2 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid3 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
$rule = new OneOf($valid1, $valid2, $valid3);
|
||||
$this->assertFalse($rule->validate('any'));
|
||||
|
||||
$rule->assert('any');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\CallbackException
|
||||
*/
|
||||
public function testInvalidMultipleCheck()
|
||||
{
|
||||
$valid1 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid2 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid3 = new Callback(function () {
|
||||
return false;
|
||||
});
|
||||
|
||||
$rule = new OneOf($valid1, $valid2, $valid3);
|
||||
$this->assertFalse($rule->validate('any'));
|
||||
|
||||
$rule->check('any');
|
||||
}
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\OneOfException
|
||||
*/
|
||||
public function testInvalidMultipleCheckAllValid()
|
||||
{
|
||||
$valid1 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid2 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
$valid3 = new Callback(function () {
|
||||
return true;
|
||||
});
|
||||
|
||||
$rule = new OneOf($valid1, $valid2, $valid3);
|
||||
$this->assertFalse($rule->validate('any'));
|
||||
|
||||
$rule->check('any');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Respect\Validation\Exceptions\XdigitException
|
||||
*/
|
||||
public function testInvalidCheck()
|
||||
{
|
||||
$rule = new OneOf(new Xdigit(), new Alnum());
|
||||
$this->assertFalse($rule->validate(-10));
|
||||
|
||||
$rule->check(-10);
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue