Skip to content

Commit

Permalink
Add optional parameter to allow extra unvalidated fields (#30)
Browse files Browse the repository at this point in the history
Add optional parameter to allow extra unvalidated fields
default set false, to keep existing functionality
  • Loading branch information
bram123 authored Sep 20, 2021
1 parent 147c5db commit 5827baf
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 46 deletions.
52 changes: 38 additions & 14 deletions src/Constraint/ConstraintCollectionBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@
*/
class ConstraintCollectionBuilder
{
/** @var bool */
private $allowExtraFields = false;

public function setAllowExtraFields(bool $allowExtraFields): self
{
$this->allowExtraFields = $allowExtraFields;

return $this;
}

/**
* @return Constraint|Constraint[]
* @throws InvalidRuleException
Expand All @@ -38,6 +48,7 @@ public function build(ConstraintMap $constraintsMap)

/**
* @param array<string|int, ConstraintMapItem|array<ConstraintMapItem>> $constraintTreeMap
*
* @return Constraint|Constraint[]
* @throws InvalidRuleException
*/
Expand All @@ -52,6 +63,7 @@ private function createConstraintTree(array $constraintTreeMap)

/**
* @param ConstraintMapItem|array<ConstraintMapItem> $node
*
* @return Constraint|Constraint[]
* @throws InvalidRuleException
*/
Expand All @@ -74,6 +86,7 @@ private function createAllConstraint($node)

/**
* @param array<string|int, ConstraintMapItem|array<ConstraintMapItem>> $constraintTreeMap
*
* @throws InvalidRuleException
*/
private function createCollectionConstraint(array $constraintTreeMap): Assert\Collection
Expand All @@ -89,23 +102,34 @@ private function createCollectionConstraint(array $constraintTreeMap): Assert\Co
$optional = true;
}

if ($node instanceof ConstraintMapItem === false) {
// recursively resolve
$constraint = $this->createConstraintTree($node);
} else {
// leaf node, check for required. It should over rule any optional indicators in the key
$constraint = $node->getConstraints();
$optional = $node->isRequired() === false;
}
$constraintMap[$key] = $this->getNodeConstraint($node, $optional);
}

// optional key
if ($optional && $constraint instanceof Assert\Required === false && $constraint instanceof Assert\Optional === false) {
$constraint = new Assert\Optional($constraint);
}
return new Assert\Collection(['fields' => $constraintMap, 'allowExtraFields' => $this->allowExtraFields]);
}

/**
* @param ConstraintMapItem|array<ConstraintMapItem> $node
*
* @return Constraint|Constraint[]
* @throws InvalidRuleException
*/
private function getNodeConstraint($node, bool $optional)
{
if ($node instanceof ConstraintMapItem === false) {
// recursively resolve
$constraint = $this->createConstraintTree($node);
} else {
// leaf node, check for required. It should overrule any optional indicators in the key
$constraint = $node->getConstraints();
$optional = $node->isRequired() === false;
}

$constraintMap[$key] = $constraint;
// optional key
if ($optional && $constraint instanceof Assert\Required === false && $constraint instanceof Assert\Optional === false) {
return new Assert\Optional($constraint);
}

return new Assert\Collection($constraintMap);
return $constraint;
}
}
7 changes: 5 additions & 2 deletions src/ConstraintFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,13 @@ public function __construct(RuleParser $parser = null, ConstraintResolver $resol

/**
* @param Constraint|array<string, string|Constraint|array<string|Constraint>> $ruleDefinitions
* @param bool $allowExtraFields Allow for extra, unvalidated, fields to be sent
* to the constraint collection
*
* @return Constraint|Constraint[]
* @throws InvalidRuleException
*/
public function fromRuleDefinitions($ruleDefinitions)
public function fromRuleDefinitions($ruleDefinitions, bool $allowExtraFields = false)
{
if ($ruleDefinitions instanceof Constraint) {
return $ruleDefinitions;
Expand All @@ -54,6 +57,6 @@ public function fromRuleDefinitions($ruleDefinitions)
}

// transform ConstraintMap to ConstraintCollection
return $this->collectionBuilder->build($constraintMap);
return $this->collectionBuilder->setAllowExtraFields($allowExtraFields)->build($constraintMap);
}
}
43 changes: 21 additions & 22 deletions tests/Unit/Constraint/ConstraintCollectionBuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
* @covers ::createConstraintTree
* @covers ::createAllConstraint
* @covers ::createCollectionConstraint
* @covers ::getNodeConstraint
*/
class ConstraintCollectionBuilderTest extends TestCase
{
Expand Down Expand Up @@ -49,6 +50,21 @@ public function testBuildSingleNonNestedConstraint(): void
static::assertEquals($expect, $result);
}

/**
* @covers ::build
* @throws Exception
*/
public function testBuildSingleCollectionAllowExtraFieldsConstraint(): void
{
$constraint = new NotNull();
$constraintMap = new ConstraintMap();
$constraintMap->set('a', new ConstraintMapItem([$constraint], true));

$result = $this->builder->setAllowExtraFields(true)->build($constraintMap);
$expect = new Collection(['fields' => ['a' => new NotNull()], 'allowExtraFields' => true]);
static::assertEquals($expect, $result);
}

/**
* @covers ::build
* @throws Exception
Expand Down Expand Up @@ -77,12 +93,7 @@ public function testBuildMultipleNestedConstraints(): void
$constraintMap->set('a.b', new ConstraintMapItem([$constraintB], true));

$result = $this->builder->build($constraintMap);
$expect = new Collection([
'a' => new Collection([
'a' => new NotNull(),
'b' => new Blank()
])
]);
$expect = new Collection(['a' => new Collection(['a' => new NotNull(), 'b' => new Blank()])]);
static::assertEquals($expect, $result);
}

Expand All @@ -97,20 +108,14 @@ public function testBuildOptionalConstraints(): void
$constraintMap->set('a?.b', new ConstraintMapItem([$constraint], true));

$result = $this->builder->build($constraintMap);
$expect = new Collection([
'a' => new Optional([
new Collection([
'b' => new NotNull()
])
])
]);
$expect = new Collection(['a' => new Optional([new Collection(['b' => new NotNull()])])]);
static::assertEquals($expect, $result);
}

/**
* If the constraint is set to required but the path is marked as optional, then always assume Required
*
* @covers ::build
*
* @throws Exception
*/
public function testBuildOptionalConstraintShouldNotOverwriteRequired(): void
Expand All @@ -120,11 +125,7 @@ public function testBuildOptionalConstraintShouldNotOverwriteRequired(): void
$constraintMap->set('a.b?', new ConstraintMapItem([$constraint], true));

$result = $this->builder->build($constraintMap);
$expect = new Collection([
'a' => new Collection([
'b' => new Required(new NotNull())
])
]);
$expect = new Collection(['a' => new Collection(['b' => new Required(new NotNull())])]);
static::assertEquals($expect, $result);
}

Expand Down Expand Up @@ -173,9 +174,7 @@ public function testBuildWithAllAndCollectionConstraint(): void

$result = $this->builder->build($constraintMap);
$expect =
new All([
new Collection(['fields' => ['name' => $constraint]])
]);
new All([new Collection(['fields' => ['name' => $constraint]])]);

static::assertEquals($expect, $result);
}
Expand Down
24 changes: 16 additions & 8 deletions tests/Unit/ConstraintFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ConstraintFactoryTest extends TestCase
*/
public function testFromRuleDefinitionsConstraintOnly(): void
{
$factory = new ConstraintFactory();
$factory = new ConstraintFactory();
$constraint = new Assert\NotBlank();
static::assertSame($constraint, $factory->fromRuleDefinitions($constraint));
}
Expand All @@ -32,12 +32,20 @@ public function testFromRuleDefinitionsConstraintOnly(): void
public function testFromRuleDefinitionsWithRule(): void
{
$factory = new ConstraintFactory();
$expect = new Assert\Collection([
'email' => new Assert\Required([
new Assert\Email(),
new Assert\NotNull()
])
]);
static::assertEquals($expect, $factory->fromRuleDefinitions(['email' => 'required|email']));
$expect = new Assert\Collection(['email' => new Assert\Required([new Assert\Email(), new Assert\NotNull()])]);
static::assertEquals($expect, $factory->fromRuleDefinitions(['email' => 'required|email'], false));
}

/**
* @covers ::fromRuleDefinitions
* @throws Exception
*/
public function testFromRuleDefinitionsWithRuleAllowExtraFields(): void
{
$factory = new ConstraintFactory();
$expect = new Assert\Collection(
['fields' => ['email' => new Assert\Required([new Assert\Email(), new Assert\NotNull()])], 'allowExtraFields' => true]
);
static::assertEquals($expect, $factory->fromRuleDefinitions(['email' => 'required|email'], true));
}
}

0 comments on commit 5827baf

Please sign in to comment.