bug #14895 [Form] Support DateTimeImmutable in transform() (c960657)

This PR was merged into the 2.3 branch.

Discussion
----------

[Form] Support DateTimeImmutable in transform()

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        |

When passing a DateTimeImmutable instance to DateTimeToLocalizedStringTransformer::transform($dateTime), it throws an exception, `TransformationFailedException('Expected a \DateTime.')`.

The method just converts a date-time object into a string, so there is no reason that it should not support all DateTimeInterface implementations.

DateTimeInterface was added in PHP 5.5, so in order to support earlier versions, we need to do instanceof checks for both DateTime and DateTimeInterface. When Symfony requires PHP 5.5 or larger, we can remove the DateTime check and only check for DateTimeInterface.

This was originally submitted as a PR against the 2.7 branch in #14676.

Commits
-------

17346c5 [Form] Support DateTimeImmutable in transform()
This commit is contained in:
Fabien Potencier 2015-06-08 15:59:27 +02:00
commit a48d36ae31
10 changed files with 111 additions and 34 deletions

View File

@ -51,7 +51,7 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
/**
* Transforms a normalized date into a localized date.
*
* @param \DateTime $dateTime Normalized date.
* @param \DateTime|\DateTimeInterface $dateTime A DateTime object
*
* @return array Localized date.
*
@ -72,14 +72,17 @@ class DateTimeToArrayTransformer extends BaseDateTimeTransformer
), array_flip($this->fields));
}
if (!$dateTime instanceof \DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
if (!$dateTime instanceof \DateTime && !$dateTime instanceof \DateTimeInterface) {
throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
}
$dateTime = clone $dateTime;
if ($this->inputTimezone !== $this->outputTimezone) {
if (!$dateTime instanceof \DateTimeImmutable) {
$dateTime = clone $dateTime;
}
try {
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
$dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}

View File

@ -70,7 +70,7 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
/**
* Transforms a normalized date into a localized date string/array.
*
* @param \DateTime $dateTime Normalized date.
* @param \DateTime|\DateTimeInterface $dateTime A DateTime object
*
* @return string|array Localized date string/array.
*
@ -84,17 +84,11 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer
return '';
}
if (!$dateTime instanceof \DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
if (!$dateTime instanceof \DateTime && !$dateTime instanceof \DateTimeInterface) {
throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
}
// convert time to UTC before passing it to the formatter
$dateTime = clone $dateTime;
if ('UTC' !== $this->inputTimezone) {
$dateTime->setTimezone(new \DateTimeZone('UTC'));
}
$value = $this->getIntlDateFormatter()->format((int) $dateTime->format('U'));
$value = $this->getIntlDateFormatter()->format($dateTime->getTimestamp());
if (intl_get_error_code() != 0) {
throw new TransformationFailedException(intl_get_error_message());

View File

@ -27,13 +27,13 @@ class DateTimeToRfc3339Transformer extends BaseDateTimeTransformer
return '';
}
if (!$dateTime instanceof \DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
if (!$dateTime instanceof \DateTime && !$dateTime instanceof \DateTimeInterface) {
throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
}
if ($this->inputTimezone !== $this->outputTimezone) {
$dateTime = clone $dateTime;
$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
$dateTime = $dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
}
return preg_replace('/\+00:00$/', 'Z', $dateTime->format('c'));

View File

@ -90,7 +90,7 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
* Transforms a DateTime object into a date string with the configured format
* and timezone.
*
* @param \DateTime $value A DateTime object
* @param \DateTime|\DateTimeInterface $dateTime A DateTime object
*
* @return string A value as produced by PHP's date() function
*
@ -104,13 +104,16 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
return '';
}
if (!$value instanceof \DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
}
if (!$value instanceof \DateTimeImmutable) {
$value = clone $value;
}
$value = clone $value;
try {
$value->setTimezone(new \DateTimeZone($this->outputTimezone));
$value = $value->setTimezone(new \DateTimeZone($this->outputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}

View File

@ -24,7 +24,7 @@ class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
/**
* Transforms a DateTime object into a timestamp in the configured timezone.
*
* @param \DateTime $value A \DateTime object
* @param \DateTime|\DateTimeInterface $dateTime A DateTime object
*
* @return int A timestamp
*
@ -38,18 +38,11 @@ class DateTimeToTimestampTransformer extends BaseDateTimeTransformer
return;
}
if (!$value instanceof \DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
if (!$value instanceof \DateTime && !$value instanceof \DateTimeInterface) {
throw new TransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
}
$value = clone $value;
try {
$value->setTimezone(new \DateTimeZone($this->outputTimezone));
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e);
}
return (int) $value->format('U');
return $value->getTimestamp();
}
/**

View File

@ -116,6 +116,30 @@ class DateTimeToArrayTransformerTest extends DateTimeTestCase
$this->assertSame($output, $transformer->transform($input));
}
public function testTransformDateTimeImmutable()
{
if (PHP_VERSION_ID < 50500) {
$this->markTestSkipped('DateTimeImmutable was introduced in PHP 5.5.0');
}
$transformer = new DateTimeToArrayTransformer('America/New_York', 'Asia/Hong_Kong');
$input = new \DateTimeImmutable('2010-02-03 04:05:06 America/New_York');
$dateTime = new \DateTimeImmutable('2010-02-03 04:05:06 America/New_York');
$dateTime = $dateTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
$output = array(
'year' => (string) (int) $dateTime->format('Y'),
'month' => (string) (int) $dateTime->format('m'),
'day' => (string) (int) $dateTime->format('d'),
'hour' => (string) (int) $dateTime->format('H'),
'minute' => (string) (int) $dateTime->format('i'),
'second' => (string) (int) $dateTime->format('s'),
);
$this->assertSame($output, $transformer->transform($input));
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
*/

View File

@ -141,6 +141,22 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase
$this->assertEquals('02*2010*03 04|05|06', $transformer->transform($this->dateTime));
}
public function testTransformDateTimeImmutableTimezones()
{
if (PHP_VERSION_ID < 50500) {
$this->markTestSkipped('DateTimeImmutable was introduced in PHP 5.5.0');
}
$transformer = new DateTimeToLocalizedStringTransformer('America/New_York', 'Asia/Hong_Kong');
$input = new \DateTimeImmutable('2010-02-03 04:05:06 America/New_York');
$dateTime = clone $input;
$dateTime = $dateTime->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
$this->assertEquals($dateTime->format('d.m.Y H:i'), $transformer->transform($input));
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
*/

View File

@ -79,6 +79,20 @@ class DateTimeToRfc3339TransformerTest extends DateTimeTestCase
$this->assertSame($to, $transformer->transform(null !== $from ? new \DateTime($from) : null));
}
/**
* @dataProvider transformProvider
*/
public function testTransformDateTimeImmutable($fromTz, $toTz, $from, $to)
{
if (PHP_VERSION_ID < 50500) {
$this->markTestSkipped('DateTimeImmutable was introduced in PHP 5.5.0');
}
$transformer = new DateTimeToRfc3339Transformer($fromTz, $toTz);
$this->assertSame($to, $transformer->transform(null !== $from ? new \DateTimeImmutable($from) : null));
}
/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
*/

View File

@ -97,6 +97,21 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase
$this->assertEquals($output, $transformer->transform($input));
}
public function testTransformDateTimeImmutable()
{
if (PHP_VERSION_ID < 50500) {
$this->markTestSkipped('DateTimeImmutable was introduced in PHP 5.5.0');
}
$transformer = new DateTimeToStringTransformer('Asia/Hong_Kong', 'America/New_York', 'Y-m-d H:i:s');
$input = new \DateTimeImmutable('2010-02-03 12:05:06 America/New_York');
$output = $input->format('Y-m-d H:i:s');
$input = $input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
$this->assertEquals($output, $transformer->transform($input));
}
public function testTransformExpectsDateTime()
{
$transformer = new DateTimeToStringTransformer();

View File

@ -56,6 +56,21 @@ class DateTimeToTimestampTransformerTest extends DateTimeTestCase
$this->assertEquals($output, $transformer->transform($input));
}
public function testTransformDateTimeImmutable()
{
if (PHP_VERSION_ID < 50500) {
$this->markTestSkipped('DateTimeImmutable was introduced in PHP 5.5.0');
}
$transformer = new DateTimeToTimestampTransformer('Asia/Hong_Kong', 'America/New_York');
$input = new \DateTimeImmutable('2010-02-03 04:05:06 America/New_York');
$output = $input->format('U');
$input = $input->setTimezone(new \DateTimeZone('Asia/Hong_Kong'));
$this->assertEquals($output, $transformer->transform($input));
}
public function testTransformExpectsDateTime()
{
$transformer = new DateTimeToTimestampTransformer();