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)); } }
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: