Refactor "KeySet" rule

Do not extend AllOf exception, but instead extend "AbstractWrapper".
This commit is contained in:
Henrique Moody 2018-03-03 18:59:36 +01:00
parent 60e3fc3740
commit b696070874
No known key found for this signature in database
GPG key ID: 221E9281655813A6
4 changed files with 108 additions and 84 deletions

View file

@ -38,7 +38,7 @@ class KeySetException extends GroupedValidationException implements NonOmissible
*/
public function chooseTemplate()
{
if ($this->getParam('keys')) {
if (0 === $this->getRelated()->count()) {
return static::STRUCTURE;
}

View file

@ -14,72 +14,73 @@ declare(strict_types=1);
namespace Respect\Validation\Rules;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Exceptions\KeySetException;
use Respect\Validation\Validatable;
use function array_key_exists;
use function array_map;
use function count;
use function current;
use function is_array;
/**
* Validates a keys in a defined structure.
*
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
*/
class KeySet extends AllOf
final class KeySet extends AbstractWrapper
{
/**
* @param AllOf $rule
*
* @return Validatable
* @var array
*/
private function filterAllOf(AllOf $rule)
{
$rules = $rule->getRules();
if (1 != count($rules)) {
throw new ComponentException('AllOf rule must have only one Key rule');
}
private $keys;
return current($rules);
/**
* @var Key[]
*/
private $keyRules;
/**
* Initializes the rule.
*
* @param Validatable[] ...$validatables
*/
public function __construct(Validatable ...$validatables)
{
$this->keyRules = array_map([$this, 'getKeyRule'], $validatables);
$this->keys = array_map([$this, 'getKeyReference'], $this->keyRules);
parent::__construct(new AllOf(...$this->keyRules));
}
/**
* {@inheritdoc}
* @param Validatable $validatable
*
* @throws ComponentException
*
* @return Key
*/
public function addRule($rule, $arguments = [])
private function getKeyRule(Validatable $validatable): Key
{
if ($rule instanceof AllOf) {
$rule = $this->filterAllOf($rule);
if ($validatable instanceof Key) {
return $validatable;
}
if (!$rule instanceof Key) {
if (!$validatable instanceof AllOf
|| 1 !== count($validatable->getRules())) {
throw new ComponentException('KeySet rule accepts only Key rules');
}
$this->appendRule($rule);
return $this;
return $this->getKeyRule(current($validatable->getRules()));
}
/**
* {@inheritdoc}
* @param Key $rule
*
* @return mixed
*/
public function addRules(array $rules)
private function getKeyReference(Key $rule)
{
foreach ($rules as $rule) {
$this->addRule($rule);
}
return $this;
}
/**
* @return array
*/
public function getKeys()
{
$keys = [];
foreach ($this->getRules() as $keyRule) {
$keys[] = $keyRule->reference;
}
return $keys;
return $rule->reference;
}
/**
@ -93,7 +94,7 @@ class KeySet extends AllOf
return false;
}
foreach ($this->getRules() as $keyRule) {
foreach ($this->keyRules as $keyRule) {
if (!array_key_exists($keyRule->reference, $input) && $keyRule->mandatory) {
return false;
}
@ -104,25 +105,14 @@ class KeySet extends AllOf
return 0 == count($input);
}
/**
* @throws KeySetException
*/
private function checkKeys($input): void
{
if (!$this->hasValidStructure($input)) {
$params = ['keys' => $this->getKeys()];
$exception = $this->reportError($input, $params);
throw $exception;
}
}
/**
* {@inheritdoc}
*/
public function assert($input): void
{
$this->checkKeys($input);
if (!$this->hasValidStructure($input)) {
throw $this->reportError($input);
}
parent::assert($input);
}
@ -132,7 +122,9 @@ class KeySet extends AllOf
*/
public function check($input): void
{
$this->checkKeys($input);
if (!$this->hasValidStructure($input)) {
throw $this->reportError($input);
}
parent::check($input);
}

View file

@ -14,7 +14,6 @@ declare(strict_types=1);
namespace Respect\Validation\Rules;
use DateTime;
use Respect\Validation\Exceptions\ComponentException;
use Respect\Validation\Test\RuleTestCase;
/**

View file

@ -16,38 +16,45 @@ namespace Respect\Validation\Rules;
use PHPUnit\Framework\TestCase;
/**
* @group rule
* @group rule
*
* @covers \Respect\Validation\Rules\KeySet
* @covers \Respect\Validation\Exceptions\KeySetException
*
* @author Henrique Moody <henriquemoody@gmail.com>
* @author Emmerson Siqueira <emmersonsiqueira@gmail.com>
*/
class KeySetTest extends TestCase
final class KeySetTest extends TestCase
{
public function testShouldAcceptKeyRule(): void
/**
* @test
*/
public function shouldAcceptKeyRule(): void
{
$key = new Key('foo', new AlwaysValid(), false);
$keySet = new KeySet($key);
$rules = $keySet->getRules();
self::assertSame(current($rules), $key);
self::assertAttributeSame([$key], 'keyRules', $keySet);
}
public function testShouldAcceptAllOfWithOneKeyRule(): void
/**
* @test
*/
public function shouldAcceptAllOfWithOneKeyRule(): void
{
$key = new Key('foo', new AlwaysValid(), false);
$allOf = new AllOf($key);
$keySet = new KeySet($allOf);
$rules = $keySet->getRules();
self::assertSame(current($rules), $key);
self::assertAttributeSame([$key], 'keyRules', $keySet);
}
/**
* @test
*
* @expectedException \Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage AllOf rule must have only one Key rule
* @expectedExceptionMessage KeySet rule accepts only Key rules
*/
public function testShouldNotAcceptAllOfWithMoreThanOneKeyRule(): void
public function shouldNotAcceptAllOfWithMoreThanOneKeyRule(): void
{
$key1 = new Key('foo', new AlwaysValid(), false);
$key2 = new Key('bar', new AlwaysValid(), false);
@ -57,10 +64,12 @@ class KeySetTest extends TestCase
}
/**
* @test
*
* @expectedException \Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage KeySet rule accepts only Key rules
*/
public function testShouldNotAcceptAllOfWithANonKeyRule(): void
public function shouldNotAcceptAllOfWithANonKeyRule(): void
{
$alwaysValid = new AlwaysValid();
$allOf = new AllOf($alwaysValid);
@ -69,27 +78,35 @@ class KeySetTest extends TestCase
}
/**
* @test
*
* @expectedException \Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage KeySet rule accepts only Key rules
*/
public function testShouldNotAcceptANonKeyRule(): void
public function shouldNotAcceptANonKeyRule(): void
{
$alwaysValid = new AlwaysValid();
new KeySet($alwaysValid);
}
public function testShouldReturnKeys(): void
/**
* @test
*/
public function shouldReturnKeys(): void
{
$key1 = new Key('foo', new AlwaysValid(), true);
$key2 = new Key('bar', new AlwaysValid(), false);
$keySet = new KeySet($key1, $key2);
self::assertEquals(['foo', 'bar'], $keySet->getKeys());
self::assertAttributeSame(['foo', 'bar'], 'keys', $keySet);
}
public function testShouldValidateKeysWhenThereAreMissingRequiredKeys(): void
/**
* @test
*/
public function shouldValidateKeysWhenThereAreMissingRequiredKeys(): void
{
$input = [
'foo' => 42,
@ -103,7 +120,10 @@ class KeySetTest extends TestCase
self::assertFalse($keySet->validate($input));
}
public function testShouldValidateKeysWhenThereAreMissingNonRequiredKeys(): void
/**
* @test
*/
public function shouldValidateKeysWhenThereAreMissingNonRequiredKeys(): void
{
$input = [
'foo' => 42,
@ -117,7 +137,10 @@ class KeySetTest extends TestCase
self::assertTrue($keySet->validate($input));
}
public function testShouldValidateKeysWhenThereAreMoreKeys(): void
/**
* @test
*/
public function shouldValidateKeysWhenThereAreMoreKeys(): void
{
$input = [
'foo' => 42,
@ -133,7 +156,10 @@ class KeySetTest extends TestCase
self::assertFalse($keySet->validate($input));
}
public function testShouldValidateKeysWhenEmpty(): void
/**
* @test
*/
public function shouldValidateKeysWhenEmpty(): void
{
$input = [];
@ -146,10 +172,12 @@ class KeySetTest extends TestCase
}
/**
* @test
*
* @expectedException \Respect\Validation\Exceptions\KeySetException
* @expectedExceptionMessage Must have keys `{ "foo", "bar" }`
*/
public function testShouldCheckKeys(): void
public function shouldCheckKeys(): void
{
$input = [];
@ -161,10 +189,12 @@ class KeySetTest extends TestCase
}
/**
* @test
*
* @expectedException \Respect\Validation\Exceptions\KeySetException
* @expectedExceptionMessage Must have keys `{ "foo", "bar" }`
*/
public function testShouldAssertKeys(): void
public function shouldAssertKeys(): void
{
$input = [];
@ -176,17 +206,20 @@ class KeySetTest extends TestCase
}
/**
* @test
*
* @dataProvider providerForInvalidArguments
*
* @expectedException \Respect\Validation\Exceptions\KeySetException
* @expectedExceptionMessage Must have keys `{ "name" }`
* @dataProvider providerForInvalidArguments
*/
public function testShouldThrowExceptionInCaseArgumentIsAnythingOtherThanArray($input): void
public function shouldThrowExceptionInCaseArgumentIsAnythingOtherThanArray($input): void
{
$keySet = new KeySet(new Key('name'));
$keySet->assert($input);
}
public function providerForInvalidArguments()
public function providerForInvalidArguments(): array
{
return [
[''],