8000 merged branch bschussek/bugfix (PR #6353) · symfony/symfony@563b208 · GitHub
[go: up one dir, main page]

Skip to content

Commit 563b208

Browse files
committed
merged branch bschussek/bugfix (PR #6353)
This PR was merged into the 2.1 branch. Commits ------- ad29df5 [Form] Fixed DateTimeToStringTransformer parsing on PHP < 5.3.8 Discussion ---------- [Form] Fixed DateTimeToStringTransformer parsing on PHP < 5.3.8 Bug fix: yes Feature addition: no Backwards compatibility break: no Symfony2 tests pass: yes Fixes the following tickets: #6351, see comments in b20c5ca Todo: - License of the code: MIT Documentation PR: -
2 parents c6bd807 + ad29df5 commit 563b208

File tree

2 files changed

+135
-15
lines changed

2 files changed

+135
-15
lines changed

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

Lines changed: 84 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,38 @@ class DateTimeToStringTransformer extends BaseDateTimeTransformer
3939
*/
4040
private $parseFormat;
4141

42+
/**
43+
* Whether to parse by appending a pipe "|" to the parse format.
44+
*
45+
* This only works as of PHP 5.3.8.
46+
*
47+
* @var Boolean
48+
*/
49+
private $parseUsingPipe;
50+
4251
/**
4352
* Transforms a \DateTime instance to a string
4453
*
4554
* @see \DateTime::format() for supported formats
4655
*
47-
* @param string $inputTimezone The name of the input timezone
48-
* @param string $outputTimezone The name of the output timezone
49-
* @param string $format The date format
56+
* @param string $inputTimezone The name of the input timezone
57+
* @param string $outputTimezone The name of the output timezone
58+
* @param string $format The date format
59+
* @param Boolean $parseUsingPipe Whether to parse by appending a pipe "|" to the parse format
5060
*
5161
* @throws UnexpectedTypeException if a timezone is not a string
5262
*/
53-
public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s')
63+
public function __construct($inputTimezone = null, $outputTimezone = null, $format = 'Y-m-d H:i:s', $parseUsingPipe = null)
5464
{
5565
parent::__construct($inputTimezone, $outputTimezone);
5666

5767
$this->generateFormat = $this->parseFormat = $format;
5868

69+
// The pipe in the parser pattern only works as of PHP 5.3.8
70+
$this->parseUsingPipe = null === $parseUsingPipe
71+
? version_compare(phpversion(), '5.3.8', '>=')
72+
: $parseUsingPipe;
73+
5974
// See http://php.net/manual/en/datetime.createfromformat.php
6075
// The character "|" in the format makes sure that the parts of a date
6176
// that are *not* specified in the format are reset to the corresponding
@@ -64,7 +79,7 @@ public function __construct($inputTimezone = null, $outputTimezone = null, $form
6479
// where the time corresponds to the current server time.
6580
// With "|" and "Y-m-d", "2010-02-03" becomes "2010-02-03 00:00:00",
6681
// which is at least deterministic and thus used here.
67-
if (false === strpos($this->parseFormat, '|')) {
82+
if ($this->parseUsingPipe && false === strpos($this->parseFormat, '|')) {
6883
$this->parseFormat .= '|';
6984
}
7085
}
@@ -125,6 +140,70 @@ public function reverseTransform($value)
125140
$outputTz = new \DateTimeZone($this->outputTimezone);
126141
$dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz);
127142

143+
// On PHP versions < 5.3.8 we need to emulate the pipe operator
144+
// and reset parts not given in the format to their equivalent
145+
// of the UNIX base timestamp.
146+
if (!$this->parseUsingPipe) {
147+
list($year, $month, $day, $hour, $minute, $second) = explode('-', $dateTime->format('Y-m-d-H-i-s'));
148+
149+
// Check which of the date parts are present in the pattern
150+
preg_match(
151+
'/(' .
152+
'(?<day>[djDl])|' .
153+
'(?<month>[FMmn])|' .
154+
'(?<year>[Yy])|' .
155+
'(?<hour>[ghGH])|' .
156+
'(?<minute>i)|' .
157+
'(?<second>s)|' .
158+
'(?<dayofyear>z)|' .
159+
'(?<timestamp>U)|' .
160+
'[^djDlFMmnYyghGHiszU]' .
161+
')*/',
162+
$this->parseFormat,
163+
$matches
164+
);
165+
166+
// preg_match() does not guarantee to set all indices, so
167+
// set them unless given
168+
$matches = array_merge(array(
169+
'day' => false,
170+
'month' => false,
171+
'year' => false,
172+
'hour' => false,
173+
'minute' => false,
174+
'second' => false,
175+
'dayofyear' => false,
176+
'timestamp' => false,
177+
), $matches);
178+
179+
// Reset all parts that don't exist in the format to the
180+
// corresponding part of the UNIX base timestamp
181+
if (!$matches['timestamp']) {
182+
if (!$matches['dayofyear']) {
183+
if (!$matches['day']) {
184+
$day = 1;
185+
}
186+
if (!$matches['month']) {
187+
$month = 1;
188+
}
189+
}
190+
if (!$matches['year']) {
191+
$year = 1970;
192+
}
193+
if (!$matches['hour']) {
194+
$hour = 0;
195+
}
196+
if (!$matches['minute']) {
197+
$minute = 0;
198+
}
199+
if (!$matches['second']) {
200+
$second = 0;
201+
}
202+
$dateTime->setDate($year, $month, $day);
203+
$dateTime->setTime($hour, $minute, $second);
204+
}
205+
}
206+
128207
$lastErrors = \DateTime::getLastErrors();
129208

130209
if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) {

src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToStringTransformerTest.php

Lines changed: 51 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,43 @@ class DateTimeToStringTransformerTest extends DateTimeTestCase
1818
public function dataProvider()
1919
{
2020
return array(
21-
array('Y-m-d H:i:s', '2010-02-03 04:05:06', '2010-02-03 04:05:06 UTC'),
22-
array('Y-m-d H:i:00', '2010-02-03 04:05:00', '2010-02-03 04:05:00 UTC'),
23-
array('Y-m-d H:i', '2010-02-03 04:05', '2010-02-03 04:05:00 UTC'),
24-
array('Y-m-d H', '2010-02-03 04', '2010-02-03 04:00:00 UTC'),
21+
array('Y-m-d H:i:s', '2010-02-03 16:05:06', '2010-02-03 16:05:06 UTC'),
22+
array('Y-m-d H:i:00', '2010-02-03 16:05:00', '2010-02-03 16:05:00 UTC'),
23+
array('Y-m-d H:i', '2010-02-03 16:05', '2010-02-03 16:05:00 UTC'),
24+
array('Y-m-d H', '2010-02-03 16', '2010-02-03 16:00:00 UTC'),
2525
array('Y-m-d', '2010-02-03', '2010-02-03 00:00:00 UTC'),
2626
array('Y-m', '2010-02', '2010-02-01 00:00:00 UTC'),
2727
array('Y', '2010', '2010-01-01 00:00:00 UTC'),
2828
array('d-m-Y', '03-02-2010', '2010-02-03 00:00:00 UTC'),
29-
array('H:i:s', '04:05:06', '1970-01-01 04:05:06 UTC'),
30-
array('H:i:00', '04:05:00', '1970-01-01 04:05:00 UTC'),
31-
array('H:i', '04:05', '1970-01-01 04:05:00 UTC'),
32-
array('H', '04', '1970-01-01 04:00:00 UTC'),
29+
array('H:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
30+
array('H:i:00', '16:05:00', '1970-01-01 16:05:00 UTC'),
31+
array('H:i', '16:05', '1970-01-01 16:05:00 UTC'),
32+
array('H', '16', '1970-01-01 16:00:00 UTC'),
33+
34+
// different day representations
35+
array('Y-m-j', '2010-02-3', '2010-02-03 00:00:00 UTC'),
36+
array('Y-z', '2010-33', '2010-02-03 00:00:00 UTC'),
37+
array('z', '33', '1970-02-03 00:00:00 UTC'),
38+
39+
// not bijective
40+
//array('Y-m-D', '2010-02-Wed', '2010-02-03 00:00:00 UTC'),
41+
//array('Y-m-l', '2010-02-Wednesday', '2010-02-03 00:00:00 UTC'),
42+
43+
// different month representations
44+
array('Y-n-d', '2010-2-03', '2010-02-03 00:00:00 UTC'),
45+
array('Y-M-d', '2010-Feb-03', '2010-02-03 00:00:00 UTC'),
46+
array('Y-F-d', '2010-February-03', '2010-02-03 00:00:00 UTC'),
47+
48+
// different year representations
49+
array('y-m-d', '10-02-03', '2010-02-03 00:00:00 UTC'),
50+
51+
// different time representations
52+
array('G:i:s', '16:05:06', '1970-01-01 16:05:06 UTC'),
53+
array('g:i:s a', '4:05:06 pm', '1970-01-01 16:05:06 UTC'),
54+
array('h:i:s a', '04:05:06 pm', '1970-01-01 16:05:06 UTC'),
55+
56+
// seconds since unix
57+
array('U', '1265213106', '2010-02-03 16:05:06 UTC'),
3358
);
3459
}
3560

@@ -75,8 +100,24 @@ public function testTransformExpectsDateTime()
75100
/**
76101
* @dataProvider dataProvider
77102
*/
78-
public function testReverseTransform($format, $input, $output)
103+
public function testReverseTransformBeforePhp538($format, $input, $output)
79104
{
105+
$reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format, false);
106+
107+
$output = new \DateTime($output);
108+
109+
$this->assertDateTimeEquals($output, $reverseTransformer->reverseTransform($input));
110+
}
111+
112+
/**
113+
* @dataProvider dataProvider
114+
*/
115+
public function testReverseTransformAsOfPhp538($format, $input, $output)
116+
{
117+
if (version_compare(phpversion(), '5.3.8', '<')) {
118+
$this->markTestSkipped('Requires PHP 5.3.8 or newer');
119+
}
120+
80121
$reverseTransformer = new DateTimeToStringTransformer('UTC', 'UTC', $format);
81122

82123
$output = new \DateTime($output);
@@ -95,7 +136,7 @@ public function testReverseTransform_differentTimezones()
95136
{
96137
$reverseTransformer = new DateTimeToStringTransformer('America/New_York', 'Asia/Hong_Kong', 'Y-m-d H:i:s');
97138

98-
$output = new \DateTime('2010-02-03 04:05:06 Asia/Hong_Kong');
139+
$output = new \DateTime('2010-02-03 16:05:06 Asia/Hong_Kong');
99140
$input = $output->format('Y-m-d H:i:s');
100141
$output->setTimeZone(new \DateTimeZone('America/New_York'));
101142

0 commit comments

Comments
 (0)
0