diff --git a/src/Symfony/Component/Validator/Context/ExecutionContext.php b/src/Symfony/Component/Validator/Context/ExecutionContext.php index dce975c203..721766a253 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContext.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContext.php @@ -287,6 +287,11 @@ class ExecutionContext implements ExecutionContextInterface return $this->group; } + public function getConstraint() + { + return $this->constraint; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php index 27d5a25ce2..1e6f3403e7 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Validator\Tests\Validator; use Symfony\Component\Validator\Constraints\Callback; +use Symfony\Component\Validator\Constraints\Collection; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Traverse; @@ -720,4 +721,22 @@ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest $this->assertCount(1, $violations); $this->assertSame($constraint, $violations[0]->getConstraint()); } + + public function testCollectionConstraitViolationHasCorrectContext() + { + $data = array( + 'foo' => 'fooValue', + ); + + // Missing field must not be the first in the collection validation + $constraint = new Collection(array( + 'foo' => new NotNull(), + 'bar' => new NotNull(), + )); + + $violations = $this->validate($data, $constraint); + + $this->assertCount(1, $violations); + $this->assertSame($constraint, $violations[0]->getConstraint()); + } } diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index db5d880969..bbd09b8212 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -14,6 +14,7 @@ namespace Symfony\Component\Validator\Validator; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\ConstraintValidatorFactoryInterface; +use Symfony\Component\Validator\Context\ExecutionContext; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; use Symfony\Component\Validator\Exception\NoSuchMetadataException; @@ -110,6 +111,11 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $previousMetadata = $this->context->getMetadata(); $previousPath = $this->context->getPropertyPath(); $previousGroup = $this->context->getGroup(); + $previousConstraint = null; + + if ($this->context instanceof ExecutionContext || method_exists($this->context, 'getConstraint')) { + $previousConstraint = $this->context->getConstraint(); + } // If explicit constraints are passed, validate the value against // those constraints @@ -138,6 +144,10 @@ class RecursiveContextualValidator implements ContextualValidatorInterface $this->context->setNode($previousValue, $previousObject, $previousMetadata, $previousPath); $this->context->setGroup($previousGroup); + if (null !== $previousConstraint) { + $this->context->setConstraint($previousConstraint); + } + return $this; }