Skip to content

Commit fc33ffe

Browse files
Merge branch '3.4' into 4.4
* 3.4: Revert "[travis][appveyor] don't cache .phpunit" silence E_NOTICE triggered since PHP 7.4 [Form] Removed legacy check in `ValidationListener` do not merge constraints within interfaces [Validator] Fixed default group for nested composite constraints
2 parents a8254c1 + e885fb7 commit fc33ffe

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
@@ -138,34 +138,25 @@ public function getMetadataFor($value)
138138

139139
private function mergeConstraints(ClassMetadata $metadata)
140140
{
141+
if ($metadata->getReflectionClass()->isInterface()) {
142+
return;
143+
}
144+
141145
// Include constraints from the parent class
142146
if ($parent = $metadata->getReflectionClass()->getParentClass()) {
143147
$metadata->mergeConstraints($this->getMetadataFor($parent->name));
144148
}
145149

146-
$interfaces = $metadata->getReflectionClass()->getInterfaces();
147-
148-
$interfaces = array_filter($interfaces, function (\ReflectionClass $interface) use ($parent, $interfaces) {
149-
$interfaceName = $interface->getName();
150-
151-
if ($parent && $parent->implementsInterface($interfaceName)) {
152-
return false;
153-
}
154-
155-
foreach ($interfaces as $i) {
156-
if ($i !== $interface && $i->implementsInterface($interfaceName)) {
157-
return false;
158-
}
159-
}
160-
161-
return true;
162-
});
163-
164150
// Include constraints from all directly implemented interfaces
165-
foreach ($interfaces as $interface) {
151+
foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
166152
if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name) {
167153
continue;
168154
}
155+
156+
if ($parent && \in_array($interface->getName(), $parent->getInterfaceNames(), true)) {
157+
continue;
158+
}
159+
169160
$metadata->mergeConstraints($this->getMetadataFor($interface->name));
170161
}
171162
}

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,11 +15,14 @@
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\Cache\Psr6Cache;
1920
use Symfony\Component\Validator\Mapping\ClassMetadata;
2021
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
2122
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
2223
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
24+
use Symfony\Component\Validator\Tests\Fixtures\PropertyGetter;
25+
use Symfony\Component\Validator\Tests\Fixtures\PropertyGetterInterface;
2326

2427
class LazyLoadingMetadataFactoryTest extends TestCase
2528
{
@@ -71,7 +74,6 @@ public function testMergeParentConstraints()
7174
new ConstraintA(['groups' => [
7275
'Default',
7376
'EntityParentInterface',
74-
'EntityInterfaceB',
7577
'Entity',
7678
]]),
7779
];
@@ -209,6 +211,15 @@ public function testGroupsFromParent()
209211
$this->assertContains('EntityStaticCar', $groups);
210212
$this->assertContains('EntityStaticVehicle', $groups);
211213
}
214+
215+
public function testMultipathInterfaceConstraint()
216+
{
217+
$factory = new LazyLoadingMetadataFactory(new PropertyGetterInterfaceConstraintLoader());
218+
$metadata = $factory->getMetadataFor(PropertyGetter::class);
219+
$constraints = $metadata->getPropertyMetadata('property');
220+
221+
$this->assertCount(1, $constraints);
222+
}
212223
}
213224

214225
class TestLoader implements LoaderInterface
@@ -220,3 +231,15 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
220231
return true;
221232
}
222233
}
234+
235+
class PropertyGetterInterfaceConstraintLoader implements LoaderInterface
236+
{
237+
public function loadClassMetadata(ClassMetadata $metadata)
238+
{
239+
if (PropertyGetterInterface::class === $metadata->getClassName()) {
240+
$metadata->addGetterConstraint('property', new NotBlank());
241+
}
242+
243+
return true;
244+
}
245+
}

0 commit comments

Comments
 (0)