From 2f9b65aa5a0baa4cdc20908012cf461202670bbd Mon Sep 17 00:00:00 2001 From: Mathieu Lemoine Date: Wed, 28 Sep 2016 14:31:59 -0400 Subject: [PATCH] Fix #19943 Make sure to process each interface metadata only once --- .../Factory/LazyLoadingMetadataFactory.php | 24 +++++++-- .../Validator/Tests/Fixtures/Entity.php | 2 +- ...tityInterface.php => EntityInterfaceA.php} | 2 +- .../Tests/Fixtures/EntityInterfaceB.php | 16 ++++++ .../Validator/Tests/Fixtures/EntityParent.php | 2 +- .../Tests/Fixtures/EntityParentInterface.php | 16 ++++++ .../LazyLoadingMetadataFactoryTest.php | 49 ++++++++++++------- 7 files changed, 88 insertions(+), 23 deletions(-) rename src/Symfony/Component/Validator/Tests/Fixtures/{EntityInterface.php => EntityInterfaceA.php} (91%) create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceB.php create mode 100644 src/Symfony/Component/Validator/Tests/Fixtures/EntityParentInterface.php diff --git a/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php b/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php index b5b202de6d2b6..9987b1ca1e13f 100644 --- a/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php +++ b/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php @@ -116,9 +116,27 @@ public function getMetadataFor($value) $metadata->mergeConstraints($this->getMetadataFor($parent->name)); } - // Include constraints from all implemented interfaces that have not been processed via parent class yet - foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) { - if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name || ($parent && $parent->implementsInterface($interface->name))) { + $interfaces = $metadata->getReflectionClass()->getInterfaces(); + + $interfaces = array_filter($interfaces, function ($interface) use ($parent, $interfaces) { + $interfaceName = $interface->getName(); + + if ($parent && $parent->implementsInterface($interfaceName)) { + return false; + } + + foreach ($interfaces as $i) { + if ($i !== $interface && $i->implementsInterface($interfaceName)) { + return false; + } + } + + return true; + }); + + // Include constraints from all directly implemented interfaces + foreach ($interfaces as $interface) { + if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name) { continue; } $metadata->mergeConstraints($this->getMetadataFor($interface->name)); diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php b/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php index e4eec6be32eb1..77a86108a1ae0 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php @@ -19,7 +19,7 @@ * @Assert\GroupSequence({"Foo", "Entity"}) * @Assert\Callback({"Symfony\Component\Validator\Tests\Fixtures\CallbackClass", "callback"}) */ -class Entity extends EntityParent +class Entity extends EntityParent implements EntityInterfaceB { /** * @Assert\NotNull diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterface.php b/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceA.php similarity index 91% rename from src/Symfony/Component/Validator/Tests/Fixtures/EntityInterface.php rename to src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceA.php index 2901f26386b4e..a0afcf8163110 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterface.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceA.php @@ -11,6 +11,6 @@ namespace Symfony\Component\Validator\Tests\Fixtures; -interface EntityInterface +interface EntityInterfaceA { } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceB.php b/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceB.php new file mode 100644 index 0000000000000..93b389414fadf --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/EntityInterfaceB.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Fixtures; + +interface EntityInterfaceB extends EntityParentInterface +{ +} diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php index acbec3d32e88b..4674f8b35a226 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParent.php @@ -13,7 +13,7 @@ use Symfony\Component\Validator\Constraints\NotNull; -class EntityParent implements EntityInterface +class EntityParent implements EntityInterfaceA { protected $firstName; private $internal; diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/EntityParentInterface.php b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParentInterface.php new file mode 100644 index 0000000000000..3aad6fec5f76e --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/EntityParentInterface.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Fixtures; + +interface EntityParentInterface +{ +} diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php index c78d2a72c8d60..c1aaa9f8c7bf2 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php @@ -18,17 +18,19 @@ class LazyLoadingMetadataFactoryTest extends \PHPUnit_Framework_TestCase { - const CLASSNAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity'; - const PARENTCLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParent'; - const INTERFACECLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityInterface'; + const CLASS_NAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity'; + const PARENT_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParent'; + const INTERFACE_A_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityInterfaceA'; + const INTERFACE_B_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityInterfaceB'; + const PARENT_INTERFACE_CLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParentInterface'; public function testLoadClassMetadataWithInterface() { $factory = new LazyLoadingMetadataFactory(new TestLoader()); - $metadata = $factory->getMetadataFor(self::PARENTCLASS); + $metadata = $factory->getMetadataFor(self::PARENT_CLASS); $constraints = array( - new ConstraintA(array('groups' => array('Default', 'EntityInterface', 'EntityParent'))), + new ConstraintA(array('groups' => array('Default', 'EntityInterfaceA', 'EntityParent'))), new ConstraintA(array('groups' => array('Default', 'EntityParent'))), ); @@ -38,12 +40,12 @@ public function testLoadClassMetadataWithInterface() public function testMergeParentConstraints() { $factory = new LazyLoadingMetadataFactory(new TestLoader()); - $metadata = $factory->getMetadataFor(self::CLASSNAME); + $metadata = $factory->getMetadataFor(self::CLASS_NAME); $constraints = array( new ConstraintA(array('groups' => array( 'Default', - 'EntityInterface', + 'EntityInterfaceA', 'EntityParent', 'Entity', ))), @@ -52,6 +54,17 @@ public function testMergeParentConstraints() 'EntityParent', 'Entity', ))), + new ConstraintA(array('groups' => array( + 'Default', + 'EntityParentInterface', + 'EntityInterfaceB', + 'Entity', + ))), + new ConstraintA(array('groups' => array( + 'Default', + 'EntityInterfaceB', + 'Entity', + ))), new ConstraintA(array('groups' => array( 'Default', 'Entity', @@ -67,34 +80,36 @@ public function testWriteMetadataToCache() $factory = new LazyLoadingMetadataFactory(new TestLoader(), $cache); $parentClassConstraints = array( - new ConstraintA(array('groups' => array('Default', 'EntityInterface', 'EntityParent'))), + new ConstraintA(array('groups' => array('Default', 'EntityInterfaceA', 'EntityParent'))), new ConstraintA(array('groups' => array('Default', 'EntityParent'))), ); - $interfaceConstraints = array(new ConstraintA(array('groups' => array('Default', 'EntityInterface')))); + $interfaceAConstraints = array( + new ConstraintA(array('groups' => array('Default', 'EntityInterfaceA'))), + ); $cache->expects($this->never()) ->method('has'); $cache->expects($this->exactly(2)) ->method('read') ->withConsecutive( - array($this->equalTo(self::PARENTCLASS)), - array($this->equalTo(self::INTERFACECLASS)) + array($this->equalTo(self::PARENT_CLASS)), + array($this->equalTo(self::INTERFACE_A_CLASS)) ) ->will($this->returnValue(false)); $cache->expects($this->exactly(2)) ->method('write') ->withConsecutive( - $this->callback(function ($metadata) use ($interfaceConstraints) { - return $interfaceConstraints == $metadata->getConstraints(); + $this->callback(function ($metadata) use ($interfaceAConstraints) { + return $interfaceAConstraints == $metadata->getConstraints(); }), $this->callback(function ($metadata) use ($parentClassConstraints) { return $parentClassConstraints == $metadata->getConstraints(); }) ); - $metadata = $factory->getMetadataFor(self::PARENTCLASS); + $metadata = $factory->getMetadataFor(self::PARENT_CLASS); - $this->assertEquals(self::PARENTCLASS, $metadata->getClassName()); + $this->assertEquals(self::PARENT_CLASS, $metadata->getClassName()); $this->assertEquals($parentClassConstraints, $metadata->getConstraints()); } @@ -104,7 +119,7 @@ public function testReadMetadataFromCache() $cache = $this->getMock('Symfony\Component\Validator\Mapping\Cache\CacheInterface'); $factory = new LazyLoadingMetadataFactory($loader, $cache); - $metadata = new ClassMetadata(self::PARENTCLASS); + $metadata = new ClassMetadata(self::PARENT_CLASS); $metadata->addConstraint(new ConstraintA()); $loader->expects($this->never()) @@ -116,7 +131,7 @@ public function testReadMetadataFromCache() ->method('read') ->will($this->returnValue($metadata)); - $this->assertEquals($metadata, $factory->getMetadataFor(self::PARENTCLASS)); + $this->assertEquals($metadata, $factory->getMetadataFor(self::PARENT_CLASS)); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy