Skip to content

Commit d65726b

Browse files
committed
deprecate using date and time types with date objects with not-matching timezones
1 parent 6217347 commit d65726b

File tree

7 files changed

+154
-3
lines changed

7 files changed

+154
-3
lines changed

CHANGELOG.md

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

4+
6.4
5+
---
6+
7+
* Deprecate using `DateTime` or `DateTimeImmutable` model data with a different timezone than configured with the
8+
`model_timezone` option in `DateType`, `DateTimeType`, and `TimeType`
9+
410
6.3
511
---
612

Extension/Core/Type/DateTimeType.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
2323
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
2424
use Symfony\Component\Form\FormBuilderInterface;
25+
use Symfony\Component\Form\FormEvent;
26+
use Symfony\Component\Form\FormEvents;
2527
use Symfony\Component\Form\FormInterface;
2628
use Symfony\Component\Form\FormView;
2729
use Symfony\Component\Form\ReversedTransformer;
@@ -194,6 +196,21 @@ public function buildForm(FormBuilderInterface $builder, array $options)
194196
new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts)
195197
));
196198
}
199+
200+
if (\in_array($options['input'], ['datetime', 'datetime_immutable'], true) && null !== $options['model_timezone']) {
201+
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
202+
$date = $event->getData();
203+
204+
if (!$date instanceof \DateTimeInterface) {
205+
return;
206+
}
207+
208+
if ($date->getTimezone()->getName() !== $options['model_timezone']) {
209+
trigger_deprecation('symfony/form', '6.4', sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is deprecated.', $date::class, $date->getTimezone()->getName(), $options['model_timezone']));
210+
// throw new LogicException(sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', $date::class, $date->getTimezone()->getName(), $options['model_timezone']));
211+
}
212+
});
213+
}
197214
}
198215

199216
/**

Extension/Core/Type/DateType.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
2020
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
2121
use Symfony\Component\Form\FormBuilderInterface;
22+
use Symfony\Component\Form\FormEvent;
23+
use Symfony\Component\Form\FormEvents;
2224
use Symfony\Component\Form\FormInterface;
2325
use Symfony\Component\Form\FormView;
2426
use Symfony\Component\Form\ReversedTransformer;
@@ -178,6 +180,21 @@ class_exists(\IntlTimeZone::class, false) ? \IntlTimeZone::createDefault() : nul
178180
new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], ['year', 'month', 'day'])
179181
));
180182
}
183+
184+
if (\in_array($options['input'], ['datetime', 'datetime_immutable'], true) && null !== $options['model_timezone']) {
185+
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
186+
$date = $event->getData();
187+
188+
if (!$date instanceof \DateTimeInterface) {
189+
return;
190+
}
191+
192+
if ($date->getTimezone()->getName() !== $options['model_timezone']) {
193+
trigger_deprecation('symfony/form', '6.4', sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is deprecated.', $date::class, $date->getTimezone()->getName(), $options['model_timezone']));
194+
// throw new LogicException(sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', $date::class, $date->getTimezone()->getName(), $options['model_timezone']));
195+
}
196+
});
197+
}
181198
}
182199

183200
/**

Extension/Core/Type/TimeType.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,21 @@ public function buildForm(FormBuilderInterface $builder, array $options)
208208
new DateTimeToArrayTransformer($options['model_timezone'], $options['model_timezone'], $parts, 'text' === $options['widget'], $options['reference_date'])
209209
));
210210
}
211+
212+
if (\in_array($options['input'], ['datetime', 'datetime_immutable'], true) && null !== $options['model_timezone']) {
213+
$builder->addEventListener(FormEvents::POST_SET_DATA, static function (FormEvent $event) use ($options): void {
214+
$date = $event->getData();
215+
216+
if (!$date instanceof \DateTimeInterface) {
217+
return;
218+
}
219+
220+
if ($date->getTimezone()->getName() !== $options['model_timezone']) {
221+
trigger_deprecation('symfony/form', '6.4', sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is deprecated.', $date::class, $date->getTimezone()->getName(), $options['model_timezone']));
222+
// throw new LogicException(sprintf('Using a "%s" instance with a timezone ("%s") not matching the configured model timezone "%s" is not supported.', $date::class, $date->getTimezone()->getName(), $options['model_timezone']));
223+
}
224+
});
225+
}
211226
}
212227

213228
/**

Tests/Extension/Core/Type/DateTimeTypeTest.php

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

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

14+
use Symfony\Bridge\PhpUnit\ExpectDeprecationTrait;
1415
use Symfony\Component\Form\FormError;
1516
use Symfony\Component\Form\FormInterface;
1617

1718
class DateTimeTypeTest extends BaseTypeTestCase
1819
{
20+
use ExpectDeprecationTrait;
21+
1922
public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\DateTimeType';
2023

2124
private $defaultLocale;
@@ -154,7 +157,7 @@ public function testSubmitWithoutMinutes()
154157
'with_minutes' => false,
155158
]);
156159

157-
$form->setData(new \DateTime());
160+
$form->setData(new \DateTime('now', new \DateTimeZone('UTC')));
158161

159162
$input = [
160163
'date' => [
@@ -184,7 +187,7 @@ public function testSubmitWithSeconds()
184187
'with_seconds' => true,
185188
]);
186189

187-
$form->setData(new \DateTime());
190+
$form->setData(new \DateTime('now', new \DateTimeZone('UTC')));
188191

189192
$input = [
190193
'date' => [
@@ -748,6 +751,35 @@ public function testSubmitStringWithCustomInputFormat()
748751
$this->assertSame('14/01/2018 21:29:00 +00:00', $form->getData());
749752
}
750753

754+
/**
755+
* @group legacy
756+
*/
757+
public function testDateTimeInputTimezoneNotMatchingModelTimezone()
758+
{
759+
$this->expectDeprecation('Since symfony/form 6.4: Using a "DateTime" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is deprecated.');
760+
// $this->expectException(LogicException::class);
761+
// $this->expectExceptionMessage('Using a "DateTime" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is not supported.');
762+
763+
$this->factory->create(static::TESTED_TYPE, new \DateTime('now', new \DateTimeZone('UTC')), [
764+
'model_timezone' => 'Europe/Berlin',
765+
]);
766+
}
767+
768+
/**
769+
* @group legacy
770+
*/
771+
public function testDateTimeImmutableInputTimezoneNotMatchingModelTimezone()
772+
{
773+
$this->expectDeprecation('Since symfony/form 6.4: Using a "DateTimeImmutable" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is deprecated.');
774+
// $this->expectException(LogicException::class);
775+
// $this->expectExceptionMessage('Using a "DateTimeImmutable" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is not supported.');
776+
777+
$this->factory->create(static::TESTED_TYPE, new \DateTimeImmutable('now', new \DateTimeZone('UTC')), [
778+
'input' => 'datetime_immutable',
779+
'model_timezone' => 'Europe/Berlin',
780+
]);
781+
}
782+
751783
protected function getTestOptions(): array
752784
{
753785
return ['widget' => 'choice'];

Tests/Extension/Core/Type/DateTypeTest.php

Lines changed: 33 additions & 1 deletion
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\Bridge\PhpUnit\ExpectDeprecationTrait;
1415
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1516
use Symfony\Component\Form\FormError;
1617
use Symfony\Component\Form\FormInterface;
@@ -19,6 +20,8 @@
1920

2021
class DateTypeTest extends BaseTypeTestCase
2122
{
23+
use ExpectDeprecationTrait;
24+
2225
public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\DateType';
2326

2427
private $defaultTimezone;
@@ -654,7 +657,7 @@ public function testIsSynchronizedReturnsTrueIfChoiceAndCompletelyEmpty()
654657

655658
public function testIsSynchronizedReturnsTrueIfChoiceAndCompletelyFilled()
656659
{
657-
$form = $this->factory->create(static::TESTED_TYPE, new \DateTime(), [
660+
$form = $this->factory->create(static::TESTED_TYPE, new \DateTime('now', new \DateTimeZone('UTC')), [
658661
'model_timezone' => 'UTC',
659662
'view_timezone' => 'UTC',
660663
'widget' => 'choice',
@@ -1112,6 +1115,35 @@ public function testSubmitStringWithCustomInputFormat()
11121115
$this->assertSame('14/01/2018', $form->getData());
11131116
}
11141117

1118+
/**
1119+
* @group legacy
1120+
*/
1121+
public function testDateTimeInputTimezoneNotMatchingModelTimezone()
1122+
{
1123+
$this->expectDeprecation('Since symfony/form 6.4: Using a "DateTime" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is deprecated.');
1124+
// $this->expectException(LogicException::class);
1125+
// $this->expectExceptionMessage('Using a "DateTime" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is not supported.');
1126+
1127+
$this->factory->create(static::TESTED_TYPE, new \DateTime('now', new \DateTimeZone('UTC')), [
1128+
'model_timezone' => 'Europe/Berlin',
1129+
]);
1130+
}
1131+
1132+
/**
1133+
* @group legacy
1134+
*/
1135+
public function testDateTimeImmutableInputTimezoneNotMatchingModelTimezone()
1136+
{
1137+
$this->expectDeprecation('Since symfony/form 6.4: Using a "DateTimeImmutable" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is deprecated.');
1138+
// $this->expectException(LogicException::class);
1139+
// $this->expectExceptionMessage('Using a "DateTimeImmutable" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is not supported.');
1140+
1141+
$this->factory->create(static::TESTED_TYPE, new \DateTimeImmutable('now', new \DateTimeZone('UTC')), [
1142+
'input' => 'datetime_immutable',
1143+
'model_timezone' => 'Europe/Berlin',
1144+
]);
1145+
}
1146+
11151147
protected function getTestOptions(): array
11161148
{
11171149
return ['widget' => 'choice'];

Tests/Extension/Core/Type/TimeTypeTest.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\Bridge\PhpUnit\ExpectDeprecationTrait;
1415
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
1516
use Symfony\Component\Form\Exception\InvalidConfigurationException;
1617
use Symfony\Component\Form\Exception\LogicException;
@@ -20,6 +21,8 @@
2021

2122
class TimeTypeTest extends BaseTypeTestCase
2223
{
24+
use ExpectDeprecationTrait;
25+
2326
public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\TimeType';
2427

2528
public function testSubmitDateTime()
@@ -1161,6 +1164,35 @@ public static function provideEmptyData()
11611164
];
11621165
}
11631166

1167+
/**
1168+
* @group legacy
1169+
*/
1170+
public function testDateTimeInputTimezoneNotMatchingModelTimezone()
1171+
{
1172+
$this->expectDeprecation('Since symfony/form 6.4: Using a "DateTime" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is deprecated.');
1173+
// $this->expectException(LogicException::class);
1174+
// $this->expectExceptionMessage('Using a "DateTime" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is not supported.');
1175+
1176+
$this->factory->create(static::TESTED_TYPE, new \DateTime('now', new \DateTimeZone('UTC')), [
1177+
'model_timezone' => 'Europe/Berlin',
1178+
]);
1179+
}
1180+
1181+
/**
1182+
* @group legacy
1183+
*/
1184+
public function testDateTimeImmutableInputTimezoneNotMatchingModelTimezone()
1185+
{
1186+
$this->expectDeprecation('Since symfony/form 6.4: Using a "DateTimeImmutable" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is deprecated.');
1187+
// $this->expectException(LogicException::class);
1188+
// $this->expectExceptionMessage('Using a "DateTimeImmutable" instance with a timezone ("UTC") not matching the configured model timezone "Europe/Berlin" is not supported.');
1189+
1190+
$this->factory->create(static::TESTED_TYPE, new \DateTimeImmutable('now', new \DateTimeZone('UTC')), [
1191+
'input' => 'datetime_immutable',
1192+
'model_timezone' => 'Europe/Berlin',
1193+
]);
1194+
}
1195+
11641196
protected function getTestOptions(): array
11651197
{
11661198
return ['widget' => 'choice'];

0 commit comments

Comments
 (0)