Skip to content

Commit

Permalink
Refactor Validator::decimal() to be more flexible with decimal
Browse files Browse the repository at this point in the history
separators and PHP magic.
Lots of testing added.
  • Loading branch information
bar committed Aug 28, 2012
1 parent 7135ff2 commit 6354826
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 35 deletions.
108 changes: 85 additions & 23 deletions lib/Cake/Test/Case/Utility/ValidationTest.php
Expand Up @@ -1487,39 +1487,77 @@ public function testDateCustomRegx() {
}

/**
* testDecimal method
* Test numbers with any number of decimal places, including none.
*
* @return void
*/
public function testDecimal() {
$this->assertTrue(Validation::decimal('+1234.54321'));
$this->assertTrue(Validation::decimal('-1234.54321'));
$this->assertTrue(Validation::decimal('1234.54321'));
$this->assertTrue(Validation::decimal('+0123.45e6'));
$this->assertTrue(Validation::decimal('-0123.45e6'));
$this->assertTrue(Validation::decimal('0123.45e6'));
$this->assertTrue(Validation::decimal(1234.56));
$this->assertTrue(Validation::decimal(1234.00));
$this->assertTrue(Validation::decimal('1234.00'));
$this->assertTrue(Validation::decimal(.0));
$this->assertTrue(Validation::decimal(.00));
$this->assertTrue(Validation::decimal('.00'));
$this->assertTrue(Validation::decimal(.01));
$this->assertTrue(Validation::decimal('.01'));
public function testDecimalWithPlacesNull() {
$this->assertTrue(Validation::decimal('+1234.54321', null));
$this->assertTrue(Validation::decimal('-1234.54321', null));
$this->assertTrue(Validation::decimal('1234.54321', null));
$this->assertTrue(Validation::decimal('+0123.45e6', null));
$this->assertTrue(Validation::decimal('-0123.45e6', null));
$this->assertTrue(Validation::decimal('0123.45e6', null));
$this->assertTrue(Validation::decimal(1234.56, null));
$this->assertTrue(Validation::decimal(1234.00, null));
$this->assertTrue(Validation::decimal(1234., null));
$this->assertTrue(Validation::decimal('1234.00', null));
$this->assertTrue(Validation::decimal(.0, null));
$this->assertTrue(Validation::decimal(.00, null));
$this->assertTrue(Validation::decimal('.00', null));
$this->assertTrue(Validation::decimal(.01, null));
$this->assertTrue(Validation::decimal('.01', null));
$this->assertTrue(Validation::decimal('1234', null));
$this->assertTrue(Validation::decimal('-1234', null));
$this->assertTrue(Validation::decimal('+1234', null));
$this->assertTrue(Validation::decimal((float) 1234, null));
$this->assertTrue(Validation::decimal((double) 1234, null));
$this->assertTrue(Validation::decimal((int) 1234, null));

$this->assertFalse(Validation::decimal(''));
$this->assertFalse(Validation::decimal('string'));
$this->assertFalse(Validation::decimal('1234'));
$this->assertFalse(Validation::decimal('-1234'));
$this->assertFalse(Validation::decimal('+1234'));
$this->assertFalse(Validation::decimal('', null));
$this->assertFalse(Validation::decimal('string', null));
$this->assertFalse(Validation::decimal('1234.', null));
}

/**
* testDecimalWithPlaces method
* Test numbers with any number of decimal places greater than 0, or a float|double.
*
* @return void
*/
public function testDecimalWithPlaces() {
public function testDecimalWithPlacesTrue() {
$this->assertTrue(Validation::decimal('+1234.54321', true));
$this->assertTrue(Validation::decimal('-1234.54321', true));
$this->assertTrue(Validation::decimal('1234.54321', true));
$this->assertTrue(Validation::decimal('+0123.45e6', true));
$this->assertTrue(Validation::decimal('-0123.45e6', true));
$this->assertTrue(Validation::decimal('0123.45e6', true));
$this->assertTrue(Validation::decimal(1234.56, true));
$this->assertTrue(Validation::decimal(1234.00, true));
$this->assertTrue(Validation::decimal(1234., true));
$this->assertTrue(Validation::decimal('1234.00', true));
$this->assertTrue(Validation::decimal(.0, true));
$this->assertTrue(Validation::decimal(.00, true));
$this->assertTrue(Validation::decimal('.00', true));
$this->assertTrue(Validation::decimal(.01, true));
$this->assertTrue(Validation::decimal('.01', true));
$this->assertTrue(Validation::decimal((float) 1234, true));
$this->assertTrue(Validation::decimal((double) 1234, true));

$this->assertFalse(Validation::decimal('', true));
$this->assertFalse(Validation::decimal('string', true));
$this->assertFalse(Validation::decimal('1234.', true));
$this->assertFalse(Validation::decimal((int) 1234, true));
$this->assertFalse(Validation::decimal('1234', true));
$this->assertFalse(Validation::decimal('-1234', true));
$this->assertFalse(Validation::decimal('+1234', true));
}

/**
* Test numbers with exactly that many number of decimal places.
*
* @return void
*/
public function testDecimalWithPlacesNumeric() {
$this->assertTrue(Validation::decimal('.27', '2'));
$this->assertTrue(Validation::decimal(0.27, 2));
$this->assertTrue(Validation::decimal(-0.27, 2));
Expand All @@ -1532,12 +1570,36 @@ public function testDecimalWithPlaces() {
$this->assertTrue(Validation::decimal(1234.5678, 4));
$this->assertTrue(Validation::decimal(-1234.5678, 4));
$this->assertTrue(Validation::decimal(1234.5678, 4));
$this->assertTrue(Validation::decimal('.00', 2));
$this->assertTrue(Validation::decimal(.01, 2));
$this->assertTrue(Validation::decimal('.01', 2));

$this->assertFalse(Validation::decimal('', 1));
$this->assertFalse(Validation::decimal('string', 1));
$this->assertFalse(Validation::decimal(1234., 1));
$this->assertFalse(Validation::decimal('1234.', 1));
$this->assertFalse(Validation::decimal(.0, 1));
$this->assertFalse(Validation::decimal(.00, 2));
$this->assertFalse(Validation::decimal((float) 1234, 1));
$this->assertFalse(Validation::decimal((double) 1234, 1));
$this->assertFalse(Validation::decimal((int) 1234, 1));
$this->assertFalse(Validation::decimal('1234.5678', '3'));
$this->assertFalse(Validation::decimal(1234.5678, 3));
$this->assertFalse(Validation::decimal(-1234.5678, 3));
$this->assertFalse(Validation::decimal(1234.5678, 3));
}

/**
* Test decimal() with invalid places parameter.
*
* @return void
*/
public function testDecimalWithInvalidPlaces() {
$this->assertFalse(Validation::decimal('.27', 'string'));
$this->assertFalse(Validation::decimal(1234.5678, (array) true));
$this->assertFalse(Validation::decimal(-1234.5678, (object) true));
}

/**
* testDecimalCustomRegex method
*
Expand Down
40 changes: 28 additions & 12 deletions lib/Cake/Utility/Validation.php
Expand Up @@ -372,23 +372,39 @@ public static function boolean($check) {
}

/**
* Checks that a value is a valid decimal. If $places is null, the $check is allowed to be a scientific float
* If no decimal point is found a false will be returned. Both the sign and exponent are optional.
* Checks that a value is a valid decimal. Both the sign and exponent are optional.
*
* Valid Places:
*
* - null => Any number of decimal places, including none. The '.' is not required.
* - true => Any number of decimal places greater than 0, or a float|double. The '.' is required.
* - 1..N => Exactly that many number of decimal places. The '.' is required.
*
* @param integer $check The value the test for decimal
* @param integer $places if set $check value must have exactly $places after the decimal point
* @param string $regex If a custom regular expression is used this is the only validation that will occur.
* @param integer $places
* @param string $regex If a custom regular expression is used, this is the only validation that will occur.
* @return boolean Success
*/
public static function decimal($check, $places = null, $regex = null) {
if (is_float($check) && floor($check) === $check) {
$check = sprintf("%.1f", $check);
}
if (is_null($regex)) {
if (is_null($places)) {
$regex = '/^[-+]?[0-9]*\\.{1}[0-9]+(?:[eE][-+]?[0-9]+)?$/';
} else {
$regex = '/^[-+]?[0-9]*\\.{1}[0-9]{' . $places . '}$/';
$lnum = '[0-9]+';
$dnum = "[0-9]*[\.]{$lnum}";
$sign = '[+-]?';
$exp = "(?:[eE]{$sign}{$lnum})?";

if ($places === null) {
$regex = "/^{$sign}(?:{$lnum}|{$dnum}){$exp}$/";

} elseif ($places === true) {
if (is_float($check) && floor($check) === $check) {
$check = sprintf("%.1f", $check);
}
$regex = "/^{$sign}{$dnum}{$exp}$/";

} elseif (is_numeric($places)) {
$places = '[0-9]{' . $places . '}';
$dnum = "(?:[0-9]*[\.]{$places}|{$lnum}[\.]{$places})";
$regex = "/^{$sign}{$dnum}{$exp}$/";
}
}
return self::_check($check, $regex);
Expand Down Expand Up @@ -796,7 +812,7 @@ protected static function _pass($method, $check, $classPrefix) {
* @return boolean Success of match
*/
protected static function _check($check, $regex) {
if (preg_match($regex, $check)) {
if (is_string($regex) && preg_match($regex, $check)) {
self::$errors[] = false;
return true;
} else {
Expand Down

0 comments on commit 6354826

Please sign in to comment.