Browse Source

Merge pull request #5813 from cakephp/validation-compare

Add compareWith validation method.
José Lorenzo Rodríguez 11 years ago
parent
commit
0f3ea4b39e

+ 25 - 8
src/Validation/RulesProvider.php

@@ -14,21 +14,29 @@
  */
 namespace Cake\Validation;
 
+use ReflectionClass;
+
 /**
  * A Proxy class used to remove any extra arguments when the user intended to call
  * a method in another class that is not aware of validation providers signature
  */
 class RulesProvider
 {
-
     /**
-     * The class to proxy, defaults to \Cake\Validation\Validation in construction
+     * The class/object to proxy.
      *
-     * @var object
+     * @var mixed
      */
     protected $_class;
 
     /**
+     * The proxied class' reflection
+     *
+     * @var \ReflectionClass
+     */
+    protected $_reflection;
+
+    /**
      * Constructor, sets the default class to use for calling methods
      *
      * @param string $class the default class to proxy
@@ -36,12 +44,16 @@ class RulesProvider
     public function __construct($class = '\Cake\Validation\Validation')
     {
         $this->_class = $class;
+        $this->_reflection = new ReflectionClass($class);
     }
 
     /**
-     * Proxies validation method calls to the Validation class, it slices
-     * the arguments array to avoid passing more arguments than required to
-     * the validation methods.
+     * Proxies validation method calls to the Validation class.
+     *
+     * The last argument (context) will be sliced off, if the validation
+     * method's last parameter is not named 'context'. This lets
+     * the various wrapped validation methods to not receive the validation
+     * context unless they need it.
      *
      * @param string $method the validation method to call
      * @param array $arguments the list of arguments to pass to the method
@@ -49,7 +61,12 @@ class RulesProvider
      */
     public function __call($method, $arguments)
     {
-        $arguments = array_slice($arguments, 0, -1);
-        return call_user_func_array([$this->_class, $method], $arguments);
+        $method = $this->_reflection->getMethod($method);
+        $argumentList = $method->getParameters();
+        if (array_pop($argumentList)->getName() !== 'context') {
+            $arguments = array_slice($arguments, 0, -1);
+        }
+        $object = is_string($this->_class) ? null : $this->_class;
+        return $method->invokeArgs($object, $arguments);
     }
 }

+ 18 - 0
src/Validation/Validation.php

@@ -260,6 +260,24 @@ class Validation
     }
 
     /**
+     * Compare one field to another.
+     *
+     * If both fields have exactly the same value this method will return true.
+     *
+     * @param mixed $check The value to find in $field.
+     * @param string $field The field to check $check against. This field must be present in $context.
+     * @param array $context The validation context.
+     * @return bool
+     */
+    public static function compareWith($check, $field, $context)
+    {
+        if (!isset($context['data'][$field])) {
+            return false;
+        }
+        return $context['data'][$field] === $check;
+    }
+
+    /**
      * Used when a custom regular expression is needed.
      *
      * @param string|array $check When used as a string, $regex must also be a valid regular expression.

+ 1 - 1
tests/TestCase/Validation/RulesProviderTest.php

@@ -48,7 +48,7 @@ class RulesProviderTest extends TestCase
     {
         $mock = $this->getMock('\Cake\Validation\Validator', ['field']);
         $mock->expects($this->once())
-            ->method('Field')
+            ->method('field')
             ->with('first', null)
             ->will($this->returnValue(true));
 

+ 25 - 0
tests/TestCase/Validation/ValidationTest.php

@@ -2511,4 +2511,29 @@ class ValidationTest extends TestCase
         $options = [];
         $this->assertTrue(Validation::uploadedFile($file, $options), 'Wrong order');
     }
+
+    /**
+     * Test the compareWith method.
+     *
+     * @return void
+     */
+    public function testCompareWith()
+    {
+        $context = [
+            'data' => [
+                'other' => 'a value'
+            ]
+        ];
+        $this->assertTrue(Validation::compareWith('a value', 'other', $context));
+
+        $context = [
+            'data' => [
+                'other' => 'different'
+            ]
+        ];
+        $this->assertFalse(Validation::compareWith('a value', 'other', $context));
+
+        $context = [];
+        $this->assertFalse(Validation::compareWith('a value', 'other', $context));
+    }
 }

+ 20 - 0
tests/TestCase/Validation/ValidatorTest.php

@@ -749,4 +749,24 @@ class ValidatorTest extends TestCase
         $this->assertInstanceOf('Cake\Validation\ValidationSet', $set);
         $this->assertCount(2, $set);
     }
+
+    /**
+     * Integration test for compareWith validator.
+     *
+     * @return void
+     */
+    public function testCompareWithIntegration()
+    {
+        $validator = new Validator;
+        $validator->add('password', [
+            'compare' => [
+                'rule' => ['compareWith', 'password_compare']
+            ],
+        ]);
+        $data = [
+            'password' => 'test',
+            'password_compare' => 'not the same'
+        ];
+        $this->assertNotEmpty($validator->errors($data), 'Validation should fail.');
+    }
 }