Skip to content

Commit

Permalink
[Validator] Fixed calling getters before resolving groups
Browse files Browse the repository at this point in the history
  • Loading branch information
HeahDude committed Mar 28, 2020
1 parent a562ba2 commit edcfd60
Show file tree
Hide file tree
Showing 5 changed files with 103 additions and 3 deletions.
9 changes: 7 additions & 2 deletions src/Symfony/Component/Validator/Context/ExecutionContext.php
Expand Up @@ -20,6 +20,7 @@
use Symfony\Component\Validator\Mapping\MetadataInterface;
use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
use Symfony\Component\Validator\Util\PropertyPath;
use Symfony\Component\Validator\Validator\LazyProperty;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Symfony\Component\Validator\Violation\ConstraintViolationBuilder;

Expand Down Expand Up @@ -187,7 +188,7 @@ public function addViolation($message, array $parameters = [])
$parameters,
$this->root,
$this->propertyPath,
$this->value,
$this->getValue(),
null,
null,
$this->constraint
Expand All @@ -206,7 +207,7 @@ public function buildViolation($message, array $parameters = [])
$parameters,
$this->root,
$this->propertyPath,
$this->value,
$this->getValue(),
$this->translator,
$this->translationDomain
);
Expand Down Expand Up @@ -241,6 +242,10 @@ public function getRoot()
*/
public function getValue()
{
if ($this->value instanceof LazyProperty) {
return $this->value->getPropertyValue();
}

return $this->value;
}

Expand Down
@@ -0,0 +1,27 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* 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;

class EntityWithGroupedConstraintOnMethods
{
public $bar;

public function isValidInFoo()
{
return false;
}

public function getBar()
{
throw new \Exception('Should not be called');
}
}
Expand Up @@ -14,14 +14,19 @@
use Symfony\Component\Translation\IdentityTranslator;
use Symfony\Component\Validator\Constraints\All;
use Symfony\Component\Validator\Constraints\Collection;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\IsTrue;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
use Symfony\Component\Validator\Constraints\NotNull;
use Symfony\Component\Validator\ConstraintValidatorFactory;
use Symfony\Component\Validator\Context\ExecutionContextFactory;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildA;
use Symfony\Component\Validator\Tests\Constraints\Fixtures\ChildB;
use Symfony\Component\Validator\Tests\Fixtures\Entity;
use Symfony\Component\Validator\Tests\Fixtures\EntityWithGroupedConstraintOnMethods;
use Symfony\Component\Validator\Validator\RecursiveValidator;

class RecursiveValidatorTest extends AbstractTest
Expand Down Expand Up @@ -117,6 +122,25 @@ public function testCollectionConstraintValidateAllGroupsForNestedConstraints()
$this->assertInstanceOf(NotBlank::class, $violations->get(1)->getConstraint());
}

public function testGroupedMethodConstraintValidateInSequence()
{
$metadata = new ClassMetadata(EntityWithGroupedConstraintOnMethods::class);
$metadata->addPropertyConstraint('bar', new NotNull(['groups' => 'Foo']));
$metadata->addGetterMethodConstraint('validInFoo', 'isValidInFoo', new IsTrue(['groups' => 'Foo']));
$metadata->addGetterMethodConstraint('bar', 'getBar', new NotNull(['groups' => 'Bar']));

$this->metadataFactory->addMetadata($metadata);

$entity = new EntityWithGroupedConstraintOnMethods();
$groups = new GroupSequence(['EntityWithGroupedConstraintOnMethods', 'Foo', 'Bar']);

$violations = $this->validator->validate($entity, null, $groups);

$this->assertCount(2, $violations);
$this->assertInstanceOf(NotNull::class, $violations->get(0)->getConstraint());
$this->assertInstanceOf(IsTrue::class, $violations->get(1)->getConstraint());
}

public function testAllConstraintValidateAllGroupsForNestedConstraints()
{
$this->metadata->addPropertyConstraint('data', new All(['constraints' => [
Expand Down
32 changes: 32 additions & 0 deletions src/Symfony/Component/Validator/Validator/LazyProperty.php
@@ -0,0 +1,32 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Validator\Validator;

/**
* A wrapper for a callable initializing a property from a getter.
*
* @internal
*/
class LazyProperty
{
private $propertyValueCallback;

public function __construct(\Closure $propertyValueCallback)
{
$this->propertyValueCallback = $propertyValueCallback;
}

public function getPropertyValue()
{
return \call_user_func($this->propertyValueCallback);
}
}
Expand Up @@ -26,6 +26,7 @@
use Symfony\Component\Validator\Mapping\ClassMetadataInterface;
use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface;
use Symfony\Component\Validator\Mapping\GenericMetadata;
use Symfony\Component\Validator\Mapping\GetterMetadata;
use Symfony\Component\Validator\Mapping\MetadataInterface;
use Symfony\Component\Validator\Mapping\PropertyMetadataInterface;
use Symfony\Component\Validator\Mapping\TraversalStrategy;
Expand Down Expand Up @@ -534,7 +535,13 @@ private function validateClassNode($object, $cacheKey, ClassMetadataInterface $m
throw new UnsupportedMetadataException(sprintf('The property metadata instances should implement "Symfony\Component\Validator\Mapping\PropertyMetadataInterface", got: "%s".', \is_object($propertyMetadata) ? \get_class($propertyMetadata) : \gettype($propertyMetadata)));
}

$propertyValue = $propertyMetadata->getPropertyValue($object);
if ($propertyMetadata instanceof GetterMetadata) {
$propertyValue = new LazyProperty(static function () use ($propertyMetadata, $object) {
return $propertyMetadata->getPropertyValue($object);
});
} else {
$propertyValue = $propertyMetadata->getPropertyValue($object);
}

$this->validateGenericNode(
$propertyValue,
Expand Down Expand Up @@ -798,6 +805,11 @@ private function validateInGroup($value, $cacheKey, MetadataInterface $metadata,

$validator = $this->validatorFactory->getInstance($constraint);
$validator->initialize($context);

if ($value instanceof LazyProperty) {
$value = $value->getPropertyValue();
}

$validator->validate($value, $constraint);
}
}
Expand Down

0 comments on commit edcfd60

Please sign in to comment.