Skip to content

Commit 5827baf

Browse files
authored
Add optional parameter to allow extra unvalidated fields (#30)
Add optional parameter to allow extra unvalidated fields default set false, to keep existing functionality
1 parent 147c5db commit 5827baf

File tree

4 files changed

+80
-46
lines changed

4 files changed

+80
-46
lines changed

src/Constraint/ConstraintCollectionBuilder.php

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414
*/
1515
class ConstraintCollectionBuilder
1616
{
17+
/** @var bool */
18+
private $allowExtraFields = false;
19+
20+
public function setAllowExtraFields(bool $allowExtraFields): self
21+
{
22+
$this->allowExtraFields = $allowExtraFields;
23+
24+
return $this;
25+
}
26+
1727
/**
1828
* @return Constraint|Constraint[]
1929
* @throws InvalidRuleException
@@ -38,6 +48,7 @@ public function build(ConstraintMap $constraintsMap)
3848

3949
/**
4050
* @param array<string|int, ConstraintMapItem|array<ConstraintMapItem>> $constraintTreeMap
51+
*
4152
* @return Constraint|Constraint[]
4253
* @throws InvalidRuleException
4354
*/
@@ -52,6 +63,7 @@ private function createConstraintTree(array $constraintTreeMap)
5263

5364
/**
5465
* @param ConstraintMapItem|array<ConstraintMapItem> $node
66+
*
5567
* @return Constraint|Constraint[]
5668
* @throws InvalidRuleException
5769
*/
@@ -74,6 +86,7 @@ private function createAllConstraint($node)
7486

7587
/**
7688
* @param array<string|int, ConstraintMapItem|array<ConstraintMapItem>> $constraintTreeMap
89+
*
7790
* @throws InvalidRuleException
7891
*/
7992
private function createCollectionConstraint(array $constraintTreeMap): Assert\Collection
@@ -89,23 +102,34 @@ private function createCollectionConstraint(array $constraintTreeMap): Assert\Co
89102
$optional = true;
90103
}
91104

92-
if ($node instanceof ConstraintMapItem === false) {
93-
// recursively resolve
94-
$constraint = $this->createConstraintTree($node);
95-
} else {
96-
// leaf node, check for required. It should over rule any optional indicators in the key
97-
$constraint = $node->getConstraints();
98-
$optional = $node->isRequired() === false;
99-
}
105+
$constraintMap[$key] = $this->getNodeConstraint($node, $optional);
106+
}
100107

101-
// optional key
102-
if ($optional && $constraint instanceof Assert\Required === false && $constraint instanceof Assert\Optional === false) {
103-
$constraint = new Assert\Optional($constraint);
104-
}
108+
return new Assert\Collection(['fields' => $constraintMap, 'allowExtraFields' => $this->allowExtraFields]);
109+
}
110+
111+
/**
112+
* @param ConstraintMapItem|array<ConstraintMapItem> $node
113+
*
114+
* @return Constraint|Constraint[]
115+
* @throws InvalidRuleException
116+
*/
117+
private function getNodeConstraint($node, bool $optional)
118+
{
119+
if ($node instanceof ConstraintMapItem === false) {
120+
// recursively resolve
121+
$constraint = $this->createConstraintTree($node);
122+
} else {
123+
// leaf node, check for required. It should overrule any optional indicators in the key
124+
$constraint = $node->getConstraints();
125+
$optional = $node->isRequired() === false;
126+
}
105127

106-
$constraintMap[$key] = $constraint;
128+
// optional key
129+
if ($optional && $constraint instanceof Assert\Required === false && $constraint instanceof Assert\Optional === false) {
130+
return new Assert\Optional($constraint);
107131
}
108132

109-
return new Assert\Collection($constraintMap);
133+
return $constraint;
110134
}
111135
}

src/ConstraintFactory.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,13 @@ public function __construct(RuleParser $parser = null, ConstraintResolver $resol
3131

3232
/**
3333
* @param Constraint|array<string, string|Constraint|array<string|Constraint>> $ruleDefinitions
34+
* @param bool $allowExtraFields Allow for extra, unvalidated, fields to be sent
35+
* to the constraint collection
36+
*
3437
* @return Constraint|Constraint[]
3538
* @throws InvalidRuleException
3639
*/
37-
public function fromRuleDefinitions($ruleDefinitions)
40+
public function fromRuleDefinitions($ruleDefinitions, bool $allowExtraFields = false)
3841
{
3942
if ($ruleDefinitions instanceof Constraint) {
4043
return $ruleDefinitions;
@@ -54,6 +57,6 @@ public function fromRuleDefinitions($ruleDefinitions)
5457
}
5558

5659
// transform ConstraintMap to ConstraintCollection
57-
return $this->collectionBuilder->build($constraintMap);
60+
return $this->collectionBuilder->setAllowExtraFields($allowExtraFields)->build($constraintMap);
5861
}
5962
}

tests/Unit/Constraint/ConstraintCollectionBuilderTest.php

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
* @covers ::createConstraintTree
2323
* @covers ::createAllConstraint
2424
* @covers ::createCollectionConstraint
25+
* @covers ::getNodeConstraint
2526
*/
2627
class ConstraintCollectionBuilderTest extends TestCase
2728
{
@@ -49,6 +50,21 @@ public function testBuildSingleNonNestedConstraint(): void
4950
static::assertEquals($expect, $result);
5051
}
5152

53+
/**
54+
* @covers ::build
55+
* @throws Exception
56+
*/
57+
public function testBuildSingleCollectionAllowExtraFieldsConstraint(): void
58+
{
59+
$constraint = new NotNull();
60+
$constraintMap = new ConstraintMap();
61+
$constraintMap->set('a', new ConstraintMapItem([$constraint], true));
62+
63+
$result = $this->builder->setAllowExtraFields(true)->build($constraintMap);
64+
$expect = new Collection(['fields' => ['a' => new NotNull()], 'allowExtraFields' => true]);
65+
static::assertEquals($expect, $result);
66+
}
67+
5268
/**
5369
* @covers ::build
5470
* @throws Exception
@@ -77,12 +93,7 @@ public function testBuildMultipleNestedConstraints(): void
7793
$constraintMap->set('a.b', new ConstraintMapItem([$constraintB], true));
7894

7995
$result = $this->builder->build($constraintMap);
80-
$expect = new Collection([
81-
'a' => new Collection([
82-
'a' => new NotNull(),
83-
'b' => new Blank()
84-
])
85-
]);
96+
$expect = new Collection(['a' => new Collection(['a' => new NotNull(), 'b' => new Blank()])]);
8697
static::assertEquals($expect, $result);
8798
}
8899

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

99110
$result = $this->builder->build($constraintMap);
100-
$expect = new Collection([
101-
'a' => new Optional([
102-
new Collection([
103-
'b' => new NotNull()
104-
])
105-
])
106-
]);
111+
$expect = new Collection(['a' => new Optional([new Collection(['b' => new NotNull()])])]);
107112
static::assertEquals($expect, $result);
108113
}
109114

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

122127
$result = $this->builder->build($constraintMap);
123-
$expect = new Collection([
124-
'a' => new Collection([
125-
'b' => new Required(new NotNull())
126-
])
127-
]);
128+
$expect = new Collection(['a' => new Collection(['b' => new Required(new NotNull())])]);
128129
static::assertEquals($expect, $result);
129130
}
130131

@@ -173,9 +174,7 @@ public function testBuildWithAllAndCollectionConstraint(): void
173174

174175
$result = $this->builder->build($constraintMap);
175176
$expect =
176-
new All([
177-
new Collection(['fields' => ['name' => $constraint]])
178-
]);
177+
new All([new Collection(['fields' => ['name' => $constraint]])]);
179178

180179
static::assertEquals($expect, $result);
181180
}

tests/Unit/ConstraintFactoryTest.php

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ class ConstraintFactoryTest extends TestCase
2020
*/
2121
public function testFromRuleDefinitionsConstraintOnly(): void
2222
{
23-
$factory = new ConstraintFactory();
23+
$factory = new ConstraintFactory();
2424
$constraint = new Assert\NotBlank();
2525
static::assertSame($constraint, $factory->fromRuleDefinitions($constraint));
2626
}
@@ -32,12 +32,20 @@ public function testFromRuleDefinitionsConstraintOnly(): void
3232
public function testFromRuleDefinitionsWithRule(): void
3333
{
3434
$factory = new ConstraintFactory();
35-
$expect = new Assert\Collection([
36-
'email' => new Assert\Required([
37-
new Assert\Email(),
38-
new Assert\NotNull()
39-
])
40-
]);
41-
static::assertEquals($expect, $factory->fromRuleDefinitions(['email' => 'required|email']));
35+
$expect = new Assert\Collection(['email' => new Assert\Required([new Assert\Email(), new Assert\NotNull()])]);
36+
static::assertEquals($expect, $factory->fromRuleDefinitions(['email' => 'required|email'], false));
37+
}
38+
39+
/**
40+
* @covers ::fromRuleDefinitions
41+
* @throws Exception
42+
*/
43+
public function testFromRuleDefinitionsWithRuleAllowExtraFields(): void
44+
{
45+
$factory = new ConstraintFactory();
46+
$expect = new Assert\Collection(
47+
['fields' => ['email' => new Assert\Required([new Assert\Email(), new Assert\NotNull()])], 'allowExtraFields' => true]
48+
);
49+
static::assertEquals($expect, $factory->fromRuleDefinitions(['email' => 'required|email'], true));
4250
}
4351
}

0 commit comments

Comments
 (0)