Skip to content

Commit a696f42

Browse files
committed
Fix #19943 Make sure to process each interface metadata only once
1 parent da6c664 commit a696f42

File tree

5 files changed

+60
-9
lines changed

5 files changed

+60
-9
lines changed

src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -116,9 +116,26 @@ public function getMetadataFor($value)
116116
$metadata->mergeConstraints($this->getMetadataFor($parent->name));
117117
}
118118

119-
// Include constraints from all implemented interfaces that have not been processed via parent class yet
120-
foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
121-
if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name || ($parent && $parent->implementsInterface($interface->name))) {
119+
$interfaces = $metadata->getReflectionClass()->getInterfaces();
120+
$interfaces = array_filter($interfaces, function ($interface) use ($parent, $interfaces) {
121+
$interfaceName = $interface->getName();
122+
123+
if ($parent && $parent->implementsInterface($interfaceName)) {
124+
return false;
125+
}
126+
127+
foreach ($interfaces as $i) {
128+
if ($i !== $interface && $i->implementsInterface($interfaceName)) {
129+
return false;
130+
}
131+
}
132+
133+
return true;
134+
});
135+
136+
// Include constraints from all directly implemented interfaces
137+
foreach ($interfaces as $interface) {
138+
if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name) {
122139
continue;
123140
}
124141
$metadata->mergeConstraints($this->getMetadataFor($interface->name));

src/Symfony/Component/Validator/Tests/Fixtures/Entity.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
* @Assert\GroupSequence({"Foo", "Entity"})
2020
* @Assert\Callback({"Symfony\Component\Validator\Tests\Fixtures\CallbackClass", "callback"})
2121
*/
22-
class Entity extends EntityParent
22+
class Entity extends EntityParent implements EntityInterface, EntityParentInterface
2323
{
2424
/**
2525
* @Assert\NotNull

src/Symfony/Component/Validator/Tests/Fixtures/EntityInterface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,6 @@
1111

1212
namespace Symfony\Component\Validator\Tests\Fixtures;
1313

14-
interface EntityInterface
14+
interface EntityInterface extends EntityParentInterface
1515
{
1616
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Validator\Tests\Fixtures;
13+
14+
interface EntityParentInterface
15+
{
16+
}

src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@ class LazyLoadingMetadataFactoryTest extends \PHPUnit_Framework_TestCase
2121
const CLASSNAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity';
2222
const PARENTCLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParent';
2323
const INTERFACECLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityInterface';
24+
const PARENTINTERFACECLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParentInterface';
2425

2526
public function testLoadClassMetadataWithInterface()
2627
{
2728
$factory = new LazyLoadingMetadataFactory(new TestLoader());
2829
$metadata = $factory->getMetadataFor(self::PARENTCLASS);
2930

3031
$constraints = array(
32+
new ConstraintA(array('groups' => array('Default', 'EntityParentInterface', 'EntityInterface', 'EntityParent'))),
3133
new ConstraintA(array('groups' => array('Default', 'EntityInterface', 'EntityParent'))),
3234
new ConstraintA(array('groups' => array('Default', 'EntityParent'))),
3335
);
@@ -41,6 +43,13 @@ public function testMergeParentConstraints()
4143
$metadata = $factory->getMetadataFor(self::CLASSNAME);
4244

4345
$constraints = array(
46+
new ConstraintA(array('groups' => array(
47+
'Default',
48+
'EntityParentInterface',
49+
'EntityInterface',
50+
'EntityParent',
51+
'Entity',
52+
))),
4453
new ConstraintA(array('groups' => array(
4554
'Default',
4655
'EntityInterface',
@@ -67,23 +76,32 @@ public function testWriteMetadataToCache()
6776
$factory = new LazyLoadingMetadataFactory(new TestLoader(), $cache);
6877

6978
$parentClassConstraints = array(
79+
new ConstraintA(array('groups' => array('Default', 'EntityParentInterface', 'EntityInterface', 'EntityParent'))),
7080
new ConstraintA(array('groups' => array('Default', 'EntityInterface', 'EntityParent'))),
7181
new ConstraintA(array('groups' => array('Default', 'EntityParent'))),
7282
);
73-
$interfaceConstraints = array(new ConstraintA(array('groups' => array('Default', 'EntityInterface'))));
83+
$interfaceConstraints = array(
84+
new ConstraintA(array('groups' => array('Default', 'EntityParentInterface', 'EntityInterface'))),
85+
new ConstraintA(array('groups' => array('Default', 'EntityParentInterface'))),
86+
);
87+
$parentInterfaceConstraints = array(new ConstraintA(array('groups' => array('Default', 'EntityParentInterface'))));
7488

7589
$cache->expects($this->never())
7690
->method('has');
77-
$cache->expects($this->exactly(2))
91+
$cache->expects($this->exactly(3))
7892
->method('read')
7993
->withConsecutive(
8094
array($this->equalTo(self::PARENTCLASS)),
81-
array($this->equalTo(self::INTERFACECLASS))
95+
array($this->equalTo(self::INTERFACECLASS)),
96+
array($this->equalTo(self::PARENTINTERFACECLASS))
8297
)
8398
->will($this->returnValue(false));
84-
$cache->expects($this->exactly(2))
99+
$cache->expects($this->exactly(3))
85100
->method('write')
86101
->withConsecutive(
102+
$this->callback(function ($metadata) use ($parentInterfaceConstraints) {
103+
return $parentInterfaceConstraints == $metadata->getConstraints();
104+
}),
87105
$this->callback(function ($metadata) use ($interfaceConstraints) {
88106
return $interfaceConstraints == $metadata->getConstraints();
89107
}),

0 commit comments

Comments
 (0)