From db0f71575fd4e35371526b691b22c10c9995c906 Mon Sep 17 00:00:00 2001 From: Henrique Moody Date: Thu, 19 Feb 2015 17:33:45 -0200 Subject: [PATCH] Create "Age" rule Also add a deprecation note in "MinimumAge" rule documentation. --- docs/Age.md | 45 ++++++++++ docs/MinimumAge.md | 3 + docs/README.md | 2 +- docs/VALIDATORS.md | 3 + library/Exceptions/AgeException.php | 43 ++++++++++ library/Rules/Age.php | 64 ++++++++++++++ library/Validator.php | 1 + tests/Rules/AgeTest.php | 129 ++++++++++++++++++++++++++++ 8 files changed, 289 insertions(+), 1 deletion(-) create mode 100644 docs/Age.md create mode 100644 library/Exceptions/AgeException.php create mode 100755 library/Rules/Age.php create mode 100644 tests/Rules/AgeTest.php diff --git a/docs/Age.md b/docs/Age.md new file mode 100644 index 000000000..cdfbb9291 --- /dev/null +++ b/docs/Age.md @@ -0,0 +1,45 @@ +# Age + +- `v::age(int $minAge)` +- `v::age(int $minAge, int $maxAge)` +- `v::age(null, int $maxAge)` + +Validates ranges of years. + +The validated values can be any date value; internally they will be transformed +into [DateTime](http://php.net/manual/en/class.datetime.php) objects according +to the defined locale settings. + +The examples below validate if the given dates are lower or equal to 18 years ago: +```php +v::age(18)->validate('17 years ago'); //false +v::age(18)->validate('18 years ago'); //true +v::age(18)->validate('19 years ago'); //true +v::age(18)->validate('1970-01-01'); //true +v::age(18)->validate('today'); //false +``` + +The examples below validate if the given dates are between 10 and 50 years ago: +```php +v::age(10, 50)->validate('9 years ago'); //false +v::age(10, 50)->validate('10 years ago'); //true +v::age(10, 50)->validate('30 years ago'); //true +v::age(10, 50)->validate('50 years ago'); //true +v::age(10, 50)->validate('51 years ago'); //false +``` + +The examples below validate if the given dates are greater than or equal to 70 years ago: +```php +v::age(null, 70)->validate('today'); //true +v::age(null, 70)->validate('70 years ago'); //true +v::age(null, 70)->validate('71 years ago'); //false +``` + +Message template for this validator includes `{{minAge}}` and `{{maxAge}}`. + +See also: + + * [Between](Between.md) + * [Date](Date.md) + * [Max](Max.md) + * [Min](Min.md) diff --git a/docs/MinimumAge.md b/docs/MinimumAge.md index e6463e884..0d25bbc48 100644 --- a/docs/MinimumAge.md +++ b/docs/MinimumAge.md @@ -1,5 +1,7 @@ # MinimumAge +This is going to be deprecated, please use [Age](Age.md) instead. + - `v::minimumAge(int $age)` - `v::minimumAge(int $age, string $format)` @@ -16,4 +18,5 @@ Message template for this validator includes `{{age}}`. See also: + * [Age](Age.md) * [Date](Date.md) diff --git a/docs/README.md b/docs/README.md index d45cf82d8..b8629d9f1 100644 --- a/docs/README.md +++ b/docs/README.md @@ -42,7 +42,7 @@ Is possible to validate its attributes in a single chain: ```php $userValidator = v::attribute('name', v::string()->length(1,32)) - ->attribute('birthdate', v::date()->minimumAge(18)); + ->attribute('birthdate', v::date()->age(18)); $userValidator->validate($user); //true ``` diff --git a/docs/VALIDATORS.md b/docs/VALIDATORS.md index d0c8ed5b6..22e03bc36 100644 --- a/docs/VALIDATORS.md +++ b/docs/VALIDATORS.md @@ -30,6 +30,7 @@ ## Comparing Values + * [Age](Age.md) * [Between](Between.md) * [Equals](Equals.md) * [Max](Max.md) @@ -101,6 +102,7 @@ ## Date and Time + * [Age](Age.md) * [Between](Between.md) * [Date](Date.md) * [LeapDate](LeapDate.md) @@ -160,6 +162,7 @@ ## Alphabetically + * [Age](Age.md) * [AllOf](AllOf.md) * [Alnum](Alnum.md) * [Alpha](Alpha.md) diff --git a/library/Exceptions/AgeException.php b/library/Exceptions/AgeException.php new file mode 100644 index 000000000..675683dc9 --- /dev/null +++ b/library/Exceptions/AgeException.php @@ -0,0 +1,43 @@ + array( + self::BOTH => '{{name}} must be between {{minAge}} and {{maxAge}} years ago', + self::LOWER => '{{name}} must be lower than {{minAge}} years ago', + self::GREATER => '{{name}} must be greater than {{maxAge}} years ago', + ), + self::MODE_NEGATIVE => array( + self::BOTH => '{{name}} must not be between {{minAge}} and {{maxAge}} years ago', + self::LOWER => '{{name}} must not be lower than {{minAge}} years ago', + self::GREATER => '{{name}} must not be greater than {{maxAge}} years ago', + ), + ); + + public function configure($name, array $params = array()) + { + $params['minAge'] = static::stringify($params['minAge']); + $params['maxAge'] = static::stringify($params['maxAge']); + + return parent::configure($name, $params); + } + + public function chooseTemplate() + { + if (!$this->getParam('minAge')) { + return static::GREATER; + } + + if (!$this->getParam('maxAge')) { + return static::LOWER; + } + + return static::BOTH; + } +} diff --git a/library/Rules/Age.php b/library/Rules/Age.php new file mode 100755 index 000000000..ebfa89e0c --- /dev/null +++ b/library/Rules/Age.php @@ -0,0 +1,64 @@ +setMinAge($minAge); + $this->setMaxAge($maxAge); + } + + private function createDateTimeFromAge($age) + { + $interval = sprintf('-%d years', $age); + + return new DateTime($interval); + } + + private function setMaxAge($maxAge) + { + $this->maxAge = $maxAge; + + if (null === $maxAge) { + return; + } + + $minDate = $this->createDateTimeFromAge($maxAge); + $minDate->setTime(0, 0, 0); + + $minRule = new Min($minDate, true); + + $this->addRule($minRule); + } + + private function setMinAge($minAge) + { + $this->minAge = $minAge; + + if (null === $minAge) { + return; + } + + $maxDate = $this->createDateTimeFromAge($minAge); + $maxDate->setTime(23, 59, 59); + + $maxRule = new Max($maxDate, true); + + $this->addRule($maxRule); + } +} diff --git a/library/Validator.php b/library/Validator.php index 66af9f11b..7855a2043 100644 --- a/library/Validator.php +++ b/library/Validator.php @@ -8,6 +8,7 @@ use Respect\Validation\Rules\AllOf; /** + * @method static Validator age(int $minAge = null, int $maxAge = null) * @method static Validator allOf() * @method static Validator alnum(string $additionalChars = null) * @method static Validator alpha(string $additionalChars = null) diff --git a/tests/Rules/AgeTest.php b/tests/Rules/AgeTest.php new file mode 100644 index 000000000..337ebe23e --- /dev/null +++ b/tests/Rules/AgeTest.php @@ -0,0 +1,129 @@ +assertTrue($rule->validate($input)); + } + + public function providerForInvalidAge() + { + return array( + array(18, null, date('Y-m-d', strtotime('-17 years'))), + array(18, null, new DateTime('-17 years')), + + array(18, 50, date('Y-m-d', strtotime('-17 years'))), + array(18, 50, date('Y-m-d', strtotime('-51 years'))), + array(18, 50, new DateTime('-17 years')), + array(18, 50, new DateTime('-51 years')), + + array(null, 50, date('Y-m-d', strtotime('-51 years'))), + array(null, 50, new DateTime('-51 years')), + ); + } + + /** + * @dataProvider providerForInvalidAge + */ + public function testShouldValidateInvalidAge($minAge, $maxAge, $input) + { + $rule = new Age($minAge, $maxAge); + + $this->assertFalse($rule->validate($input)); + } + + /** + * @depends testShouldValidateInvalidAge + * + * @expectedException Respect\Validation\Exceptions\AgeException + * @expectedExceptionMessage "today" must be lower than 18 years ago + */ + public function testShouldThrowsExceptionWhenMinimumAgeFails() + { + $rule = new Age(18); + $rule->assert('today'); + } + + /** + * @depends testShouldValidateInvalidAge + * + * @expectedException Respect\Validation\Exceptions\AgeException + * @expectedExceptionMessage "51 years ago" must be greater than 50 years ago + */ + public function testShouldThrowsExceptionWhenMaximunAgeFails() + { + $rule = new Age(null, 50); + $rule->assert('51 years ago'); + } + + /** + * @depends testShouldValidateInvalidAge + * + * @expectedException Respect\Validation\Exceptions\AgeException + * @expectedExceptionMessage "today" must be between 18 and 50 years ago + */ + public function testShouldThrowsExceptionWhenMinimunAndMaximunAgeFails() + { + $rule = new Age(18, 50); + $rule->assert('today'); + } +}