diff --git a/src/Illuminate/Validation/Rule.php b/src/Illuminate/Validation/Rule.php index b94f40ca3372..5e367f64cb6c 100644 --- a/src/Illuminate/Validation/Rule.php +++ b/src/Illuminate/Validation/Rule.php @@ -6,6 +6,7 @@ use Illuminate\Support\Traits\Macroable; use Illuminate\Validation\Rules\ArrayRule; use Illuminate\Validation\Rules\Can; +use Illuminate\Validation\Rules\Date; use Illuminate\Validation\Rules\Dimensions; use Illuminate\Validation\Rules\Email; use Illuminate\Validation\Rules\Enum; @@ -170,6 +171,16 @@ public static function prohibitedIf($callback) return new ProhibitedIf($callback); } + /** + * Get a date rule builder instance. + * + * @return \Illuminate\Validation\Rules\Date + */ + public static function date() + { + return new Date; + } + /** * Get an email rule builder instance. * diff --git a/src/Illuminate/Validation/Rules/Date.php b/src/Illuminate/Validation/Rules/Date.php new file mode 100644 index 000000000000..6b6140fbd8f8 --- /dev/null +++ b/src/Illuminate/Validation/Rules/Date.php @@ -0,0 +1,135 @@ +addRule('date_format:'.$format); + } + + /** + * Ensure the date is before today. + */ + public function beforeToday(): static + { + return $this->before('today'); + } + + /** + * Ensure the date is after today. + */ + public function afterToday(): static + { + return $this->after('today'); + } + + /** + * Ensure the date is before or equal to today. + */ + public function todayOrBefore(): static + { + return $this->beforeOrEqual('today'); + } + + /** + * Ensure the date is after or equal to today. + */ + public function todayOrAfter(): static + { + return $this->afterOrEqual('today'); + } + + /** + * Ensure the date is before the given date or date field. + */ + public function before(DateTimeInterface|string $date): static + { + return $this->addRule('before:'.$this->formatDate($date)); + } + + /** + * Ensure the date is after the given date or date field. + */ + public function after(DateTimeInterface|string $date): static + { + return $this->addRule('after:'.$this->formatDate($date)); + } + + /** + * Ensure the date is on or before the specified date or date field. + */ + public function beforeOrEqual(DateTimeInterface|string $date): static + { + return $this->addRule('before_or_equal:'.$this->formatDate($date)); + } + + /** + * Ensure the date is on or after the given date or date field. + */ + public function afterOrEqual(DateTimeInterface|string $date): static + { + return $this->addRule('after_or_equal:'.$this->formatDate($date)); + } + + /** + * Ensure the date is between two dates or date fields. + */ + public function between(DateTimeInterface|string $from, DateTimeInterface|string $to): static + { + return $this->after($from)->before($to); + } + + /** + * Ensure the date is between or equal to two dates or date fields. + */ + public function betweenOrEqual(DateTimeInterface|string $from, DateTimeInterface|string $to): static + { + return $this->afterOrEqual($from)->beforeOrEqual($to); + } + + /** + * Add custom rules to the validation rules array. + */ + protected function addRule(array|string $rules): static + { + $this->constraints = array_merge($this->constraints, Arr::wrap($rules)); + + return $this; + } + + /** + * Format the date for the validation rule. + */ + protected function formatDate(DateTimeInterface|string $date): string + { + return $date instanceof DateTimeInterface + ? $date->format('Y-m-d') + : $date; + } + + /** + * Convert the rule to a validation string. + */ + public function __toString(): string + { + return implode('|', $this->constraints); + } +} diff --git a/tests/Validation/ValidationDateRuleTest.php b/tests/Validation/ValidationDateRuleTest.php new file mode 100644 index 000000000000..6c903a6f956a --- /dev/null +++ b/tests/Validation/ValidationDateRuleTest.php @@ -0,0 +1,138 @@ +assertEquals('date', (string) $rule); + + $rule = new Date; + $this->assertSame('date', (string) $rule); + } + + public function testDateFormatRule() + { + $rule = Rule::date()->format('d/m/Y'); + $this->assertEquals('date|date_format:d/m/Y', (string) $rule); + } + + public function testAfterTodayRule() + { + $rule = Rule::date()->afterToday(); + $this->assertEquals('date|after:today', (string) $rule); + + $rule = Rule::date()->todayOrAfter(); + $this->assertEquals('date|after_or_equal:today', (string) $rule); + } + + public function testBeforeTodayRule() + { + $rule = Rule::date()->beforeToday(); + $this->assertEquals('date|before:today', (string) $rule); + + $rule = Rule::date()->todayOrBefore(); + $this->assertEquals('date|before_or_equal:today', (string) $rule); + } + + public function testAfterSpecificDateRule() + { + $rule = Rule::date()->after(Carbon::parse('2024-01-01')); + $this->assertEquals('date|after:2024-01-01', (string) $rule); + } + + public function testBeforeSpecificDateRule() + { + $rule = Rule::date()->before(Carbon::parse('2024-01-01')); + $this->assertEquals('date|before:2024-01-01', (string) $rule); + } + + public function testAfterOrEqualSpecificDateRule() + { + $rule = Rule::date()->afterOrEqual(Carbon::parse('2024-01-01')); + $this->assertEquals('date|after_or_equal:2024-01-01', (string) $rule); + } + + public function testBeforeOrEqualSpecificDateRule() + { + $rule = Rule::date()->beforeOrEqual(Carbon::parse('2024-01-01')); + $this->assertEquals('date|before_or_equal:2024-01-01', (string) $rule); + } + + public function testBetweenDatesRule() + { + $rule = Rule::date()->between(Carbon::parse('2024-01-01'), Carbon::parse('2024-02-01')); + $this->assertEquals('date|after:2024-01-01|before:2024-02-01', (string) $rule); + } + + public function testBetweenOrEqualDatesRule() + { + $rule = Rule::date()->betweenOrEqual('2024-01-01', '2024-02-01'); + $this->assertEquals('date|after_or_equal:2024-01-01|before_or_equal:2024-02-01', (string) $rule); + } + + public function testChainedRules() + { + $rule = Rule::date('Y-m-d H:i:s') + ->format('Y-m-d') + ->after('2024-01-01 00:00:00') + ->before('2025-01-01 00:00:00'); + $this->assertEquals('date|date_format:Y-m-d|after:2024-01-01 00:00:00|before:2025-01-01 00:00:00', (string) $rule); + + $rule = Rule::date() + ->format('Y-m-d') + ->when(true, function ($rule) { + $rule->after('2024-01-01'); + }) + ->unless(true, function ($rule) { + $rule->before('2025-01-01'); + }); + $this->assertSame('date|date_format:Y-m-d|after:2024-01-01', (string) $rule); + } + + public function testDateValidation() + { + $trans = new Translator(new ArrayLoader, 'en'); + + $rule = Rule::date(); + + $validator = new Validator( + $trans, + ['date' => 'not a date'], + ['date' => $rule] + ); + + $this->assertSame( + $trans->get('validation.date'), + $validator->errors()->first('date') + ); + + $validator = new Validator( + $trans, + ['date' => '2024-01-01'], + ['date' => $rule] + ); + + $this->assertEmpty($validator->errors()->first('date')); + + $rule = Rule::date()->between('2024-01-01', '2025-01-01'); + + $validator = new Validator( + $trans, + ['date' => '2024-02-01'], + ['date' => (string) $rule] + ); + + $this->assertEmpty($validator->errors()->first('date')); + } +}