Skip to content

Commit de3a0fc

Browse files
committed
Resolve DateTime value using the clock
1 parent ff56fe8 commit de3a0fc

File tree

4 files changed

+54
-14
lines changed

4 files changed

+54
-14
lines changed

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

Lines 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/Controller/ArgumentResolver/DateTimeValueResolver.php

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

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

14+
use Symfony\Component\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
*/
@@ -53,15 +59,20 @@ public function resolve(Request $request, ArgumentMetadata $argument): array
5359
}
5460

5561
$class = \DateTimeInterface::class === $argument->getType() ? \DateTimeImmutable::class : $argument->getType();
62+
63+
if ($this->clock && !$value) {
64+
$date = $this->clock->now();
65+
66+
return $date instanceof $class ? [$date] : [$class::createFromInterface($date)];
67+
}
68+
5669
$format = null;
5770

5871
if ($attributes = $argument->getAttributes(MapDateTime::class, ArgumentMetadata::IS_INSTANCEOF)) {
5972
$attribute = $attributes[0];
6073
$format = $attribute->format;
6174
}
6275

63-
$date = false;
64-
6576
if (null !== $format) {
6677
$date = $class::createFromFormat($format, $value);
6778

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

Lines changed: 36 additions & 11 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 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
/**
@@ -71,10 +75,10 @@ public function testUnsupportedArgument()
7175
/**
7276
* @dataProvider getTimeZones
7377
*/
74-
public function testFullDate(string $timezone)
78+
public function testFullDate(string $timezone, bool $withClock)
7579
{
7680
date_default_timezone_set($timezone);
77-
$resolver = new DateTimeValueResolver();
81+
$resolver = new DateTimeValueResolver($withClock ? new MockClock() : null);
7882

7983
$argument = new ArgumentMetadata('dummy', \DateTimeImmutable::class, false, false, null);
8084
$request = self::requestWithAttributes(['dummy' => '2012-07-21 00:00:00']);
@@ -90,10 +94,10 @@ public function testFullDate(string $timezone)
9094
/**
9195
* @dataProvider getTimeZones
9296
*/
93-
public function testUnixTimestamp(string $timezone)
97+
public function testUnixTimestamp(string $timezone, bool $withClock)
9498
{
9599
date_default_timezone_set($timezone);
96-
$resolver = new DateTimeValueResolver();
100+
$resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);
97101

98102
$argument = new ArgumentMetadata('dummy', \DateTimeImmutable::class, false, false, null);
99103
$request = self::requestWithAttributes(['dummy' => '989541720']);
@@ -150,10 +154,10 @@ public function testCustomClass()
150154
/**
151155
* @dataProvider getTimeZones
152156
*/
153-
public function testDateTimeImmutable(string $timezone)
157+
public function testDateTimeImmutable(string $timezone, bool $withClock)
154158
{
155159
date_default_timezone_set($timezone);
156-
$resolver = new DateTimeValueResolver();
160+
$resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);
157161

158162
$argument = new ArgumentMetadata('dummy', \DateTimeImmutable::class, false, false, null);
159163
$request = self::requestWithAttributes(['dummy' => '2016-09-08 00:00:00 +05:00']);
@@ -169,10 +173,10 @@ public function testDateTimeImmutable(string $timezone)
169173
/**
170174
* @dataProvider getTimeZones
171175
*/
172-
public function testWithFormat(string $timezone)
176+
public function testWithFormat(string $timezone, bool $withClock)
173177
{
174178
date_default_timezone_set($timezone);
175-
$resolver = new DateTimeValueResolver();
179+
$resolver = new DateTimeValueResolver($withClock ? new MockClock('now', $timezone) : null);
176180

177181
$argument = new ArgumentMetadata('dummy', \DateTimeInterface::class, false, false, null, false, [
178182
MapDateTime::class => new MapDateTime('m-d-y H:i:s'),
@@ -218,6 +222,27 @@ public function test404Exception(ArgumentMetadata $argument, Request $request)
218222
$resolver->resolve($request, $argument);
219223
}
220224

225+
/**
226+
* @param class-string<\DateTimeInterface> $class
227+
* @testWith ["DateTimeInterface"]
228+
* ["DateTimeImmutable"]
229+
* ["DateTime"]
230+
*/
231+
public function testNowFromClock(string $class)
232+
{
233+
$clock = new MockClock('2022-02-20 22:20:02');
234+
$resolver = new DateTimeValueResolver($clock);
235+
236+
$argument = new ArgumentMetadata('dummy', $class, false, false, null, false);
237+
$request = self::requestWithAttributes(['dummy' => null]);
238+
239+
$results = $resolver->resolve($request, $argument);
240+
241+
$this->assertCount(1, $results);
242+
$this->assertInstanceOf($class, $results[0]);
243+
$this->assertEquals($clock->now(), $results[0]);
244+
}
245+
221246
private static function requestWithAttributes(array $attributes): Request
222247
{
223248
$request = Request::create('/');

src/Symfony/Component/HttpKernel/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@
4141
"symfony/translation-contracts": "^1.1|^2|^3",
4242
"symfony/uid": "^5.4|^6.0",
4343
"psr/cache": "^1.0|^2.0|^3.0",
44-
"twig/twig": "^2.13|^3.0.4"
44+
"twig/twig": "^2.13|^3.0.4",
45+
"symfony/clock": "^6.2"
4546
},
4647
"provide": {
4748
"psr/log-implementation": "1.0|2.0|3.0"

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy