Skip to content

Commit

Permalink
Merge branch '4.4' into 5.0
Browse files Browse the repository at this point in the history
* 4.4:
  [travis] fix CI (ter)
  Revert "[travis][appveyor] don't cache .phpunit"
  silence E_NOTICE triggered since PHP 7.4
  [Form] Removed legacy check in `ValidationListener`
  [HttpClient] fix HTTP/2 support on non-SSL connections - CurlHttpClient only
  Force ping after transport Exception
  do not merge constraints within interfaces
  [Validator] Fixed default group for nested composite constraints
  • Loading branch information
nicolas-grekas committed Apr 12, 2020
2 parents b6562e5 + fc33ffe commit d01fd93
Show file tree
Hide file tree
Showing 10 changed files with 136 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Constraints/Composite.php
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ public function __construct($options = null)
}
}

$this->groups = array_keys($mergedGroups);
// prevent empty composite constraint to have empty groups
$this->groups = array_keys($mergedGroups) ?: [self::DEFAULT_GROUP];
$this->$compositeOption = $nestedConstraints;

return;
Expand Down
29 changes: 10 additions & 19 deletions Mapping/Factory/LazyLoadingMetadataFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,34 +113,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 (\ReflectionClass $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
12 changes: 12 additions & 0 deletions Tests/Constraints/CollectionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,16 @@ public function testAcceptRequiredConstraintAsOneElementArray()

$this->assertEquals($collection1, $collection2);
}

public function testConstraintHasDefaultGroupWithOptionalValues()
{
$constraint = new Collection([
'foo' => new Required(),
'bar' => new Optional(),
]);

$this->assertEquals(['Default'], $constraint->groups);
$this->assertEquals(['Default'], $constraint->fields['foo']->groups);
$this->assertEquals(['Default'], $constraint->fields['bar']->groups);
}
}
23 changes: 23 additions & 0 deletions Tests/Constraints/CollectionValidatorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,29 @@ public function testExtraFieldsDisallowed()
->assertRaised();
}

public function testExtraFieldsDisallowedWithOptionalValues()
{
$constraint = new Optional();

$data = $this->prepareTestData([
'baz' => 6,
]);

$this->validator->validate($data, new Collection([
'fields' => [
'foo' => $constraint,
],
'extraFieldsMessage' => 'myMessage',
]));

$this->buildViolation('myMessage')
->setParameter('{{ field }}', '"baz"')
->atPath('property.path[baz]')
->setInvalidValue(6)
->setCode(Collection::NO_SUCH_FIELD_ERROR)
->assertRaised();
}

// bug fix
public function testNullNotConsideredExtraField()
{
Expand Down
26 changes: 25 additions & 1 deletion Tests/Constraints/CompositeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

class ConcreteComposite extends Composite
{
public $constraints;
public $constraints = [];

protected function getCompositeOption(): string
{
Expand All @@ -37,6 +37,30 @@ public function getDefaultOption(): ?string
*/
class CompositeTest extends TestCase
{
public function testConstraintHasDefaultGroup()
{
$constraint = new ConcreteComposite([
new NotNull(),
new NotBlank(),
]);

$this->assertEquals(['Default'], $constraint->groups);
$this->assertEquals(['Default'], $constraint->constraints[0]->groups);
$this->assertEquals(['Default'], $constraint->constraints[1]->groups);
}

public function testNestedCompositeConstraintHasDefaultGroup()
{
$constraint = new ConcreteComposite([
new ConcreteComposite(),
new ConcreteComposite(),
]);

$this->assertEquals(['Default'], $constraint->groups);
$this->assertEquals(['Default'], $constraint->constraints[0]->groups);
$this->assertEquals(['Default'], $constraint->constraints[1]->groups);
}

public function testMergeNestedGroupsIfNoExplicitParentGroup()
{
$constraint = new ConcreteComposite([
Expand Down
13 changes: 13 additions & 0 deletions Tests/Fixtures/AbstractPropertyGetter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

abstract class AbstractPropertyGetter implements PropertyGetterInterface
{
private $property;

public function getProperty()
{
return $this->property;
}
}
7 changes: 7 additions & 0 deletions Tests/Fixtures/ChildGetterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

interface ChildGetterInterface extends PropertyGetterInterface
{
}
12 changes: 12 additions & 0 deletions Tests/Fixtures/PropertyGetter.php
Original file line number Diff line number Diff line change
@@ -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
{
}
8 changes: 8 additions & 0 deletions Tests/Fixtures/PropertyGetterInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Symfony\Component\Validator\Tests\Fixtures;

interface PropertyGetterInterface
{
public function getProperty();
}
25 changes: 24 additions & 1 deletion Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
use Psr\Cache\CacheItemPoolInterface;
use Symfony\Component\Cache\Adapter\ArrayAdapter;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Constraints\NotBlank;
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 @@ -150,6 +152,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 @@ -161,3 +172,15 @@ public function loadClassMetadata(ClassMetadata $metadata): bool
return true;
}
}

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

return true;
}
}

0 comments on commit d01fd93

Please sign in to comment.