Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

Commitcd93b98

Browse files
franzwildingnicolas-grekas
authored andcommitted
[Form] Fix DateTimeType html5 input format
1 parent528eef3 commitcd93b98

File tree

6 files changed

+267
-25
lines changed

6 files changed

+267
-25
lines changed
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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+
namespaceSymfony\Component\Form\Extension\Core\DataTransformer;
13+
14+
useSymfony\Component\Form\Exception\TransformationFailedException;
15+
16+
/**
17+
* @author Franz Wilding <franz.wilding@me.com>
18+
* @author Bernhard Schussek <bschussek@gmail.com>
19+
*/
20+
class DateTimeToHtml5DateTimeLocalTransformerextends BaseDateTimeTransformer
21+
{
22+
/**
23+
* Transforms a normalized date into a localized date without trailing timezone.
24+
*
25+
* According to the HTML standard, the input string of a datetime-local
26+
* input is a RFC3339 date followed by 'T', followed by a RFC3339 time.
27+
* http://w3c.github.io/html-reference/datatypes.html#form.data.datetime-local
28+
*
29+
* @param \DateTime|\DateTimeInterface $dateTime A DateTime object
30+
*
31+
* @return string The formatted date
32+
*
33+
* @throws TransformationFailedException If the given value is not an
34+
* instance of \DateTime or \DateTimeInterface
35+
*/
36+
publicfunctiontransform($dateTime)
37+
{
38+
if (null ===$dateTime) {
39+
return'';
40+
}
41+
42+
if (!$dateTimeinstanceof \DateTime && !$dateTimeinstanceof \DateTimeInterface) {
43+
thrownewTransformationFailedException('Expected a \DateTime or \DateTimeInterface.');
44+
}
45+
46+
if ($this->inputTimezone !==$this->outputTimezone) {
47+
if (!$dateTimeinstanceof \DateTimeImmutable) {
48+
$dateTime =clone$dateTime;
49+
}
50+
51+
$dateTime =$dateTime->setTimezone(new \DateTimeZone($this->outputTimezone));
52+
}
53+
54+
returnpreg_replace('/\+00:00$/','',$dateTime->format('c'));
55+
}
56+
57+
/**
58+
* Transforms a formatted datetime-local string into a normalized date.
59+
*
60+
* @param string $dateTimeLocal Formatted string
61+
*
62+
* @return \DateTime Normalized date
63+
*
64+
* @throws TransformationFailedException If the given value is not a string,
65+
* if the value could not be transformed
66+
*/
67+
publicfunctionreverseTransform($dateTimeLocal)
68+
{
69+
if (!\is_string($dateTimeLocal)) {
70+
thrownewTransformationFailedException('Expected a string.');
71+
}
72+
73+
if ('' ===$dateTimeLocal) {
74+
return;
75+
}
76+
77+
if ('Z' !==substr($dateTimeLocal, -1)) {
78+
$dateTimeLocal .='Z';
79+
}
80+
81+
try {
82+
$dateTime =new \DateTime($dateTimeLocal);
83+
}catch (\Exception$e) {
84+
thrownewTransformationFailedException($e->getMessage(),$e->getCode(),$e);
85+
}
86+
87+
if ($this->inputTimezone !==$dateTime->getTimezone()->getName()) {
88+
$dateTime->setTimezone(new \DateTimeZone($this->inputTimezone));
89+
}
90+
91+
if (preg_match('/(\d{4})-(\d{2})-(\d{2})/',$dateTimeLocal,$matches)) {
92+
if (!checkdate($matches[2],$matches[3],$matches[1])) {
93+
thrownewTransformationFailedException(sprintf(
94+
'The date "%s-%s-%s" is not a valid date.',
95+
$matches[1],
96+
$matches[2],
97+
$matches[3]
98+
));
99+
}
100+
}
101+
102+
return$dateTime;
103+
}
104+
}

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

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@
1515
useSymfony\Component\Form\Extension\Core\DataTransformer\ArrayToPartsTransformer;
1616
useSymfony\Component\Form\Extension\Core\DataTransformer\DataTransformerChain;
1717
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToArrayTransformer;
18+
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToHTML5DateTimeLocalTransformer;
1819
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToLocalizedStringTransformer;
19-
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToRfc3339Transformer;
2020
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToStringTransformer;
2121
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToTimestampTransformer;
2222
useSymfony\Component\Form\FormBuilderInterface;
@@ -33,21 +33,8 @@ class DateTimeType extends AbstractType
3333
constDEFAULT_TIME_FORMAT = \IntlDateFormatter::MEDIUM;
3434

3535
/**
36-
* This is not quite the HTML5 format yet, because ICU lacks the
37-
* capability of parsing and generating RFC 3339 dates.
38-
*
39-
* For more information see:
40-
*
41-
* http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax
42-
* https://www.w3.org/TR/html5/sec-forms.html#local-date-and-time-state-typedatetimelocal
43-
* http://tools.ietf.org/html/rfc3339
44-
*
45-
* An ICU ticket was created:
46-
* http://icu-project.org/trac/ticket/9421
47-
*
48-
* It was supposedly fixed, but is not available in all PHP installations
49-
* yet. To temporarily circumvent this issue, DateTimeToRfc3339Transformer
50-
* is used when the format matches this constant.
36+
* The HTML5 datetime-local format as defined in
37+
* http://w3c.github.io/html-reference/datatypes.html#form.data.datetime-local.
5138
*/
5239
constHTML5_FORMAT ="yyyy-MM-dd'T'HH:mm:ss";
5340

@@ -88,7 +75,7 @@ public function buildForm(FormBuilderInterface $builder, array $options)
8875

8976
if ('single_text' ===$options['widget']) {
9077
if (self::HTML5_FORMAT ===$pattern) {
91-
$builder->addViewTransformer(newDateTimeToRfc3339Transformer(
78+
$builder->addViewTransformer(newDateTimeToHtml5DateTimeLocalTransformer(
9279
$options['model_timezone'],
9380
$options['view_timezone']
9481
));

‎src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1603,7 +1603,7 @@ public function testDateTimeWithWidgetSingleText()
16031603
[@type="datetime-local"]
16041604
[@name="name"]
16051605
[@class="my&class form-control"]
1606-
[@value="2011-02-03T04:05:06Z"]
1606+
[@value="2011-02-03T04:05:06"]
16071607
'
16081608
);
16091609
}
@@ -1624,7 +1624,7 @@ public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
16241624
[@type="datetime-local"]
16251625
[@name="name"]
16261626
[@class="my&class form-control"]
1627-
[@value="2011-02-03T04:05:06Z"]
1627+
[@value="2011-02-03T04:05:06"]
16281628
'
16291629
);
16301630
}

‎src/Symfony/Component/Form/Tests/AbstractLayoutTest.php‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1502,7 +1502,7 @@ public function testDateTimeWithWidgetSingleText()
15021502
'/input
15031503
[@type="datetime-local"]
15041504
[@name="name"]
1505-
[@value="2011-02-03T04:05:06Z"]
1505+
[@value="2011-02-03T04:05:06"]
15061506
'
15071507
);
15081508
}
@@ -1522,7 +1522,7 @@ public function testDateTimeWithWidgetSingleTextIgnoreDateAndTimeWidgets()
15221522
'/input
15231523
[@type="datetime-local"]
15241524
[@name="name"]
1525-
[@value="2011-02-03T04:05:06Z"]
1525+
[@value="2011-02-03T04:05:06"]
15261526
'
15271527
);
15281528
}
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
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+
namespaceSymfony\Component\Form\Tests\Extension\Core\DataTransformer;
13+
14+
usePHPUnit\Framework\TestCase;
15+
useSymfony\Component\Form\Extension\Core\DataTransformer\DateTimeToHtml5DateTimeLocalTransformer;
16+
17+
class DateTimeToHtml5DateTimeLocaleTransformerTestextends TestCase
18+
{
19+
protected$dateTime;
20+
protected$dateTimeWithoutSeconds;
21+
22+
protectedfunctionsetUp()
23+
{
24+
parent::setUp();
25+
26+
$this->dateTime =new \DateTime('2010-02-03 04:05:06 UTC');
27+
$this->dateTimeWithoutSeconds =new \DateTime('2010-02-03 04:05:00 UTC');
28+
}
29+
30+
protectedfunctiontearDown()
31+
{
32+
$this->dateTime =null;
33+
$this->dateTimeWithoutSeconds =null;
34+
}
35+
36+
publicstaticfunctionassertEquals($expected,$actual,$message ='',$delta =0,$maxDepth =10,$canonicalize =false,$ignoreCase =false)
37+
{
38+
if ($expectedinstanceof \DateTime &&$actualinstanceof \DateTime) {
39+
$expected =$expected->format('c');
40+
$actual =$actual->format('c');
41+
}
42+
43+
parent::assertEquals($expected,$actual,$message,$delta,$maxDepth,$canonicalize,$ignoreCase);
44+
}
45+
46+
publicfunctionallProvider()
47+
{
48+
returnarray(
49+
array('UTC','UTC','2010-02-03 04:05:06 UTC','2010-02-03T04:05:06'),
50+
array('UTC','UTC',null,''),
51+
array('America/New_York','Asia/Hong_Kong','2010-02-03 04:05:06 America/New_York','2010-02-03T17:05:06+08:00'),
52+
array('America/New_York','Asia/Hong_Kong',null,''),
53+
array('UTC','Asia/Hong_Kong','2010-02-03 04:05:06 UTC','2010-02-03T12:05:06+08:00'),
54+
array('America/New_York','UTC','2010-02-03 04:05:06 America/New_York','2010-02-03T09:05:06'),
55+
);
56+
}
57+
58+
publicfunctiontransformProvider()
59+
{
60+
return$this->allProvider();
61+
}
62+
63+
publicfunctionreverseTransformProvider()
64+
{
65+
returnarray(
66+
// format without seconds, as appears in some browsers
67+
array('UTC','UTC','2010-02-03 04:05:06 UTC','2010-02-03T04:05:06'),
68+
array('UTC','UTC',null,''),
69+
array('America/New_York','Asia/Hong_Kong','2010-02-03 04:05:06 America/New_York','2010-02-03T17:05:06+08:00'),
70+
array('America/New_York','Asia/Hong_Kong',null,''),
71+
array('UTC','Asia/Hong_Kong','2010-02-03 04:05:06 UTC','2010-02-03T12:05:06+08:00'),
72+
array('America/New_York','UTC','2010-02-03 04:05:06 America/New_York','2010-02-03T09:05:06'),
73+
array('UTC','UTC','2010-02-03 04:05:00 UTC','2010-02-03T04:05'),
74+
array('America/New_York','Asia/Hong_Kong','2010-02-03 04:05:00 America/New_York','2010-02-03T17:05+08:00'),
75+
array('Europe/Amsterdam','Europe/Amsterdam','2013-08-21 10:30:00 Europe/Amsterdam','2013-08-21T08:30:00'),
76+
);
77+
}
78+
79+
/**
80+
* @dataProvider transformProvider
81+
*/
82+
publicfunctiontestTransform($fromTz,$toTz,$from,$to)
83+
{
84+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer($fromTz,$toTz);
85+
86+
$this->assertSame($to,$transformer->transform(null !==$from ?new \DateTime($from) :null));
87+
}
88+
89+
/**
90+
* @dataProvider transformProvider
91+
* @requires PHP 5.5
92+
*/
93+
publicfunctiontestTransformDateTimeImmutable($fromTz,$toTz,$from,$to)
94+
{
95+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer($fromTz,$toTz);
96+
97+
$this->assertSame($to,$transformer->transform(null !==$from ?new \DateTimeImmutable($from) :null));
98+
}
99+
100+
/**
101+
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
102+
*/
103+
publicfunctiontestTransformRequiresValidDateTime()
104+
{
105+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer();
106+
$transformer->transform('2010-01-01');
107+
}
108+
109+
/**
110+
* @dataProvider reverseTransformProvider
111+
*/
112+
publicfunctiontestReverseTransform($toTz,$fromTz,$to,$from)
113+
{
114+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer($toTz,$fromTz);
115+
116+
if (null !==$to) {
117+
$this->assertEquals(new \DateTime($to),$transformer->reverseTransform($from));
118+
}else {
119+
$this->assertNull($transformer->reverseTransform($from));
120+
}
121+
}
122+
123+
/**
124+
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
125+
*/
126+
publicfunctiontestReverseTransformRequiresString()
127+
{
128+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer();
129+
$transformer->reverseTransform(12345);
130+
}
131+
132+
/**
133+
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
134+
*/
135+
publicfunctiontestReverseTransformWithNonExistingDate()
136+
{
137+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer('UTC','UTC');
138+
139+
$transformer->reverseTransform('2010-04-31T04:05Z');
140+
}
141+
142+
/**
143+
* @expectedException \Symfony\Component\Form\Exception\TransformationFailedException
144+
*/
145+
publicfunctiontestReverseTransformExpectsValidDateString()
146+
{
147+
$transformer =newDateTimeToHtml5DateTimeLocalTransformer('UTC','UTC');
148+
149+
$transformer->reverseTransform('2010-2010-2010');
150+
}
151+
}

‎src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -238,10 +238,10 @@ public function testSubmitStringSingleText()
238238
'widget' =>'single_text',
239239
));
240240

241-
$form->submit('2010-06-02T03:04:00Z');
241+
$form->submit('2010-06-02T03:04:00');
242242

243243
$this->assertEquals('2010-06-02 03:04:00',$form->getData());
244-
$this->assertEquals('2010-06-02T03:04:00Z',$form->getViewData());
244+
$this->assertEquals('2010-06-02T03:04:00',$form->getViewData());
245245
}
246246

247247
publicfunctiontestSubmitStringSingleTextWithSeconds()
@@ -254,10 +254,10 @@ public function testSubmitStringSingleTextWithSeconds()
254254
'with_seconds' =>true,
255255
));
256256

257-
$form->submit('2010-06-02T03:04:05Z');
257+
$form->submit('2010-06-02T03:04:05');
258258

259259
$this->assertEquals('2010-06-02 03:04:05',$form->getData());
260-
$this->assertEquals('2010-06-02T03:04:05Z',$form->getViewData());
260+
$this->assertEquals('2010-06-02T03:04:05',$form->getViewData());
261261
}
262262

263263
publicfunctiontestSubmitDifferentPattern()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp