Skip to content

Commit

Permalink
Merge c530ba0 into 2df58dd
Browse files Browse the repository at this point in the history
  • Loading branch information
brendt committed Oct 16, 2018
2 parents 2df58dd + c530ba0 commit e046721
Show file tree
Hide file tree
Showing 10 changed files with 402 additions and 1 deletion.
89 changes: 89 additions & 0 deletions README.md
Expand Up @@ -24,6 +24,9 @@ The package will automatically register itself.
- [`authorized`](#authorized)
- [`enum`](#enum)
- [`modelsExist`](#modelids)
- [`futureDate`](#futuredate)
- [`pastDate`](#pastdate)
- [`dateBetween`](#date)

### `authorized`

Expand Down Expand Up @@ -117,6 +120,92 @@ public function rules()
}
```

### `futureDate`

Determine if a date is in the future.

```php
// in a `FormRequest`

public function rules()
{
return [
'date_from' => ['date', new FutureDate()],
];
}
```

#### Date format

By default this rule will use `Y-m-d` as the date format, it can be overridden in the constructor.

```php
new FutureDate('Y-m-d H:i:s');
```

### `pastDate`

Determine if a date is in the past.

```php
// in a `FormRequest`

public function rules()
{
return [
'date_from' => ['date', new PastDate()],
];
}
```

#### Date format

By default this rule will use `Y-m-d` as the date format, it can be overridden in the constructor.

```php
new PastDate('Y-m-d H:i:s');
```

### `dateBetween`

Determine if a date is between two other dates.

```php
// in a `FormRequest`

public function rules()
{
return [
'date_from' => [
'date',
new DateBetween(now()->subWeek(), now()->addWeek()),
],
];
}
```

By default the boundary dates are included, you can exluding them by calling `excludeBoundaries`.

```php
(new DateBetween(now()->subWeek(), now()->addWeek()))
->excludeBoundaries()
```

If you only want to determine whether a date is between full days, you can use `withoutTime`.

```php
(new DateBetween(now()->subWeek(), now()->addWeek()))
->withoutTime()
```

#### Date format

By default this rule will use `Y-m-d` as the date format, it can be overridden in the constructor.

```php
new DateBetween($from, $to, 'Y-m-d H:i:s');
```

### Testing

``` bash
Expand Down
3 changes: 2 additions & 1 deletion composer.json
Expand Up @@ -17,7 +17,8 @@
],
"require": {
"php": "^7.1",
"illuminate/support": "^5.7"
"illuminate/support": "^5.7",
"nesbot/carbon": "^1.34"
},
"require-dev": {
"orchestra/testbench": "^3.7",
Expand Down
13 changes: 13 additions & 0 deletions src/Exceptions/InvalidDate.php
@@ -0,0 +1,13 @@
<?php

namespace Spatie\ValidationRules\Exceptions;

use Exception;

class InvalidDate extends Exception
{
public static function withFormat(string $format, string $value): InvalidDate
{
return new self("Invalid date {$value} for format {$format}");
}
}
22 changes: 22 additions & 0 deletions src/IsDateRule.php
@@ -0,0 +1,22 @@
<?php

namespace Spatie\ValidationRules;

use Carbon\Carbon;
use InvalidArgumentException;
use Spatie\ValidationRules\Exceptions\InvalidDate;

trait IsDateRule
{
/** @var string */
protected $format;

protected function createDate(string $value): Carbon
{
try {
return Carbon::createFromFormat($this->format, $value);
} catch (InvalidArgumentException $exception) {
throw InvalidDate::withFormat($this->format, $value);
}
}
}
65 changes: 65 additions & 0 deletions src/Rules/DateBetween.php
@@ -0,0 +1,65 @@
<?php

namespace Spatie\ValidationRules\Rules;

use Carbon\Carbon;
use Spatie\ValidationRules\IsDateRule;
use Illuminate\Contracts\Validation\Rule;

class DateBetween implements Rule
{
use IsDateRule;

/** @var \Carbon\Carbon */
protected $start;

/** @var \Carbon\Carbon */
protected $end;

/** @var bool */
protected $orEquals = true;

public function __construct(Carbon $start, Carbon $end, string $format = 'Y-m-d')
{
$this->start = $start->copy();

$this->end = $end->copy();

$this->format = $format;
}

public function includeBoundaries(): DateBetween
{
$this->orEquals = true;

return $this;
}

public function excludeBoundaries(): DateBetween
{
$this->orEquals = false;

return $this;
}

public function withoutTime(): DateBetween
{
$this->start->startOfDay();

$this->end->endOfDay();

return $this;
}

public function passes($attribute, $value): bool
{
$date = $this->createDate($value);

return $date->between($this->start, $this->end, $this->orEquals);
}

public function message(): string
{
return __('validationRules.date_between');
}
}
28 changes: 28 additions & 0 deletions src/Rules/FutureDate.php
@@ -0,0 +1,28 @@
<?php

namespace Spatie\ValidationRules\Rules;

use Spatie\ValidationRules\IsDateRule;
use Illuminate\Contracts\Validation\Rule;

class FutureDate implements Rule
{
use IsDateRule;

public function __construct(string $format = 'Y-m-d')
{
$this->format = $format;
}

public function passes($attribute, $value): bool
{
$date = $this->createDate($value);

return $date->isFuture();
}

public function message(): string
{
return __('validationRules.future_date');
}
}
28 changes: 28 additions & 0 deletions src/Rules/PastDate.php
@@ -0,0 +1,28 @@
<?php

namespace Spatie\ValidationRules\Rules;

use Spatie\ValidationRules\IsDateRule;
use Illuminate\Contracts\Validation\Rule;

class PastDate implements Rule
{
use IsDateRule;

public function __construct(string $format = 'Y-m-d')
{
$this->format = $format;
}

public function passes($attribute, $value): bool
{
$date = $this->createDate($value);

return $date->isPast();
}

public function message(): string
{
return __('validationRules.past_date');
}
}
89 changes: 89 additions & 0 deletions tests/Rules/DateBetweenTest.php
@@ -0,0 +1,89 @@
<?php

namespace Spatie\ValidationRules\Tests\Rules;

use Carbon\Carbon;
use Spatie\ValidationRules\Tests\TestCase;
use Spatie\ValidationRules\Rules\DateBetween;
use Spatie\ValidationRules\Exceptions\InvalidDate;

class DateBetweenTest extends TestCase
{
public function setUp()
{
parent::setUp();

Carbon::setTestNow(Carbon::make('2018-01-01 00:00:00'));
}

/** @test */
public function it_will_return_true_when_between_or_equals()
{
$rule = new DateBetween(now(), now()->addDays(2));

$this->assertTrue($rule->passes('attribute', '2018-01-01'));
$this->assertTrue($rule->passes('attribute', '2018-01-02'));
$this->assertTrue($rule->passes('attribute', '2018-01-03'));
}

/** @test */
public function it_will_return_false_when_not_between()
{
$rule = new DateBetween(now(), now()->addDays(2));

$this->assertFalse($rule->passes('attribute', '2017-01-01'));
$this->assertFalse($rule->passes('attribute', '2019-01-01'));
}

/** @test */
public function it_will_return_false_when_on_boundary_and_boundaries_are_excluded()
{
$rule = (new DateBetween(now(), now()->addDays(2)))
->excludeBoundaries();

$this->assertFalse($rule->passes('attribute', '2018-01-01'));
$this->assertTrue($rule->passes('attribute', '2018-01-02'));
$this->assertFalse($rule->passes('attribute', '2018-01-03'));
}

/** @test */
public function it_will_return_true_when_comparing_without_time_and_within_day_boundary()
{
$rule = (new DateBetween(
Carbon::make('2018-01-01 12:00:00'),
Carbon::make('2018-01-03 12:00:00'),
'Y-m-d H:i:s'
))
->withoutTime();

$this->assertTrue($rule->passes('attribute', Carbon::make('2018-01-01 10:00:00')));
$this->assertTrue($rule->passes('attribute', Carbon::make('2018-01-03 14:00:00')));
}

/** @test */
public function it_will_return_false_when_comparing_with_time_and_within_day_boundary()
{
$rule = (new DateBetween(
Carbon::make('2018-01-01 12:00:00'),
Carbon::make('2018-01-03 12:00:00'),
'Y-m-d H:i:s'
));

$this->assertFalse($rule->passes('attribute', Carbon::make('2018-01-01 10:00:00')));
$this->assertFalse($rule->passes('attribute', Carbon::make('2018-01-03 14:00:00')));
}

/** @test */
public function it_throws_an_invalid_date_exception_on_invalid_format()
{
$rule = (new DateBetween(
Carbon::make('2018-01-01 12:00:00'),
Carbon::make('2018-01-03 12:00:00'),
'Y-m-d'
));

$this->expectException(InvalidDate::class);

$rule->passes('attribute', Carbon::make('2018-01-01'));
}
}
33 changes: 33 additions & 0 deletions tests/Rules/FutureDateTest.php
@@ -0,0 +1,33 @@
<?php

namespace Spatie\ValidationRules\Tests\Rules;

use Carbon\Carbon;
use Spatie\ValidationRules\Tests\TestCase;
use Spatie\ValidationRules\Rules\FutureDate;

class FutureDateTest extends TestCase
{
public function setUp()
{
parent::setUp();

Carbon::setTestNow(Carbon::make('2018-01-01 00:00:00'));
}

/** @test */
public function it_will_return_true_when_is_future_date()
{
$rule = new FutureDate();

$this->assertTrue($rule->passes('attribute', '2018-01-02'));
}

/** @test */
public function it_will_return_false_when_not_future_date()
{
$rule = new FutureDate();

$this->assertFalse($rule->passes('attribute', '2017-01-01'));
}
}

0 comments on commit e046721

Please sign in to comment.