Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 4917528

Browse filesBrowse files
committed
Resolve DateTime value using the clock
1 parent 5bfb260 commit 4917528
Copy full SHA for 4917528

File tree

5 files changed

+67
-21
lines changed
Filter options

5 files changed

+67
-21
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/web.php
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@
5555
->tag('controller.argument_value_resolver', ['priority' => 100])
5656

5757
->set('argument_resolver.datetime', DateTimeValueResolver::class)
58+
->args([
59+
service('clock')->nullOnInvalid(),
60+
])
5861
->tag('controller.argument_value_resolver', ['priority' => 100])
5962

6063
->set('argument_resolver.request_attribute', RequestAttributeValueResolver::class)

‎src/Symfony/Component/HttpKernel/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ CHANGELOG
77
* Deprecate parameters `container.dumper.inline_factories` and `container.dumper.inline_class_loader`, use `.container.dumper.inline_factories` and `.container.dumper.inline_class_loader` instead
88
* `FileProfilerStorage` removes profiles automatically after two days
99
* Add `#[HttpStatus]` for defining status codes for exceptions
10+
* Use an instance of `Psr\Clock\ClockInterface` to generate the current date time in `DateTimeValueResolver`
1011

1112
6.2
1213
---

‎src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/DateTimeValueResolver.php
+17-5Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Component\HttpKernel\Controller\ArgumentResolver;
1313

14+
use Psr\Clock\ClockInterface;
1415
use Symfony\Component\HttpFoundation\Request;
1516
use Symfony\Component\HttpKernel\Attribute\MapDateTime;
1617
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
@@ -26,6 +27,11 @@
2627
*/
2728
final class DateTimeValueResolver implements ArgumentValueResolverInterface, ValueResolverInterface
2829
{
30+
public function __construct(
31+
private readonly ?ClockInterface $clock = null,
32+
) {
33+
}
34+
2935
/**
3036
* @deprecated since Symfony 6.2, use resolve() instead
3137
*/
@@ -45,12 +51,18 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
4551
$value = $request->attributes->get($argument->getName());
4652
$class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType();
4753

48-
if ($value instanceof \DateTimeInterface) {
49-
return [$value instanceof $class ? $value : $class::createFromInterface($value)];
54+
if (!$value) {
55+
if ($argument->isNullable()) {
56+
return [null];
57+
}
58+
if (!$this->clock) {
59+
return [new $class()];
60+
}
61+
$value = $this->clock->now();
5062
}
5163

52-
if ($argument->isNullable() && !$value) {
53-
return [null];
64+
if ($value instanceof \DateTimeInterface) {
65+
return [$value instanceof $class ? $value : $class::createFromInterface($value)];
5466
}
5567

5668
$format = null;
@@ -71,7 +83,7 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
7183
$value = '@'.$value;
7284
}
7385
try {
74-
$date = new $class($value ?? 'now');
86+
$date = new $class($value);
7587
} catch (\Exception) {
7688
$date = false;
7789
}

‎src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/DateTimeValueResolverTest.php
+45-16Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\HttpKernel\Tests\Controller\ArgumentResolver;
1313

1414
use PHPUnit\Framework\TestCase;
15+
use Symfony\Component\Clock\MockClock;
1516
use Symfony\Component\HttpFoundation\Request;
1617
use Symfony\Component\HttpKernel\Attribute\MapDateTime;
1718
use Symfony\Component\HttpKernel\Controller\ArgumentResolver\DateTimeValueResolver;
@@ -34,9 +35,12 @@ protected function tearDown(): void
3435

3536
public static function getTimeZones()
3637
{
37-
yield ['UTC'];
38-
yield ['Etc/GMT+9'];
39-
yield ['Etc/GMT-14'];
38+
yield ['UTC', false];
39+
yield ['Etc/GMT+9', false];
40+
yield ['Etc/GMT-14', false];
41+
yield ['UTC', true];
42+
yield ['Etc/GMT+9', true];
43+
yield ['Etc/GMT-14', true];
4044
}
4145

4246
public static function getClasses()
@@ -78,10 +82,10 @@ public function testUnsupportedArgument()
7882
/**
7983
* @dataProvider getTimeZones
8084
*/
81-
public function testFullDate(string $timezone)
85+
public function testFullDate(string $timezone, bool $withClock)
8286
{
8387
date_default_timezone_set($timezone);
84-
$resolver = new DateTimeValueResolver();
88+
$resolver = new DateTimeValueResolver($withClock ? new MockClock() : null);
8589

8690
$argument = new ArgumentMetadata('dummy', \DateTimeImmutable::class, false, false, null);
8791
$request = self::requestWithAttributes(['dummy' => '2012-07-21 00:00:00']);
@@ -97,10 +101,10 @@ public function testFullDate(string $timezone)
97101
/**
98102
* @dataProvider getTimeZones
99103
*/
100-
public function testUnixTimestamp(string $timezone)
104+
public function testUnixTimestamp(string $timezone, bool $withClock)
101105
{
102106
date_default_timezone_set($timezone);
103-
$resolver = new DateTimeValueResolver();
107+
$resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);
104108

105109
$argument = new ArgumentMetadata('dummy', \DateTimeImmutable::class, false, false, null);
106110
$request = self::requestWithAttributes(['dummy' => '989541720']);
@@ -127,21 +131,46 @@ public function testNullableWithEmptyAttribute()
127131
}
128132

129133
/**
130-
* @dataProvider getTimeZones
134+
* @param class-string<\DateTimeInterface> $class
135+
*
136+
* @dataProvider getClasses
131137
*/
132-
public function testNow(string $timezone)
138+
public function testNow(string $class)
133139
{
134-
date_default_timezone_set($timezone);
140+
date_default_timezone_set($timezone = 'Etc/GMT+9');
135141
$resolver = new DateTimeValueResolver();
136142

137-
$argument = new ArgumentMetadata('dummy', \DateTime::class, false, false, null, false);
143+
$argument = new ArgumentMetadata('dummy', $class, false, false, null, false);
138144
$request = self::requestWithAttributes(['dummy' => null]);
139145

140146
$results = $resolver->resolve($request, $argument);
141147

142148
$this->assertCount(1, $results);
143-
$this->assertEquals('0', $results[0]->diff(new \DateTimeImmutable())->format('%s'));
149+
$this->assertInstanceOf($class, $results[0]);
144150
$this->assertSame($timezone, $results[0]->getTimezone()->getName(), 'Default timezone');
151+
$this->assertEquals('0', $results[0]->diff(new \DateTimeImmutable())->format('%s'));
152+
}
153+
154+
/**
155+
* @param class-string<\DateTimeInterface> $class
156+
*
157+
* @dataProvider getClasses
158+
*/
159+
public function testNowWithClock(string $class)
160+
{
161+
date_default_timezone_set('Etc/GMT+9');
162+
$clock = new MockClock('2022-02-20 22:20:02');
163+
$resolver = new DateTimeValueResolver($clock);
164+
165+
$argument = new ArgumentMetadata('dummy', $class, false, false, null, false);
166+
$request = self::requestWithAttributes(['dummy' => null]);
167+
168+
$results = $resolver->resolve($request, $argument);
169+
170+
$this->assertCount(1, $results);
171+
$this->assertInstanceOf($class, $results[0]);
172+
$this->assertSame('UTC', $results[0]->getTimezone()->getName(), 'Default timezone');
173+
$this->assertEquals($clock->now(), $results[0]);
145174
}
146175

147176
/**
@@ -181,10 +210,10 @@ public function testCustomClass()
181210
/**
182211
* @dataProvider getTimeZones
183212
*/
184-
public function testDateTimeImmutable(string $timezone)
213+
public function testDateTimeImmutable(string $timezone, bool $withClock)
185214
{
186215
date_default_timezone_set($timezone);
187-
$resolver = new DateTimeValueResolver();
216+
$resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);
188217

189218
$argument = new ArgumentMetadata('dummy', \DateTimeImmutable::class, false, false, null);
190219
$request = self::requestWithAttributes(['dummy' => '2016-09-08 00:00:00 +05:00']);
@@ -200,10 +229,10 @@ public function testDateTimeImmutable(string $timezone)
200229
/**
201230
* @dataProvider getTimeZones
202231
*/
203-
public function testWithFormat(string $timezone)
232+
public function testWithFormat(string $timezone, bool $withClock)
204233
{
205234
date_default_timezone_set($timezone);
206-
$resolver = new DateTimeValueResolver();
235+
$resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);
207236

208237
$argument = new ArgumentMetadata('dummy', \DateTimeInterface::class, false, false, null, false, [
209238
MapDateTime::class => new MapDateTime('m-d-y H:i:s'),

‎src/Symfony/Component/HttpKernel/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Component/HttpKernel/composer.json
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
},
2727
"require-dev": {
2828
"symfony/browser-kit": "^5.4|^6.0",
29+
"symfony/clock": "^6.2",
2930
"symfony/config": "^6.1",
3031
"symfony/console": "^5.4|^6.0",
3132
"symfony/css-selector": "^5.4|^6.0",

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.