8000 [Form] Add support for \DateTimeImmutable to date types · symfony/symfony@8d60d72 · GitHub
[go: up one dir, main page]

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 8d60d72

Browse files
James Halsalljameshalsall
authored andcommitted
[Form] Add support for \DateTimeImmutable to date types
1 parent 93c0e8a commit 8d60d72

File tree

12 files changed

+213
-80
lines changed

12 files changed

+213
-80
lines changed

src/Symfony/Component/Form/Extension/Core/DataTransformer/BaseDateTimeTransformer.php

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,19 @@ abstract class BaseDateTimeTransformer implements DataTransformerInterface
2929

3030
protected $outputTimezone;
3131

32+
protected $immutable;
33+
3234
/**
3335
* Constructor.
3436
*
3537
* @param string $inputTimezone The name of the input timezone
3638
* @param string $outputTimezone The name of the output timezone
39+
* @param bool $immutable Whether to use \DateTimeImmutable instead of \DateTime
3740
*
3841
* @throws UnexpectedTypeException if a timezone is not a string
3942
* @throws InvalidArgumentException if a timezone is not valid
4043
*/
41-
public function __construct($inputTimezone = null, $outputTimezone = null)
44+
public function __construct($inputTimezone = null, $outputTimezone = null, $immutable = false)
4245
{
4346
if (null !== $inputTimezone && !is_string($inputTimezone)) {
4447
throw new UnexpectedTypeException($inputTimezone, 'string');
@@ -63,5 +66,12 @@ public function __construct($inputTimezone = null, $outputTimezone = null)
6366
} catch (\Exception $e) {
6467
throw new InvalidArgumentException(sprintf('Output timezone is invalid: %s.', $this->outputTimezone), $e->getCode(), $e);
6568
}
69+
70+
$this->immutable = $immutable;
71+
}
72+
73+
protected function getDateTimeClass()
74+
{
75+
return true === $this->immutable ? \DateTimeImmutable::class : \DateTime::class;
6676
}
6777
}

src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
3333
* @param string $outputTimezone The output timezone
3434
* @param array $fields The date fields
3535
* @param bool $pad Whether to use padding
36+
* @param bool $immutable Whether to use \DateTimeImmutable instead of \DateTime
3637
*
3738
* @throws UnexpectedTypeException if a timezone is not a string
3839
*/
39-
public function __construct($inputTimezone = null, $outputTimezone = null, array $fields = null, $pad = false)
40+
public function __construct($inputTimezone = null, $outputTimezone = null, array $fields = null, $pad = false, $immutable = false)
4041
{
41-
parent::__construct($inputTimezone, $outputTimezone);
42+
parent::__construct($inputTimezone, $outputTimezone, $immutable);
4243

4344
if (null === $fields) {
4445
$fields = array('year', 'month', 'day', 'hour', 'minute', 'second');
@@ -108,7 +109,7 @@ public function transform($dateTime)
108109
*
109110
* @param array $value Localized date
110111
*
111-
* @return \DateTime Normalized date
112+
* @return \DateTimeInterface Normalized date
112113
*
113114
* @throws TransformationFailedException If the given value is not an array,
114115
* if the value could not be transformed
@@ -170,7 +171,8 @@ public function reverseTransform($value)
170171
}
171172

172173
try {
173-
$dateTime = new \DateTime(sprintf(
174+
$dateTimeClass = $this->getDateTimeClass();
175+
$dateTime = new $dateTimeClass(sprintf(
174176
'%s-%s-%s %s:%s:%s',
175177
empty($value['year']) ? '1970' : $value['year'],
176178
empty($value['month']) ? '1' : $value['month'],

src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
3838
* @param int $timeFormat The time format
3939
* @param int $calendar One of the \IntlDateFormatter calendar constants
4040
* @param string $pattern A pattern to pass to \IntlDateFormatter
41+
* @param bool $immutable Whether to use \DateTimeImmutable instead of \DateTime
4142
*
4243
* @throws UnexpectedTypeException If a format is not supported or if a timezone is not a string
4344
*/
44-
public function __construct($inputTimezone = null, $outputTimezone = null, $dateFormat = null, $timeFormat = null, $calendar = \IntlDateFormatter::GREGORIAN, $pattern = null)
45+
public function __construct($inputTimezone = null, $outputTimezone = null, $dateFormat = null, $timeFormat = null, $calendar = \IntlDateFormatter::GREGORIAN, $pattern = null, $immutable = false)
4546
{
46-
parent::__construct($inputTimezone, $outputTimezone);
47+
parent::__construct($inputTimezone, $outputTimezone, $immutable);
4748

4849
if (null === $dateFormat) {
4950
$dateFormat = \IntlDateFormatter::MEDIUM;
@@ -101,7 +102,7 @@ public function transform($dateTime)
101102
*
102103
* @param string|array $value Localized date string/array
103104
*
104-
* @return \DateTime Normalized date
105+
* @return \DateTimeInterface Normalized date
105106
*
106107
* @throws TransformationFailedException if the given value is not a string,
107108
* if the date could not be parsed
@@ -126,14 +127,16 @@ public function reverseTransform($value)
126127
throw new TransformationFailedException(intl_get_error_message());
127128
}
128129

130+
$dateTimeClass = $this->getDateTimeClass();
131+
129132
try {
130133
if ($dateOnly) {
131134
// we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight
132-
return new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone));
135+
return new $dateTimeClass(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone));
133136
}
134137

135138
// read timestamp into DateTime object - the formatter delivers a timestamp
136-
$dateTime = new \DateTime(sprintf('@%s', $timestamp));
139+
$dateTime = new $dateTimeClass(sprintf('@%s', $timestamp));
137140
// set timezone separately, as it would be ignored if set via the constructor,
138141
// see http://php.net/manual/en/datetime.construct.php
139142
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));

src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToRfc3339Transformer.php

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public function transform($dateTime)
5353
*
5454
* @param string $rfc3339 Formatted string
5555
*
56-
* @return \DateTime Normalized date
56+
* @return \DateTimeInterface Normalized date
5757
*
5858
* @throws TransformationFailedException If the given value is not a string,
5959
* if the value could not be transformed
@@ -68,8 +68,10 @@ public function reverseTransform($rfc3339)
6868
return;
6969
}
7070

71+
$dateTimeClass = $this->getDateTimeClass();
72+
7173
try {
72-
$dateTime = new \DateTime($rfc3339);
74+
$dateTime = new $dateTimeClass($rfc3339);
7375
} catch (\Exception $e) {
7476
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
7577
}

src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,13 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
5858
* @param string $outputTimezone The name of the output timezone
5959
* @param string $format The date format
6060
* @param bool $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format
61+
* @param bool $immutable Whether to use \DateTimeImmutable instead of \DateTime
6162
*
6263
* @throws UnexpectedTypeException if a timezone is not a string
6364
*/
64-
public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = true)
65+
public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = true, $immutable = false)
6566
{
66-
parent::__construct($inputTimezone, $outputTimezone);
67+
parent::__construct($inputTimezone, $outputTimezone, $immutable);
6768

6869
$this->generateFormat = $this->parseFormat = $format;
6970
$this->parseUsingPipe = $parseUsingPipe || null === $parseUsingPipe;
@@ -115,7 +116,7 @@ public function transform($dateTime)
115116
*
116117
* @param string $value A value as produced by PHP's date() function
117118
*
118-
* @return \DateTime An instance of \DateTime
119+
* @return \DateTimeInterface An instance of \DateTime
119120
*
120121
* @throws TransformationFailedException If the given value is not a string,
121122
* or could not be transformed
@@ -130,10 +131,12 @@ public function reverseTransform($value)
130131
throw new TransformationFailedException('Expected a string.');
131132
}
132133

134+
$dateTimeClass = $this->getDateTimeClass();
135+
133136
$outputTz = new \DateTimeZone($this->outputTimezone);
134-
$dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
137+
$dateTime = $dateTimeClass::createFromFormat($this->parseFormat, $value, $outputTz);
135138

136-
$lastErrors = \DateTime::getLastErrors();
139+
$lastErrors = $dateTimeClass::getLastErrors();
137140

138141
if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {
139142
throw new TransformationFailedException(

src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8787
$timeFormat = self::DEFAULT_TIME_FORMAT;
8888
$calendar = \IntlDateFormatter::GREGORIAN;
8989
$pattern = is_string($options['format']) ? $options['format'] : null;
90+
$immutable = 'datetimeimmutable' === $options['input'];
9091

9192
if (!in_array($dateFormat, self::$acceptedFormats, true)) {
9293
throw new InvalidOptionsException('The "date_format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
@@ -96,7 +97,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
9697
if (self::HTML5_FORMAT === $pattern) {
9798
$builder->addViewTransformer(new DateTimeToRfc3339Transformer(
9899
$options['model_timezone'],
99-
$options['view_timezone']
100+
$options['view_timezone'],
101+
$immutable
100102
));
101103
} else {
102104
$builder->addViewTransformer(new DateTimeToLocalizedStringTransformer(
@@ -105,7 +107,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
105107
$dateFormat,
106108
$timeFormat,
107109
$calendar,
108-
$pattern
110+
$pattern,
111+
$immutable
109112
));
110113
}
111114
} else {
@@ -155,7 +158,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
155158

156159
$builder
157160
->addViewTransformer(new DataTransformerChain(array(
158-
new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts),
161+
new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, false, $immutable),
159162
new ArrayToPartsTransformer(array(
160163
'date' => $dateParts,
161164
'time' => $timeParts,
@@ -255,6 +258,7 @@ public function configureOptions(OptionsResolver $resolver)
255258

256259
$resolver->setAllowedValues('input', array(
257260
'datetime',
261+
'datetimeimmutable',
258262
'string',
259263
'timestamp',
260264
'array',

src/Symfony/Component/Form/Extension/Core/Type/DateType.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5151
$timeFormat = \IntlDateFormatter::NONE;
5252
$calendar = \IntlDateFormatter::GREGORIAN;
5353
$pattern = is_string($options['format']) ? $options['format'] : null;
54+
$immutable = 'datetimeimmutable' === $options['input'];
5455

5556
if (!in_array($dateFormat, self::$acceptedFormats, true)) {
5657
throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.');
@@ -67,7 +68,8 @@ public function buildForm(FormBuilderInterface $builder, array $options)
6768
$dateFormat,
6869
$timeFormat,
6970
$calendar,
70-
$pattern
71+
$pattern,
72+
$immutable
7173
));
7274
} else {
7375
$yearOptions = $monthOptions = $dayOptions = array(
@@ -113,7 +115,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
113115
->add('month', se 802E lf::$widgets[$options['widget']], $monthOptions)
114116
->add('day', self::$widgets[$options['widget']], $dayOptions)
115117
->addViewTransformer(new DateTimeToArrayTransformer(
116-
$options['model_timezone'], $options['view_timezone'], array('year', 'month', 'day')
118+
$options['model_timezone'], $options['view_timezone'], array('year', 'month', 'day'), false, $immutable
117119
))
118120
->setAttribute('formatter', $formatter)
119121
;
@@ -254,6 +256,7 @@ public function configureOptions(OptionsResolver $resolver)
254256

255257
$resolver->setAllowedValues('input', array(
256258
'datetime',
259+
'datetimeimmutable',
257260
'string',
258261
'timestamp',
259262
'array',

src/Symfony/Component/Form/Extension/Core/Type/TimeType.php

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ public function buildForm(FormBuilderInterface $builder, array $options)
5252
$parts[] = 'second';
5353
}
5454

55+
$immutable = 'datetimeimmutable' === $options['input'];
56+
5557
if ('single_text' === $options['widget']) {
56-
$builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format));
58+
$builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format, true, $immutable));
5759
} else {
5860
$hourOptions = $minuteOptions = $secondOptions = array(
5961
'error_bubbling' => true,
@@ -117,7 +119,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
117119
$builder->add('second', self::$widgets[$options['widget']], $secondOptions);
118120
}
119121

120-
$builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget']));
122+
$builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget'], $immutable));
121123
}
122124

123125
if ('string' === $options['input']) {
@@ -239,6 +241,7 @@ public function configureOptions(OptionsResolver $resolver)
239241

240242
$resolver->setAllowedValues('input', array(
241243
'datetime',
244+
'datetimeimmutable',
242245
'string',
243246
'timestamp',
244247
'array',

src/Symfony/Component/Form/Test/TypeTestCase.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ protected function setUp()
3434
$this->builder = new FormBuilder(null, null, $this->dispatcher, $this->factory);
3535
}
3636

37-
public static function assertDateTimeEquals(\DateTime $expected, \DateTime $actual)
37+
public static function assertDateTimeEquals(\DateTimeInterface $expected, \DateTimeInterface $actual)
3838
{
3939
self::assertEquals($expected->format('c'), $actual->format('c'));
4040
}

0 commit comments

Comments
 (0)
0