Skip to content

Commit

Permalink
Merge pull request #305 from henriquemoody/age
Browse files Browse the repository at this point in the history
Create "Age" rule
  • Loading branch information
henriquemoody committed Feb 19, 2015
2 parents 97c7db4 + db0f715 commit 7136e82
Show file tree
Hide file tree
Showing 8 changed files with 289 additions and 1 deletion.
45 changes: 45 additions & 0 deletions docs/Age.md
Original file line number Diff line number Diff line change
@@ -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)
3 changes: 3 additions & 0 deletions docs/MinimumAge.md
Original file line number Diff line number Diff line change
@@ -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)`

Expand All @@ -16,4 +18,5 @@ Message template for this validator includes `{{age}}`.

See also:

* [Age](Age.md)
* [Date](Date.md)
2 changes: 1 addition & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
Expand Down
3 changes: 3 additions & 0 deletions docs/VALIDATORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@

## Comparing Values

* [Age](Age.md)
* [Between](Between.md)
* [Equals](Equals.md)
* [Max](Max.md)
Expand Down Expand Up @@ -101,6 +102,7 @@

## Date and Time

* [Age](Age.md)
* [Between](Between.md)
* [Date](Date.md)
* [LeapDate](LeapDate.md)
Expand Down Expand Up @@ -160,6 +162,7 @@

## Alphabetically

* [Age](Age.md)
* [AllOf](AllOf.md)
* [Alnum](Alnum.md)
* [Alpha](Alpha.md)
Expand Down
43 changes: 43 additions & 0 deletions library/Exceptions/AgeException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php
namespace Respect\Validation\Exceptions;

class AgeException extends AbstractNestedException
{
const BOTH = 0;
const LOWER = 1;
const GREATER = 2;

public static $defaultTemplates = array(
self::MODE_DEFAULT => 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;
}
}
64 changes: 64 additions & 0 deletions library/Rules/Age.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
namespace Respect\Validation\Rules;

use DateTime;
use Respect\Validation\Exceptions\ComponentException;

class Age extends AllOf
{
public $minAge;
public $maxAge;

public function __construct($minAge = null, $maxAge = null)
{
if (null === $minAge && null === $maxAge) {
throw new ComponentException('An age interval must be provided');
}

if (null !== $minAge && null !== $maxAge && $maxAge <= $minAge) {
throw new ComponentException(sprintf('%d cannot be greater than or equals to %d', $minAge, $maxAge));
}

$this->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);
}
}
1 change: 1 addition & 0 deletions library/Validator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
129 changes: 129 additions & 0 deletions tests/Rules/AgeTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
<?php
namespace Respect\Validation\Rules;

use DateTime;

/**
* @covers Respect\Validation\Rules\Age
* @covers Respect\Validation\Exceptions\AgeException
*/
class AgeTest extends \PHPUnit_Framework_TestCase
{
/**
* @expectedException Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage An age interval must be provided
*/
public function testShouldThrowsExceptionWhenThereIsNoArgumentsOnConstructor()
{
new Age();
}
/**
* @expectedException Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage 20 cannot be greater than or equals to 10
*/
public function testShouldThrowsExceptionWhenMinimumAgeIsLessThenMaximumAge()
{
new Age(20, 10);
}

/**
* @expectedException Respect\Validation\Exceptions\ComponentException
* @expectedExceptionMessage 20 cannot be greater than or equals to 20
*/
public function testShouldThrowsExceptionWhenMinimumAgeIsEqualsToMaximumAge()
{
new Age(20, 20);
}

public function providerForValidAge()
{
return array(
array(18, null, date('Y-m-d', strtotime('-18 years'))),
array(18, null, date('Y-m-d', strtotime('-19 years'))),
array(18, null, new DateTime('-18 years')),
array(18, null, new DateTime('-19 years')),

array(18, 50, date('Y-m-d', strtotime('-18 years'))),
array(18, 50, date('Y-m-d', strtotime('-50 years'))),
array(18, 50, new DateTime('-18 years')),
array(18, 50, new DateTime('-50 years')),

array(null, 50, date('Y-m-d', strtotime('-49 years'))),
array(null, 50, date('Y-m-d', strtotime('-50 years'))),
array(null, 50, new DateTime('-49 years')),
array(null, 50, new DateTime('-50 years')),
);
}

/**
* @dataProvider providerForValidAge
*/
public function testShouldValidateValidAge($minAge, $maxAge, $input)
{
$rule = new Age($minAge, $maxAge);

$this->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');
}
}

0 comments on commit 7136e82

Please sign in to comment.