Skip to content

Commit

Permalink
feature #25582 [Form] Support \DateTimeImmutable (vudaltsov)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 4.1-dev branch (closes #25582).

Discussion
----------

[Form] Support \DateTimeImmutable

| Q             | A
| ------------- | ---
| Branch?       | master
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #9508
| License       | MIT
| Doc PR        | symfony/symfony-docs#8920

This PR implements `input=datetime_immutable`. Replaces #25273.

Commits
-------

034f8b2 [Form] Support \DateTimeImmutable
  • Loading branch information
fabpot committed Feb 7, 2018
2 parents 0c128f8 + 034f8b2 commit ec89ac8
Show file tree
Hide file tree
Showing 9 changed files with 255 additions and 3 deletions.
5 changes: 5 additions & 0 deletions src/Symfony/Component/Form/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========

4.1.0
-----

* added `input=datetime_immutable` to DateType, TimeType, DateTimeType

4.0.0
-----

Expand Down
@@ -0,0 +1,67 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Form\Extension\Core\DataTransformer;

use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

/**
* Transforms between a DateTimeImmutable object and a DateTime object.
*
* @author Valentin Udaltsov <udaltsov.valentin@gmail.com>
*/
final class DateTimeImmutableToDateTimeTransformer implements DataTransformerInterface
{
/**
* Transforms a DateTimeImmutable into a DateTime object.
*
* @param \DateTimeImmutable|null $value A DateTimeImmutable object
*
* @return \DateTime|null A \DateTime object
*
* @throws TransformationFailedException If the given value is not a \DateTimeImmutable
*/
public function transform($value)
{
if (null === $value) {
return null;
}

if (!$value instanceof \DateTimeImmutable) {
throw new TransformationFailedException('Expected a \DateTimeImmutable.');
}

return \DateTime::createFromFormat(\DateTime::RFC3339, $value->format(\DateTime::RFC3339));
}

/**
* Transforms a DateTime object into a DateTimeImmutable object.
*
* @param \DateTime|null $value A DateTime object
*
* @return \DateTimeImmutable|null A DateTimeImmutable object
*
* @throws TransformationFailedException If the given value is not a \DateTime
*/
public function reverseTransform($value)
{
if (null === $value) {
return null;
}

if (!$value instanceof \DateTime) {
throw new TransformationFailedException('Expected a \DateTime.');
}

return \DateTimeImmutable::createFromMutable($value);
}
}
Expand Up @@ -18,6 +18,7 @@
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\ReversedTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
Expand Down Expand Up @@ -165,7 +166,9 @@ public function buildForm(FormBuilderInterface $builder, array $options)
;
}

if ('string' === $options['input']) {
if ('datetime_immutable' === $options['input']) {
$builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer());
} elseif ('string' === $options['input']) {
$builder->addModelTransformer(new ReversedTransformer(
new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'])
));
Expand Down Expand Up @@ -254,6 +257,7 @@ public function configureOptions(OptionsResolver $resolver)

$resolver->setAllowedValues('input', array(
'datetime',
'datetime_immutable',
'string',
'timestamp',
'array',
Expand Down
6 changes: 5 additions & 1 deletion src/Symfony/Component/Form/Extension/Core/Type/DateType.php
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
Expand Down Expand Up @@ -123,7 +124,9 @@ class_exists('IntlTimeZone', false) ? \IntlTimeZone::createDefault() : null,
;
}

if ('string' === $options['input']) {
if ('datetime_immutable' === $options['input']) {
$builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer());
} elseif ('string' === $options['input']) {
$builder->addModelTransformer(new ReversedTransformer(
new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'Y-m-d')
));
Expand Down Expand Up @@ -258,6 +261,7 @@ public function configureOptions(OptionsResolver $resolver)

$resolver->setAllowedValues('input', array(
'datetime',
'datetime_immutable',
'string',
'timestamp',
'array',
Expand Down
6 changes: 5 additions & 1 deletion src/Symfony/Component/Form/Extension/Core/Type/TimeType.php
Expand Up @@ -18,6 +18,7 @@
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\ReversedTransformer;
use Symfony\Component\Form\Exception\InvalidConfigurationException;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
Expand Down Expand Up @@ -133,7 +134,9 @@ public function buildForm(FormBuilderInterface $builder, array $options)
$builder->addViewTransformer(new DateTimeToArrayTransformer($options['model_timezone'], $options['view_timezone'], $parts, 'text' === $options['widget']));
}

if ('string' === $options['input']) {
if ('datetime_immutable' === $options['input']) {
$builder->addModelTransformer(new DateTimeImmutableToDateTimeTransformer());
} elseif ('string' === $options['input']) {
$builder->addModelTransformer(new ReversedTransformer(
new DateTimeToStringTransformer($options['model_timezone'], $options['model_timezone'], 'H:i:s')
));
Expand Down Expand Up @@ -252,6 +255,7 @@ public function configureOptions(OptionsResolver $resolver)

$resolver->setAllowedValues('input', array(
'datetime',
'datetime_immutable',
'string',
'timestamp',
'array',
Expand Down
@@ -0,0 +1,76 @@
<?php

/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace Symfony\Component\Form\Tests\Extension\Core\DataTransformer;

use PHPUnit\Framework\TestCase;
use Symfony\Component\Form\Extension\Core\DataTransformer\DateTimeImmutableToDateTimeTransformer;

class DateTimeImmutableToDateTimeTransformerTest extends TestCase
{
public function testTransform()
{
$transformer = new DateTimeImmutableToDateTimeTransformer();

$input = new \DateTimeImmutable('2010-02-03 04:05:06 UTC');
$expectedOutput = new \DateTime('2010-02-03 04:05:06 UTC');
$actualOutput = $transformer->transform($input);

$this->assertInstanceOf(\DateTime::class, $actualOutput);
$this->assertEquals($expectedOutput, $actualOutput);
}

public function testTransformEmpty()
{
$transformer = new DateTimeImmutableToDateTimeTransformer();

$this->assertNull($transformer->transform(null));
}

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage Expected a \DateTimeImmutable.
*/
public function testTransformFail()
{
$transformer = new DateTimeImmutableToDateTimeTransformer();
$transformer->transform(new \DateTime());
}

public function testReverseTransform()
{
$transformer = new DateTimeImmutableToDateTimeTransformer();

$input = new \DateTime('2010-02-03 04:05:06 UTC');
$expectedOutput = new \DateTimeImmutable('2010-02-03 04:05:06 UTC');
$actualOutput = $transformer->reverseTransform($input);

$this->assertInstanceOf(\DateTimeImmutable::class, $actualOutput);
$this->assertEquals($expectedOutput, $actualOutput);
}

public function testReverseTransformEmpty()
{
$transformer = new DateTimeImmutableToDateTimeTransformer();

$this->assertNull($transformer->reverseTransform(null));
}

/**
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
* @expectedExceptionMessage Expected a \DateTime.
*/
public function testReverseTransformFail()
{
$transformer = new DateTimeImmutableToDateTimeTransformer();
$transformer->reverseTransform(new \DateTimeImmutable());
}
}
Expand Up @@ -52,6 +52,34 @@ public function testSubmitDateTime()
$this->assertEquals($dateTime, $form->getData());
}

public function testSubmitDateTimeImmutable()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
'model_timezone' => 'UTC',
'view_timezone' => 'UTC',
'date_widget' => 'choice',
'years' => array(2010),
'time_widget' => 'choice',
'input' => 'datetime_immutable',
));

$form->submit(array(
'date' => array(
'day' => '2',
'month' => '6',
'year' => '2010',
),
'time' => array(
'hour' => '3',
'minute' => '4',
),
));

$dateTime = new \DateTimeImmutable('2010-06-02 03:04:00 UTC');

$this->assertEquals($dateTime, $form->getData());
}

public function testSubmitString()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
Expand Down Expand Up @@ -219,6 +247,26 @@ public function testSubmitDifferentTimezonesDateTime()
$this->assertEquals('2010-06-02T03:04:00-10:00', $form->getViewData());
}

public function testSubmitDifferentTimezonesDateTimeImmutable()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
'model_timezone' => 'America/New_York',
'view_timezone' => 'Pacific/Tahiti',
'widget' => 'single_text',
'input' => 'datetime_immutable',
));

$outputTime = new \DateTimeImmutable('2010-06-02 03:04:00 Pacific/Tahiti');

$form->submit('2010-06-02T03:04:00-10:00');

$outputTime = $outputTime->setTimezone(new \DateTimeZone('America/New_York'));

$this->assertInstanceOf(\DateTimeImmutable::class, $form->getData());
$this->assertEquals($outputTime, $form->getData());
$this->assertEquals('2010-06-02T03:04:00-10:00', $form->getViewData());
}

public function testSubmitStringSingleText()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
Expand Down
Expand Up @@ -105,6 +105,28 @@ public function testSubmitFromSingleTextDateTime()
$this->assertEquals('02.06.2010', $form->getViewData());
}

public function testSubmitFromSingleTextDateTimeImmutable()
{
// we test against "de_DE", so we need the full implementation
IntlTestHelper::requireFullIntl($this, false);

\Locale::setDefault('de_DE');

$form = $this->factory->create(static::TESTED_TYPE, null, array(
'format' => \IntlDateFormatter::MEDIUM,
'model_timezone' => 'UTC',
'view_timezone' => 'UTC',
'widget' => 'single_text',
'input' => 'datetime_immutable',
));

$form->submit('2.6.2010');

$this->assertInstanceOf(\DateTimeImmutable::class, $form->getData());
$this->assertEquals(new \DateTimeImmutable('2010-06-02 UTC'), $form->getData());
$this->assertEquals('02.06.2010', $form->getViewData());
}

public function testSubmitFromSingleTextString()
{
// we test against "de_DE", so we need the full implementation
Expand Down
Expand Up @@ -39,6 +39,28 @@ public function testSubmitDateTime()
$this->assertEquals($input, $form->getViewData());
}

public function testSubmitDateTimeImmutable()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
'model_timezone' => 'UTC',
'view_timezone' => 'UTC',
'input' => 'datetime_immutable',
));

$input = array(
'hour' => '3',
'minute' => '4',
);

$form->submit($input);

$dateTime = new \DateTimeImmutable('1970-01-01 03:04:00 UTC');

$this->assertInstanceOf(\DateTimeImmutable::class, $form->getData());
$this->assertEquals($dateTime, $form->getData());
$this->assertEquals($input, $form->getViewData());
}

public function testSubmitString()
{
$form = $this->factory->create(static::TESTED_TYPE, null, array(
Expand Down

0 comments on commit ec89ac8

Please sign in to comment.