8000 feature #60315 [Form] Add `input=date_point` to `DateTimeType`, `Date… · symfony/form@6694bfe · GitHub
[go: up one dir, main page]

Skip to content

Commit 6694bfe

Browse files
feature #60315 [Form] Add input=date_point to DateTimeType, DateType and TimeType (wkania)
This PR was merged into the 7.4 branch. Discussion ---------- [Form] Add `input=date_point` to `DateTimeType`, `DateType` and `TimeType` | Q | A | ------------- | --- | Branch? | 7.4 | Bug fix? | no | New feature? | yes | Deprecations? | no | Issues | | License | MIT Based on [datetime_immutable](https://symfony.com/blog/new-in-symfony-4-1-added-support-for-immutable-dates-in-forms). After [DatePointType](symfony/symfony#59900) and [DatePointDateType](symfony/symfony#60237), it would be great to use Forms without needing to transform values into the DatePoint type manually. ``` use Symfony\Component\Form\Extension\Core\Type\DateType; use Symfony\Component\Form\Extension\Core\Type\DateTimeType; use Symfony\Component\Form\Extension\Core\Type\TimeType; use Symfony\Component\Form\Extension\Core\Type\BirthdayType; $builder->add('from', DateType::class, [ 'input' => 'date_point', ]); $builder->add('from', DateTimeType::class, [ 'input' => 'date_point', ]); $builder->add('from', TimeType::class, [ 'input' => 'date_point', ]); $builder->add('from', BirthdayType::class, [ 'input' => 'date_point', ]); ``` Alternative: Make symfony/clock a hard requirement and refactor the existing DateTimeImmutableToDateTimeTransformer to return a DatePoint instead. This should not introduce any breaking changes. Commits ------- f1160d6617f [Form] Add input=date_point to DateTimeType, DateType and TimeType
2 parents 9ee0a68 + 6b3a364 commit 6694bfe

File tree

9 files changed

+181
-6
lines changed

9 files changed

+181
-6
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
CHANGELOG
22
=========
33

4+
7.4
5+
---
6+
7+
* Add `input=date_point` to `DateTimeType`, `DateType` and `TimeType`
8+
49
7.3
510
---
611

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\Component\Form\Extension\Core\DataTransformer;
13+
14+
use Symfony\Component\Clock\DatePoint;
15+
use Symfony\Component\Form\DataTransformerInterface;
16+
use Symfony\Component\Form\Exception\TransformationFailedException;
17+
18+
/**
19+
* Transforms between a DatePoint object and a DateTime object.
20+
*
21+
* @implements DataTransformerInterface<DatePoint, \DateTime>
22+
*/
23+
final class DatePointToDateTimeTransformer implements DataTransformerInterface
24+
{
25+
/**
26+
* Transforms a DatePoint into a DateTime object.
27+
*
28+
* @param DatePoint|null $value A DatePoint object
29+
*
30+
* @throws TransformationFailedException If the given value is not a DatePoint
31+
*/
32+
public function transform(mixed $value): ?\DateTime
33+
{
34+
if (null === $value) {
35+
return null;
36+
}
37+
38+
if (!$value instanceof DatePoint) {
39+
throw new TransformationFailedException(\sprintf('Expected a "%s".', DatePoint::class));
40+
}
41+
42+
return \DateTime::createFromImmutable($value);
43+
}
44+
45+
/**
46+
* Transforms a DateTime object into a DatePoint object.
47+
*
48+
* @param \DateTime|null $value A DateTime object
49+
*
50+
* @throws TransformationFailedException If the given value is not a \DateTime
51+
*/
52+
public function reverseTransform(mixed $value): ?DatePoint
53+
{
54+
if (null === $value) {
55+
return null;
56+
}
57+
58+
if (!$value instanceof \DateTime) {
59+
throw new TransformationFailedException('Expected a \DateTime.');
60+
}
61+
62+
return DatePoint::createFromMutable($value);
63+
}
64+
}

Extension/Core/Type/DateTimeType.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111

1212
namespace Symfony\Component\Form\Extension\Core\Type;
1313

14+
use Symfony\Component\Clock\DatePoint;
1415
use Symfony\Component\Form\AbstractType;
1516
use Symfony\Component\Form\Exception\LogicException;
1617
use Symfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
1718
use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
19+
use Symfony\Component\Form\Extension\Core\DataTransformer\DatePointToDateTimeTransformer;
1820
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
1921
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
2022
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToHtml5LocalDateTimeTransformer;
@@ -178,7 +180,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
178180
;
179181
}
180182

181-
if ('datetime_immutable' === $options['input']) {
183+
if ('date_point' === $options['input']) {
184+
if (!class_exists(DatePoint::class)) {
185+
throw new LogicException(\sprintf('The "symfony/clock" component is required to use "%s" with option "input=date_point". Try running "composer require symfony/clock".', self::class));
186+
}
187+
$builder->addModelTransformer(new DatePointToDateTimeTransformer());
188+
} elseif ('datetime_immutable' === $options['input']) {
182189
$builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer());
183190
} elseif ('string' === $options['input']) {
184191
$builder->addModelTransformer(new ReversedTransformer(
@@ -194,7 +201,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
194201
));
195202
}
196203

197-
if (\in_array($options['input'], ['datetime', 'datetime_immutable'], true) && null !== $options['model_timezone']) {
204+
if (\in_array($options['input'], ['datetime', 'datetime_immutable', 'date_point'], true) && null !== $options['model_timezone']) {
198205
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
199206
$date = $event->getData();
200207

@@ -283,6 +290,7 @@ public function configureOptions(OptionsResolver $resolver): void
283290
$resolver->setAllowedValues('input', [
284291
'datetime',
285292
'datetime_immutable',
293+
'date_point',
286294
'string',
287295
'timestamp',
288296
'array',

Extension/Core/Type/DateType.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@
1111

1212
namespace Symfony\Component\Form\Extension\Core\Type;
1313

14+
use Symfony\Component\Clock\DatePoint;
1415
use Symfony\Component\Form\AbstractType;
1516
use Symfony\Component\Form\Exception\LogicException;
17+
use Symfony\Component\Form\Extension\Core\DataTransformer\DatePointToDateTimeTransformer;
1618
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
1719
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
1820
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
@@ -156,7 +158,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
156158
;
157159
}
158160

159-
if ('datetime_immutable' === $options['input']) {
161+
if ('date_point' === $options['input']) {
162+
if (!class_exists(DatePoint::class)) {
163+
throw new LogicException(\sprintf('The "symfony/clock" component is required to use "%s" with option "input=date_point". Try running "composer require symfony/clock".', self::class));
164+
}
165+
$builder->addModelTransformer(new DatePointToDateTimeTransformer());
166+
} elseif ('datetime_immutable' === $options['input']) {
160167
$builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer());
161168
} elseif ('string' === $options['input']) {
162169
$builder->addModelTransformer(new ReversedTransformer(
@@ -172,7 +179,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
172179
));
173180
}
174181

175-
if (\in_array($options['input'], ['datetime', 'datetime_immutable'], true) && null !== $options['model_timezone']) {
182+
if (\in_array($options['input'], ['datetime', 'datetime_immutable', 'date_point'], true) && null !== $options['model_timezone']) {
176183
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
177184
$date = $event->getData();
178185

@@ -298,6 +305,7 @@ public function configureOptions(OptionsResolver $resolver): void
298305
$resolver->setAllowedValues('input', [
299306
'datetime',
300307
'datetime_immutable',
308+
'date_point',
301309
'string',
302310
'timestamp',
303311
'array',

Extension/Core/Type/TimeType.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,11 @@
1111

1212
namespace Symfony\Component\Form\Extension\Core\Type;
1313

14+
use Symfony\Component\Clock\DatePoint;
1415
use Symfony\Component\Form\AbstractType;
1516
use Symfony\Component\Form\Exception\InvalidConfigurationException;
1617
use Symfony\Component\Form\Exception\LogicException;
18+
use Symfony\Component\Form\Extension\Core\DataTransformer\DatePointToDateTimeTransformer;
1719
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
1820
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
1921
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
@@ -190,7 +192,12 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
190192
$builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget'], $options['reference_date']));
191193
}
192194

193-
if ('datetime_immutable' === $options['input']) {
195+
if ('date_point' === $options['input']) {
196+
if (!class_exists(DatePoint::class)) {
197+
throw new LogicException(\sprintf('The "symfony/clock" component is required to use "%s" with option "input=date_point". Try running "composer require symfony/clock".', self::class));
198+
}
199+
$builder->addModelTransformer(new DatePointToDateTimeTransformer());
200+
} elseif ('datetime_immutable' === $options['input']) {
194201
$builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer());
195202
} elseif ('string' === $options['input']) {
196203
$builder->addModelTransformer(new ReversedTransformer(
@@ -206,7 +213,7 @@ public function buildForm(FormBuilderInterface $builder, array $options): void
206213
));
207214
}
208215

209-
if (\in_array($options['input'], ['datetime', 'datetime_immutable'], true) && null !== $options['model_timezone']) {
216+
if (\in_array($options['input'], ['datetime', 'datetime_immutable', 'date_point'], true) && null !== $options['model_timezone']) {
210217
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
211218
$date = $event->getData();
212219

@@ -354,6 +361,7 @@ public function configureOptions(OptionsResolver $resolver): void
354361
$resolver->setAllowedValues('input', [
355362
'datetime',
356363
'datetime_immutable',
364+
'date_point',
357365
'string',
358366
'timestamp',
359367
'array',

Tests/Extension/Core/Type/DateTimeTypeTest.php

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

1212
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
1313

14+
use Symfony\Component\Clock\DatePoint;
1415
use Symfony\Component\Form\Exception\LogicException;
1516
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
1617
use Symfony\Component\Form\FormError;
@@ -62,6 +63,37 @@ public function testSubmitDateTime()
6263
$this->assertEquals($dateTime, $form->getData());
6364
}
6465

66+
public function testSubmitDatePoint()
67+
{
68+
$form = $this->factory->create(static::TESTED_TYPE, null, [
69+
'model_timezone' => 'UTC',
70+
'view_timezone' => 'UTC',
71+
'date_widget' => 'choice',
72< 8000 code class="diff-text syntax-highlighted-line addition">+
'years' => [2010],
73+
'time_widget' => 'choice',
74+
'input' => 'date_point',
75+
]);
76+
77+
$input = [
78+
'date' => [
79+
'day' => '2',
80+
'month' => '6',
81+
'year' => '2010',
82+
],
83+
'time' => [
84+
'hour' => '3',
85+
'minute' => '4',
86+
],
87+
];
88+
89+
$form->submit($input);
90+
91+
$this->assertInstanceOf(DatePoint::class, $form->getData());
92+
$datePoint = DatePoint::createFromMutable(new \DateTime('2010-06-02 03:04:00 UTC'));
93+
$this->assertEquals($datePoint, $form->getData());
94+
$this->assertEquals($input, $form->getViewData());
95+
}
96+
6597
public function testSubmitDateTimeImmutable()
6698
{
6799
$form = $this->factory->create(static::TESTED_TYPE, null, [

Tests/Extension/Core/Type/DateTypeTest.php

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

1212
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
1313

14+
use Symfony\Component\Clock\DatePoint;
1415
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1516
use Symfony\Component\Form\Exception\LogicException;
1617
use Symfony\Component\Form\Extension\Core\Type\DateType;
@@ -115,6 +116,27 @@ public function testSubmitFromSingleTextDateTime()
115116
$this->assertEquals('02.06.2010', $form->getViewData());
116117
}
117118

119+
public function testSubmitFromSingleTextDatePoint()
120+
{
121+
if (!class_exists(DatePoint::class)) {
122+
self::markTestSkipped('The DatePoint class is not available.');
123+
}
124+
125+
$form = $this->factory->create(static::TESTED_TYPE, null, [
126+
'html5' => false,
127+
'model_timezone' => 'UTC',
128+
'view_timezone' => 'UTC',
129+
'widget' => 'single_text',
130+
'input' => 'date_point',
131+
]);
132+
133+
$form->submit('2010-06-02');
134+
135+
$this->assertInstanceOf(DatePoint::class, $form->getData());
136+
$this->assertEquals(DatePoint::createFromMutable(new \DateTime('2010-06-02 UTC')), $form->getData());
137+
$this->assertEquals('2010-06-02', $form->getViewData());
138+
}
139+
118140
public function testSubmitFromSingleTextDateTimeImmutable()
119141
{
120142
// we test against "de_DE", so we need the full implementation

Tests/Extension/Core/Type/TimeTypeTest.php

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

1212
namespace Symfony\Component\Form\Tests\Extension\Core\Type;
1313

14+
use Symfony\Component\Clock\DatePoint;
1415
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1516
use Symfony\Component\Form\Exception\InvalidConfigurationException;
1617
use Symfony\Component\Form\Exception\LogicException;
@@ -45,6 +46,32 @@ public function testSubmitDateTime()
4546
$this->assertEquals($input, $form->getViewData());
4647
}
4748

49+
public function testSubmitDatePoint()
50+
{
51+
if (!class_exist 8000 s(DatePoint::class)) {
52+
self::markTestSkipped('The DatePoint class is not available.');
53+
}
54+
55+
$form = $this->factory->create(static::TESTED_TYPE, null, [
56+
'model_timezone' => 'UTC',
57+
'view_timezone' => 'UTC',
58+
'widget' => 'choice',
59+
'input' => 'date_point',
60+
]);
61+
62+
$input = [
63+
'hour' => '3',
64+
'minute' => '4',
65+
];
66+
67+
$form->submit($input);
68+
69+
$this->assertInstanceOf(DatePoint::class, $form->getData());
70+
$datePoint = DatePoint::createFromMutable(new \DateTime('1970-01-01 03:04:00 UTC'));
71+
$this->assertEquals($datePoint, $form->getData());
72+
$this->assertEquals($input, $form->getViewData());
73+
}
74+
4875
public function testSubmitDateTimeImmutable()
4976
{
5077
$form = $this->factory->create(static::TESTED_TYPE, null, [

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"symfony/validator": "^6.4|^7.0",
3232
"symfony/dependency-injection": "^6.4|^7.0",
3333
"symfony/expression-language": "^6.4|^7.0",
34+
"symfony/clock": "^6.4|^7.0",
3435
"symfony/config": "^6.4|^7.0",
3536
"symfony/console": "^6.4|^7.0",
3637
"symfony/html-sanitizer": "^6.4|^7.0",

0 commit comments

Comments
 (0)
0