Browse Source

Merge pull request #8726 from cakephp/validate-numelements

Added Validator::atLeast and atMost
José Lorenzo Rodríguez 10 years ago
parent
commit
59b9f4cc86

+ 18 - 0
src/Validation/Validation.php

@@ -216,6 +216,24 @@ class Validation
     }
 
     /**
+     * Used to check the count of a given value of type array or Countable.
+     *
+     * @param array|\Countable $check The value to check the count on.
+     * @param string $operator Can be either a word or operand
+     *    is greater >, is less <, greater or equal >=
+     *    less or equal <=, is less <, equal to ==, not equal !=
+     * @param int $expectedCount The expected count value.
+     * @return bool Success
+     */
+    public static function numElements($check, $operator, $expectedCount)
+    {
+        if (!is_array($check) && !$check instanceof \Countable) {
+            return false;
+        }
+        return self::comparison(count($check), $operator, $expectedCount);
+    }
+
+    /**
      * Used to compare 2 numeric values.
      *
      * @param string $check1 if string is passed for, a string must also be passed for $check2

+ 50 - 0
src/Validation/Validator.php

@@ -1320,6 +1320,56 @@ class Validator implements ArrayAccess, IteratorAggregate, Countable
     }
 
     /**
+     * Add a validation rule to ensure that a field is an array containing at least
+     * the specified amount of elements
+     *
+     * @param string $field The field you want to apply the rule to.
+     * @param int $count The number of elements the array should at least have
+     * @param string|null $message The error message when the rule fails.
+     * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
+     *   true when the validation rule should be applied.
+     * @see \Cake\Validation\Validation::numElements()
+     * @return $this
+     */
+    public function hasAtLeast($field, $count, $message = null, $when = null)
+    {
+        $extra = array_filter(['on' => $when, 'message' => $message]);
+        return $this->add($field, 'hasAtLeast', $extra + [
+            'rule' => function ($value) use ($count) {
+                if (is_array($value) && isset($value['_ids'])) {
+                    $value = $value['_ids'];
+                }
+                return Validation::numElements($value, '>=', $count);
+            }
+        ]);
+    }
+
+    /**
+     * Add a validation rule to ensure that a field is an array containing at most
+     * the specified amount of elements
+     *
+     * @param string $field The field you want to apply the rule to.
+     * @param int $count The number maximim amount of elements the field should have
+     * @param string|null $message The error message when the rule fails.
+     * @param string|callable|null $when Either 'create' or 'update' or a callable that returns
+     *   true when the validation rule should be applied.
+     * @see \Cake\Validation\Validation::numElements()
+     * @return $this
+     */
+    public function hasAtMost($field, $count, $message = null, $when = null)
+    {
+        $extra = array_filter(['on' => $when, 'message' => $message]);
+        return $this->add($field, 'hasAtMost', $extra + [
+            'rule' => function ($value) use ($count) {
+                if (is_array($value) && isset($value['_ids'])) {
+                    $value = $value['_ids'];
+                }
+                return Validation::numElements($value, '<=', $count);
+            }
+        ]);
+    }
+
+    /**
      * Returns whether or not a field can be left empty for a new or already existing
      * record.
      *

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

@@ -2768,4 +2768,27 @@ class ValidationTest extends TestCase
         // Grinning face
         $this->assertTrue(Validation::utf8('some' . "\xf0\x9f\x98\x80" . 'value', ['extended' => true]));
     }
+
+    /**
+     * Test numElements
+     *
+     * @return void
+     */
+    public function testNumElements()
+    {
+        $array = ['cake', 'php'];
+        $this->assertTrue(Validation::numElements($array, '==', 2));
+        $this->assertFalse(Validation::numElements($array, '>', 3));
+        $this->assertFalse(Validation::numElements($array, '<', 1));
+
+        $callable = function () {
+            return '';
+        };
+
+        $this->assertFalse(Validation::numElements(null, '==', 0));
+        $this->assertFalse(Validation::numElements(new \stdClass(), '==', 0));
+        $this->assertFalse(Validation::numElements($callable, '==', 0));
+        $this->assertFalse(Validation::numElements(false, '==', 0));
+        $this->assertFalse(Validation::numElements(true, '==', 0));
+    }
 }

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

@@ -1545,6 +1545,46 @@ class ValidatorTest extends TestCase
         $this->assertNotEmpty($validator->errors(['username' => '']));
     }
 
+    /**
+     * Tests the hasAtLeast method
+     *
+     * @return void
+     */
+    public function testHasAtLeast()
+    {
+        $validator = new Validator();
+        $validator->hasAtLeast('things', 3);
+        $this->assertEmpty($validator->errors(['things' => [1, 2, 3]]));
+        $this->assertEmpty($validator->errors(['things' => [1, 2, 3, 4]]));
+        $this->assertNotEmpty($validator->errors(['things' => [1, 2]]));
+        $this->assertNotEmpty($validator->errors(['things' => []]));
+        $this->assertNotEmpty($validator->errors(['things' => 'string']));
+
+        $this->assertEmpty($validator->errors(['things' => ['_ids' => [1, 2, 3]]]));
+        $this->assertEmpty($validator->errors(['things' => ['_ids' => [1, 2, 3, 4]]]));
+        $this->assertNotEmpty($validator->errors(['things' => ['_ids' => [1, 2]]]));
+        $this->assertNotEmpty($validator->errors(['things' => ['_ids' => []]]));
+        $this->assertNotEmpty($validator->errors(['things' => ['_ids' => 'string']]));
+    }
+
+    /**
+     * Tests the hasAtMost method
+     *
+     * @return void
+     */
+    public function testHasAtMost()
+    {
+        $validator = new Validator();
+        $validator->hasAtMost('things', 3);
+        $this->assertEmpty($validator->errors(['things' => [1, 2, 3]]));
+        $this->assertEmpty($validator->errors(['things' => [1]]));
+        $this->assertNotEmpty($validator->errors(['things' => [1, 2, 3, 4]]));
+
+        $this->assertEmpty($validator->errors(['things' => ['_ids' => [1, 2, 3]]]));
+        $this->assertEmpty($validator->errors(['things' => ['_ids' => [1, 2]]]));
+        $this->assertNotEmpty($validator->errors(['things' => ['_ids' => [1, 2, 3, 4]]]));
+    }
+
     protected function assertProxyMethod($validator, $method, $extra = null, $pass = [], $name = null)
     {
         $name = $name ?: $method;