Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Validator] do not merge constraints within interfaces #35591

Merged
merged 1 commit into from Apr 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -117,34 +117,25 @@ public function getMetadataFor($value)

private function mergeConstraints(ClassMetadata $metadata)
{
if ($metadata->getReflectionClass()->isInterface()) {
return;
}

// Include constraints from the parent class
if ($parent = $metadata->getReflectionClass()->getParentClass()) {
$metadata->mergeConstraints($this->getMetadataFor($parent->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) {
foreach ($metadata->getReflectionClass()->getInterfaces() as $interface) {
if ('Symfony\Component\Validator\GroupSequenceProviderInterface' === $interface->name) {
continue;
}

if ($parent && \in_array($interface->getName(), $parent->getInterfaceNames(), true)) {
continue;
}

$metadata->mergeConstraints($this->getMetadataFor($interface->name));
}
}
Expand Down
@@ -0,0 +1,13 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

abstract class AbstractPropertyGetter implements PropertyGetterInterface
{
private $property;

public function getProperty()
{
return $this->property;
}
}
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

interface ChildGetterInterface extends PropertyGetterInterface
{
}
12 changes: 12 additions & 0 deletions src/Symfony/Component/Validator/Tests/Fixtures/PropertyGetter.php
@@ -0,0 +1,12 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

/**
* This class has two paths to PropertyGetterInterface:
* PropertyGetterInterface <- AbstractPropertyGetter <- PropertyGetter
* PropertyGetterInterface <- ChildGetterInterface <- PropertyGetter
*/
class PropertyGetter extends AbstractPropertyGetter implements ChildGetterInterface
{
}
@@ -0,0 +1,8 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

interface PropertyGetterInterface
{
public function getProperty();
}
Expand Up @@ -14,11 +14,14 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Mapping\Cache\Psr6Cache;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
use Symfony\Component\Validator\Mapping\Loader\LoaderInterface;
use Symfony\Component\Validator\Tests\Fixtures\ConstraintA;
use Symfony\Component\Validator\Tests\Fixtures\PropertyGetter;
use Symfony\Component\Validator\Tests\Fixtures\PropertyGetterInterface;

class LazyLoadingMetadataFactoryTest extends TestCase
{
Expand Down Expand Up @@ -70,7 +73,6 @@ public function testMergeParentConstraints()
new ConstraintA(['groups' => [
'Default',
'EntityParentInterface',
'EntityInterfaceB',
'Entity',
]]),
];
Expand Down Expand Up @@ -186,6 +188,15 @@ public function testGroupsFromParent()
$this->assertContains('EntityStaticCar', $groups);
$this->assertContains('EntityStaticVehicle', $groups);
}

public function testMultipathInterfaceConstraint()
{
$factory = new LazyLoadingMetadataFactory(new PropertyGetterInterfaceConstraintLoader());
$metadata = $factory->getMetadataFor(PropertyGetter::class);
$constraints = $metadata->getPropertyMetadata('property');

$this->assertCount(1, $constraints);
}
}

class TestLoader implements LoaderInterface
Expand All @@ -195,3 +206,15 @@ public function loadClassMetadata(ClassMetadata $metadata)
$metadata->addConstraint(new ConstraintA());
}
}

class PropertyGetterInterfaceConstraintLoader implements LoaderInterface
{
public function loadClassMetadata(ClassMetadata $metadata)
{
if (PropertyGetterInterface::class === $metadata->getClassName()) {
$metadata->addGetterConstraint('property', new NotBlank());
}

return true;
}
}