From a5ae20ba16252cf830d7f60a4631201ec140d8f4 Mon Sep 17 00:00:00 2001 From: Derek MacDonald Date: Mon, 19 Feb 2018 01:27:32 -0500 Subject: [PATCH] make validation time params testable Date validation rule parameters containing relative time like 'today' or 'next monday' do not respective Carbon::setTestNow(). To get a date-adjusted value when these keywords are present in a date parameter, instantiate Carbon over DateTime or strtotime(). --- .../Concerns/ValidatesAttributes.php | 54 ++++++++++++++++++- tests/Validation/ValidationValidatorTest.php | 47 ++++++++++++++++ 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php index d6667b4f918b..dc121ffb7049 100644 --- a/src/Illuminate/Validation/Concerns/ValidatesAttributes.php +++ b/src/Illuminate/Validation/Concerns/ValidatesAttributes.php @@ -11,6 +11,7 @@ use Illuminate\Support\Arr; use Illuminate\Support\Str; use InvalidArgumentException; +use Illuminate\Support\Carbon; use Illuminate\Validation\Rules\Exists; use Illuminate\Validation\Rules\Unique; use Illuminate\Validation\ValidationData; @@ -180,7 +181,19 @@ protected function getDateFormat($attribute) */ protected function getDateTimestamp($value) { - return $value instanceof DateTimeInterface ? $value->getTimestamp() : strtotime($value); + if ($value instanceof DateTimeInterface) { + return $value->getTimestamp(); + } + + if ($this->hasRelativeDateKeyword($value)) { + $date = $this->getDateTime($value); + + if (! is_null($date)) { + return $date->getTimestamp(); + } + } + + return strtotime($value); } /** @@ -214,13 +227,52 @@ protected function getDateTimeWithOptionalFormat($format, $value) return $date; } + return $this->getDateTime($value); + } + + /** + * @param string $value + * @return \DateTime|null + */ + protected function getDateTime($value) + { try { + if ($this->hasRelativeDateKeyword($value)) { + return $this->getTestNowDateTime($value); + } + return new DateTime($value); } catch (Exception $e) { // } } + /** + * @param mixed $value + * @return bool + */ + protected function hasRelativeDateKeyword($value) + { + return Carbon::hasTestNow() && is_string($value) && ( + Carbon::hasRelativeKeywords($value) || in_array($value, ['now', 'today']) + ); + } + + /** + * @param string $value + * @return DateTime + */ + protected function getTestNowDateTime($value) + { + $date = Carbon::getTestNow()->copy(); + + if ($value !== 'now') { + $date->modify($value); + } + + return new DateTime($date->toDateTimeString()); + } + /** * Validate that an attribute contains only alphabetic characters. * diff --git a/tests/Validation/ValidationValidatorTest.php b/tests/Validation/ValidationValidatorTest.php index 36e98cb59041..137918b19aea 100755 --- a/tests/Validation/ValidationValidatorTest.php +++ b/tests/Validation/ValidationValidatorTest.php @@ -19,6 +19,7 @@ class ValidationValidatorTest extends TestCase { public function tearDown() { + Carbon::setTestNow(); m::close(); } @@ -2479,6 +2480,52 @@ public function testDateEquals() $this->assertTrue($v->fails()); } + public function testDateEqualsRespectsCarbonTestNowWhenParameterIsRelative() + { + date_default_timezone_set('UTC'); + $trans = $this->getIlluminateArrayTranslator(); + Carbon::setTestNow(new Carbon('2018-01-01')); + + $v = new Validator($trans, ['x' => '2018-01-01 00:00:00'], ['x' => 'date_equals:now']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['x' => '2018-01-01'], ['x' => 'date_equals:today']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['x' => '2018-01-01'], ['x' => 'date_equals:yesterday']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => '2018-01-01'], ['x' => 'date_equals:tomorrow']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => '01/01/2018'], ['x' => 'date_format:d/m/Y|date_equals:today']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['x' => '01/01/2018'], ['x' => 'date_format:d/m/Y|date_equals:yesterday']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => '01/01/2018'], ['x' => 'date_format:d/m/Y|date_equals:tomorrow']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => new DateTime('2018-01-01')], ['x' => 'date_equals:today']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['x' => new DateTime('2018-01-01')], ['x' => 'date_equals:yesterday']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => new DateTime('2018-01-01')], ['x' => 'date_equals:tomorrow']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => new Carbon('2018-01-01')], ['x' => 'date_equals:today|after:yesterday|before:tomorrow']); + $this->assertTrue($v->passes()); + + $v = new Validator($trans, ['x' => new Carbon('2018-01-01')], ['x' => 'date_equals:yesterday']); + $this->assertTrue($v->fails()); + + $v = new Validator($trans, ['x' => new Carbon('2018-01-01')], ['x' => 'date_equals:tomorrow']); + $this->assertTrue($v->fails()); + } + public function testBeforeAndAfter() { date_default_timezone_set('UTC');