diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php index a079454c70519..7fda47f5e4dcf 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php @@ -299,8 +299,9 @@ public function addPropertyConstraints($property, array $constraints) * The name of the getter is assumed to be the name of the property with an * uppercased first letter and either the prefix "get" or "is". * - * @param string $property The name of the property - * @param Constraint $constraint The constraint + * @param string $property The name of the property + * @param Constraint $constraint The constraint + * @param string|null $method The method that is called to retrieve the value being validated (null for auto-detection) * * @return $this */ @@ -319,6 +320,30 @@ public function addGetterConstraint($property, Constraint $constraint) return $this; } + /** + * Adds a constraint to the getter of the given property. + * + * @param string $property The name of the property + * @param string $method The name of the getter method + * @param Constraint $constraint The constraint + * + * @return $this + */ + public function addGetterMethodConstraint($property, $method, Constraint $constraint) + { + if (!isset($this->getters[$property])) { + $this->getters[$property] = new GetterMetadata($this->getClassName(), $property, $method); + + $this->addPropertyMetadata($this->getters[$property]); + } + + $constraint->addImplicitGroupName($this->getDefaultGroup()); + + $this->getters[$property]->addConstraint($constraint); + + return $this; + } + /** * @param string $property * @param Constraint[] $constraints @@ -334,6 +359,22 @@ public function addGetterConstraints($property, array $constraints) return $this; } + /** + * @param string $property + * @param string $method + * @param Constraint[] $constraints + * + * @return $this + */ + public function addGetterMethodConstraints($property, $method, array $constraints) + { + foreach ($constraints as $constraint) { + $this->addGetterMethodConstraint($property, $method, $constraint); + } + + return $this; + } + /** * Merges the constraints of the given metadata into this object. * diff --git a/src/Symfony/Component/Validator/Mapping/GetterMetadata.php b/src/Symfony/Component/Validator/Mapping/GetterMetadata.php index 0cf99927695ba..cd42c4338cbb5 100644 --- a/src/Symfony/Component/Validator/Mapping/GetterMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/GetterMetadata.php @@ -35,25 +35,30 @@ class GetterMetadata extends MemberMetadata /** * Constructor. * - * @param string $class The class the getter is defined on - * @param string $property The property which the getter returns + * @param string $class The class the getter is defined on + * @param string $property The property which the getter returns + * @param string|null $method The method that is called to retrieve the value being validated (null for auto-detection) * * @throws ValidatorException */ - public function __construct($class, $property) + public function __construct($class, $property, $method = null) { - $getMethod = 'get'.ucfirst($property); - $isMethod = 'is'.ucfirst($property); - $hasMethod = 'has'.ucfirst($property); + if (null === $method) { + $getMethod = 'get'.ucfirst($property); + $isMethod = 'is'.ucfirst($property); + $hasMethod = 'has'.ucfirst($property); - if (method_exists($class, $getMethod)) { - $method = $getMethod; - } elseif (method_exists($class, $isMethod)) { - $method = $isMethod; - } elseif (method_exists($class, $hasMethod)) { - $method = $hasMethod; - } else { - throw new ValidatorException(sprintf('Neither of these methods exist in class %s: %s, %s, %s', $class, $getMethod, $isMethod, $hasMethod)); + if (method_exists($class, $getMethod)) { + $method = $getMethod; + } elseif (method_exists($class, $isMethod)) { + $method = $isMethod; + } elseif (method_exists($class, $hasMethod)) { + $method = $hasMethod; + } else { + throw new ValidatorException(sprintf('Neither of these methods exist in class %s: %s, %s, %s', $class, $getMethod, $isMethod, $hasMethod)); + } + } elseif (!method_exists($class, $method)) { + throw new ValidatorException(sprintf('The %s() method does not exist in class %s.', $method, $class)); } parent::__construct($class, $method, $property); diff --git a/src/Symfony/Component/Validator/Mapping/Loader/AnnotationLoader.php b/src/Symfony/Component/Validator/Mapping/Loader/AnnotationLoader.php index d1b8c35b36891..a3b5f7ee8e973 100644 --- a/src/Symfony/Component/Validator/Mapping/Loader/AnnotationLoader.php +++ b/src/Symfony/Component/Validator/Mapping/Loader/AnnotationLoader.php @@ -79,7 +79,7 @@ public function loadClassMetadata(ClassMetadata $metadata) $metadata->addConstraint($constraint); } elseif ($constraint instanceof Constraint) { if (preg_match('/^(get|is|has)(.+)$/i', $method->name, $matches)) { - $metadata->addGetterConstraint(lcfirst($matches[2]), $constraint); + $metadata->addGetterMethodConstraint(lcfirst($matches[2]), $matches[0], $constraint); } else { throw new MappingException(sprintf('The constraint on "%s::%s" cannot be added. Constraints can only be added on methods beginning with "get", "is" or "has".', $className, $method->name)); } diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php b/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php index 77a86108a1ae0..e30619103d906 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/Entity.php @@ -63,6 +63,10 @@ public function getLastName() return $this->lastName; } + public function getValid() + { + } + /** * @Assert\IsTrue */ diff --git a/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php index 078159971af83..8c1236d305e70 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/GetterMetadataTest.php @@ -47,7 +47,7 @@ public function testGetPropertyValueFromOverriddenPublicGetter() public function testGetPropertyValueFromIsser() { $entity = new Entity(); - $metadata = new GetterMetadata(self::CLASSNAME, 'valid'); + $metadata = new GetterMetadata(self::CLASSNAME, 'valid', 'isValid'); $this->assertEquals('valid', $metadata->getPropertyValue($entity)); } @@ -59,4 +59,13 @@ public function testGetPropertyValueFromHasser() $this->assertEquals('permissions', $metadata->getPropertyValue($entity)); } + + /** + * @expectedException \Symfony\Component\Validator\Exception\ValidatorException + * @expectedExceptionMessage The hasLastName() method does not exist in class Symfony\Component\Validator\Tests\Fixtures\Entity. + */ + public function testUndefinedMethodNameThrowsException() + { + new GetterMetadata(self::CLASSNAME, 'lastName', 'hasLastName'); + } } diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php index 0e2ad41d697a0..16cca09efb93d 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/AnnotationLoaderTest.php @@ -68,7 +68,7 @@ public function testLoadClassMetadata() 'choices' => array('A', 'B'), ))); $expected->addGetterConstraint('lastName', new NotNull()); - $expected->addGetterConstraint('valid', new IsTrue()); + $expected->addGetterMethodConstraint('valid', 'isValid', new IsTrue()); $expected->addGetterConstraint('permissions', new IsTrue()); // load reflection class so that the comparison passes @@ -138,7 +138,7 @@ public function testLoadClassMetadataAndMerge() 'choices' => array('A', 'B'), ))); $expected->addGetterConstraint('lastName', new NotNull()); - $expected->addGetterConstraint('valid', new IsTrue()); + $expected->addGetterMethodConstraint('valid', 'isValid', new IsTrue()); $expected->addGetterConstraint('permissions', new IsTrue()); // load reflection class so that the comparison passes
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: