Skip to content

Commit d01fd93

Browse files
Merge branch '4.4' into 5.0
* 4.4: [travis] fix CI (ter) Revert "[travis][appveyor] don't cache .phpunit" silence E_NOTICE triggered since PHP 7.4 [Form] Removed legacy check in `ValidationListener` [HttpClient] fix HTTP/2 support on non-SSL connections - CurlHttpClient only Force ping after transport Exception do not merge constraints within interfaces [Validator] Fixed default group for nested composite constraints
2 parents b6562e5 + fc33ffe commit d01fd93

File tree

10 files changed

+136
-22
lines changed

10 files changed

+136
-22
lines changed

Constraints/Composite.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,8 @@ public function __construct($options = null)
8888
}
8989
}
9090

91-
$this->groups = array_keys($mergedGroups);
91+
// prevent empty composite constraint to have empty groups
92+
$this->groups = array_keys($mergedGroups) ?: [self::DEFAULT_GROUP];
9293
$this->$compositeOption = $nestedConstraints;
9394

9495
return;

Mapping/Factory/LazyLoadingMetadataFactory.php

Lines changed: 10 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -113,34 +113,25 @@ public function getMetadataFor($value)
113113

114114
private function mergeConstraints(ClassMetadata $metadata)
115115
{
116+
if ($metadata->getReflectionClass()->isInterface()) {
117+
return;
118+
}
119+
116120
// Include constraints from the parent class
117121
if ($parent = $metadata->getReflectionClass()->getParentClass()) {
118122
$metadata->mergeConstraints($this->getMetadataFor($parent->name));
119123
}
120124

121-
$interfaces = $metadata->getReflectionClass()->getInterfaces();
122-
123-
$interfaces = array_filter($interfaces, function (\ReflectionClass $interface) use ($parent, $interfaces) {
124-
$interfaceName = $interface->getName();
125-
126-
if ($parent && $parent->implementsInterface($interfaceName)) {
127-
return false;
128-
}
129-
130-
foreach ($interfaces as $i) {
131-
if ($i !== $interface && $i->implementsInterface($interfaceName)) {
132-
return false;
133-
}
134-
}
135-
136-
return true;
137-
});
138-
139125
// Include constraints from all directly implemented interfaces
140-
foreach ($interfaces as $interface) {
126+
foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
141127
if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name) {
142128
continue;
143129
}
130+
131+
if ($parent && \in_array($interface->getName(), $parent->getInterfaceNames(), true)) {
132+
continue;
133+
}
134+
144135
$metadata->mergeConstraints($this->getMetadataFor($interface->name));
145136
}
146137
}

Tests/Constraints/CollectionTest.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,16 @@ public function testAcceptRequiredConstraintAsOneElementArray()
100100

101101
$this->assertEquals($collection1, $collection2);
102102
}
103+
104+
public function testConstraintHasDefaultGroupWithOptionalValues()
105+
{
106+
$constraint = new Collection([
107+
'foo' => new Required(),
108+
'bar' => new Optional(),
109+
]);
110+
111+
$this->assertEquals(['Default'], $constraint->groups);
112+
$this->assertEquals(['Default'], $constraint->fields['foo']->groups);
113+
$this->assertEquals(['Default'], $constraint->fields['bar']->groups);
114+
}
103115
}

Tests/Constraints/CollectionValidatorTest.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,29 @@ public function testExtraFieldsDisallowed()
143143
->assertRaised();
144144
}
145145

146+
public function testExtraFieldsDisallowedWithOptionalValues()
147+
{
148+
$constraint = new Optional();
149+
150+
$data = $this->prepareTestData([
151+
'baz' => 6,
152+
]);
153+
154+
$this->validator->validate($data, new Collection([
155+
'fields' => [
156+
'foo' => $constraint,
157+
],
158+
'extraFieldsMessage' => 'myMessage',
159+
]));
160+
161+
$this->buildViolation('myMessage')
162+
->setParameter('{{ field }}', '"baz"')
163+
->atPath('property.path[baz]')
164+
->setInvalidValue(6)
165+
->setCode(Collection::NO_SUCH_FIELD_ERROR)
166+
->assertRaised();
167+
}
168+
146169
// bug fix
147170
public function testNullNotConsideredExtraField()
148171
{

Tests/Constraints/CompositeTest.php

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
class ConcreteComposite extends Composite
2121
{
22-
public $constraints;
22+
public $constraints = [];
2323

2424
protected function getCompositeOption(): string
2525
{
@@ -37,6 +37,30 @@ public function getDefaultOption(): ?string
3737
*/
3838
class CompositeTest extends TestCase
3939
{
40+
public function testConstraintHasDefaultGroup()
41+
{
42+
$constraint = new ConcreteComposite([
43+
new NotNull(),
44+
new NotBlank(),
45+
]);
46+
47+
$this->assertEquals(['Default'], $constraint->groups);
48+
$this->assertEquals(['Default'], $constraint->constraints[0]->groups);
49+
$this->assertEquals(['Default'], $constraint->constraints[1]->groups);
50+
}
51+
52+
public function testNestedCompositeConstraintHasDefaultGroup()
53+
{
54+
$constraint = new ConcreteComposite([
55+
new ConcreteComposite(),
56+
new ConcreteComposite(),
57+
]);
58+
59+
$this->assertEquals(['Default'], $constraint->groups);
60+
$this->assertEquals(['Default'], $constraint->constraints[0]->groups);
61+
$this->assertEquals(['Default'], $constraint->constraints[1]->groups);
62+
}
63+
4064
public function testMergeNestedGroupsIfNoExplicitParentGroup()
4165
{
4266
$constraint = new ConcreteComposite([
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<?php
2+
3+
namespace Symfony\Component\Validator\Tests\Fixtures;
4+
5+
abstract class AbstractPropertyGetter implements PropertyGetterInterface
6+
{
7+
private $property;
8+
9+
public function getProperty()
10+
{
11+
return $this->property;
12+
}
13+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Component\Validator\Tests\Fixtures;
4+
5+
interface ChildGetterInterface extends PropertyGetterInterface
6+
{
7+
}

Tests/Fixtures/PropertyGetter.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
namespace Symfony\Component\Validator\Tests\Fixtures;
4+
5+
/**
6+
* This class has two paths to PropertyGetterInterface:
7+
* PropertyGetterInterface <- AbstractPropertyGetter <- PropertyGetter
8+
* PropertyGetterInterface <- ChildGetterInterface <- PropertyGetter
9+
*/
10+
class PropertyGetter extends AbstractPropertyGetter implements ChildGetterInterface
11+
{
12+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Component\Validator\Tests\Fixtures;
4+
5+
interface PropertyGetterInterface
6+
{
7+
public function getProperty();
8+
}

Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
use Psr\Cache\CacheItemPoolInterface;
1616
use Symfony\Component\Cache\Adapter\ArrayAdapter;
1717
use Symfony\Component\Validator\Constraints\Callback;
18+
use Symfony\Component\Validator\Constraints\NotBlank;
1819
use Symfony\Component\Validator\Mapping\ClassMetadata;
1920
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
2021
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
2122
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
23+
use Symfony\Component\Validator\Tests\Fixtures\PropertyGetter;
24+
use Symfony\Component\Validator\Tests\Fixtures\PropertyGetterInterface;
2225

2326
class LazyLoadingMetadataFactoryTest extends TestCase
2427
{
@@ -70,7 +73,6 @@ public function testMergeParentConstraints()
7073
new ConstraintA(['groups' => [
7174
'Default',
7275
'EntityParentInterface',
73-
'EntityInterfaceB',
7476
'Entity',
7577
]]),
7678
];
@@ -150,6 +152,15 @@ public function testGroupsFromParent()
150152
$this->assertContains('EntityStaticCar', $groups);
151153
$this->assertContains('EntityStaticVehicle', $groups);
152154
}
155+
156+
public function testMultipathInterfaceConstraint()
157+
{
158+
$factory = new LazyLoadingMetadataFactory(new PropertyGetterInterfaceConstraintLoader());
159+
$metadata = $factory->getMetadataFor(PropertyGetter::class);
160+
$constraints = $metadata->getPropertyMetadata('property');
161+
162+
$this->assertCount(1, $constraints);
163+
}
153164
}
154165

155166
class TestLoader implements LoaderInterface
@@ -161,3 +172,15 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
161172
return true;
162173
}
163174
}
175+
176+
class PropertyGetterInterfaceConstraintLoader implements LoaderInterface
177+
{
178+
public function loadClassMetadata(ClassMetadata $metadata)
179+
{
180+
if (PropertyGetterInterface::class === $metadata->getClassName()) {
181+
$metadata->addGetterConstraint('property', new NotBlank());
182+
}
183+
184+
return true;
185+
}
186+
}

0 commit comments

Comments
 (0)