diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index 1621f1e67f69..39f8663da167 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -1251,6 +1251,25 @@ public function validateMin($attribute, $value, $parameters) return $this->getSize($attribute, $value) >= $parameters[0]; } + /** + * Validate the value of an attribute is a multiple of a given value. + * + * @param string $attribute + * @param mixed $value + * @param array $parameters + * @return bool + */ + public function validateMultipleOf($attribute, $value, $parameters) + { + $this->requireParameterCount(1, $parameters, 'multiple_of'); + + if (! $this->validateNumeric($attribute, $value) || ! $this->validateNumeric($attribute, $parameters[0])) { + return false; + } + + return fmod($value, $parameters[0]) === 0.0; + } + /** * "Indicate" validation should pass if value is null. * diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index dd017ef44706..d016b0193e7b 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -1847,6 +1847,82 @@ public function testValidateMax() $this->assertFalse($v->passes()); } + /** + * @param mixed $input + * @param mixed $allowed + * @param bool $passes + * + * @dataProvider multipleOfDataProvider + */ + public function testValidateMutlpleOf($input, $allowed, $passes) + { + $trans = $this->getIlluminateArrayTranslator(); + + $v = new Validator($trans, ['foo' => $input], ['foo' => "multiple_of:{$allowed}"]); + $this->assertSame($passes, $v->passes()); + } + + public function multipleOfDataProvider() + { + return [ + [0, 0, false], // zero (same) + [0, 10, true], // zero + integer + [10, 0, false], + [0, 10.1, true], // zero + float + [10.1, 0, false], + [0, -10, true], // zero + -integer + [-10, 0, false], + [0, -10.1, true], // zero + -float + [-10.1, 0, false], + [10, 10, true], // integer (same) + [10, 5, true], // integer + integer + [10, 4, false], + [20, 10, true], + [5, 10, false], + [10, -5, true], // integer + -integer + [10, -4, false], + [-20, 10, true], + [-5, 10, false], + [-10, -10, true], // -integer (same) + [-10, -5, true], // -integer + -integer + [-10, -4, false], + [-20, -10, true], + [-5, -10, false], + [10, 10.0, true], // integer + float (same) + [10, 5.0, true], // integer + float + [10, 4.0, false], + [20.0, 10, true], + [5.0, 10, false], + [10.0, -10.0, true], // integer + -float (same) + [10, -5.0, true], // integer + -float + [10, -4.0, false], + [-20.0, 10, true], + [-5.0, 10, false], + [10.0, -10.0, true], // -integer + float (same) + [-10, 5.0, true], // -integer + float + [-10, 4.0, false], + [20.0, -10, true], + [5.0, -10, false], + [10.5, 10.5, true], // float (same) + [10.5, 0.5, true], // float + float + [10.5, 0.3, false], + [31.5, 10.5, true], + [31.6, 10.5, false], + [10.5, -0.5, true], // float + -float + [10.5, -0.3, false], + [-31.5, 10.5, true], + [-31.6, 10.5, false], + [-10.5, -10.5, true], // -float (same) + [-10.5, -0.5, true], // -float + -float + [-10.5, -0.3, false], + [-31.5, -10.5, true], + [-31.6, -10.5, false], + ['foo', 1, false], // invalid values + [1, 'foo', false], + ['foo', 'foo', false], + ]; + } + public function testProperMessagesAreReturnedForSizes() { $trans = $this->getIlluminateArrayTranslator();