Bläddra i källkod

[Validator] Added support for static callbacks to Callback constraint

Bernhard Schussek 14 år sedan
förälder
incheckning
3e29348d21

+ 19 - 5
src/Symfony/Component/Validator/Constraints/CallbackValidator.php

@@ -29,7 +29,13 @@ class CallbackValidator extends ConstraintValidator
             return true;
         }
 
-        $methods = (array)$constraint->methods;
+        // has to be an array so that we can differentiate between callables
+        // and method names
+        if (!is_array($constraint->methods)) {
+            throw new UnexpectedTypeException($constraint->methods, 'array');
+        }
+
+        $methods = $constraint->methods;
         $context = $this->context;
 
         // save context state
@@ -39,11 +45,19 @@ class CallbackValidator extends ConstraintValidator
         $propertyPath = $context->getPropertyPath();
 
         foreach ($methods as $method) {
-            if (!method_exists($object, $method)) {
-                throw new ConstraintDefinitionException(sprintf('Method "%s" targeted by Callback constraint does not exist', $method));
-            }
+            if (is_array($method)) {
+                if (!is_callable($method)) {
+                    throw new ConstraintDefinitionException(sprintf('"%s::%s" targeted by Callback constraint is not a valid callable', $method[0], $method[1]));
+                }
 
-            $object->$method($context);
+                call_user_func($method, $object, $context);
+            } else {
+                if (!method_exists($object, $method)) {
+                    throw new ConstraintDefinitionException(sprintf('Method "%s" targeted by Callback constraint does not exist', $method));
+                }
+
+                $object->$method($context);
+            }
 
             // restore context state
             $context->setCurrentClass($currentClass);

+ 69 - 2
tests/Symfony/Tests/Component/Validator/Constraints/CallbackValidatorTest.php

@@ -17,6 +17,19 @@ use Symfony\Component\Validator\ConstraintViolationList;
 use Symfony\Component\Validator\Constraints\Callback;
 use Symfony\Component\Validator\Constraints\CallbackValidator;
 
+class CallbackValidatorTest_Class
+{
+    public static function validateStatic($object, ExecutionContext $context)
+    {
+        $context->setCurrentClass('Foo');
+        $context->setCurrentProperty('bar');
+        $context->setGroup('mygroup');
+        $context->setPropertyPath('foo.bar');
+
+        $context->addViolation('Static message', array('parameter'), 'invalidValue');
+    }
+}
+
 class CallbackValidatorTest_Object
 {
     public function validateOne(ExecutionContext $context)
@@ -58,14 +71,14 @@ class CallbackValidatorTest extends \PHPUnit_Framework_TestCase
 
     public function testNullIsValid()
     {
-        $this->assertTrue($this->validator->isValid(null, new Callback('foo')));
+        $this->assertTrue($this->validator->isValid(null, new Callback(array('foo'))));
     }
 
     public function testCallbackSingleMethod()
     {
         $object = new CallbackValidatorTest_Object();
 
-        $this->assertTrue($this->validator->isValid($object, new Callback('validateOne')));
+        $this->assertTrue($this->validator->isValid($object, new Callback(array('validateOne'))));
 
         $violations = new ConstraintViolationList();
         $violations->add(new ConstraintViolation(
@@ -83,6 +96,30 @@ class CallbackValidatorTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals('initial.property.path', $this->context->getPropertyPath());
     }
 
+    public function testCallbackSingleStaticMethod()
+    {
+        $object = new CallbackValidatorTest_Object();
+
+        $this->assertTrue($this->validator->isValid($object, new Callback(array(
+            array(__NAMESPACE__.'\CallbackValidatorTest_Class', 'validateStatic')
+        ))));
+
+        $violations = new ConstraintViolationList();
+        $violations->add(new ConstraintViolation(
+            'Static message',
+            array('parameter'),
+            'Root',
+            'foo.bar',
+            'invalidValue'
+        ));
+
+        $this->assertEquals($violations, $this->context->getViolations());
+        $this->assertEquals('InitialClass', $this->context->getCurrentClass());
+        $this->assertEquals('initialProperty', $this->context->getCurrentProperty());
+        $this->assertEquals('InitialGroup', $this->context->getGroup());
+        $this->assertEquals('initial.property.path', $this->context->getPropertyPath());
+    }
+
     public function testCallbackMultipleMethods()
     {
         $object = new CallbackValidatorTest_Object();
@@ -111,4 +148,34 @@ class CallbackValidatorTest extends \PHPUnit_Framework_TestCase
 
         $this->assertEquals($violations, $this->context->getViolations());
     }
+
+    /**
+     * @expectedException Symfony\Component\Validator\Exception\UnexpectedTypeException
+     */
+    public function testExpectCallbackArray()
+    {
+        $object = new CallbackValidatorTest_Object();
+
+        $this->validator->isValid($object, new Callback('foobar'));
+    }
+
+    /**
+     * @expectedException Symfony\Component\Validator\Exception\ConstraintDefinitionException
+     */
+    public function testExpectValidMethods()
+    {
+        $object = new CallbackValidatorTest_Object();
+
+        $this->validator->isValid($object, new Callback(array('foobar')));
+    }
+
+    /**
+     * @expectedException Symfony\Component\Validator\Exception\ConstraintDefinitionException
+     */
+    public function testExpectValidCallbacks()
+    {
+        $object = new CallbackValidatorTest_Object();
+
+        $this->validator->isValid($object, new Callback(array(array('foo', 'bar'))));
+    }
 }