Skip to content

Commit

Permalink
Merge pull request #1108 from VincentLanglet/handleArray
Browse files Browse the repository at this point in the history
Handle array format for dateHandler
  • Loading branch information
goetas authored Jan 24, 2020
2 parents cb74e6f + a2c5a59 commit 5286388
Show file tree
Hide file tree
Showing 11 changed files with 223 additions and 126 deletions.
210 changes: 111 additions & 99 deletions doc/reference/annotations.rst

Large diffs are not rendered by default.

43 changes: 25 additions & 18 deletions src/Handler/DateHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -221,23 +221,32 @@ public function deserializeDateIntervalFromJson(DeserializationVisitorInterface
private function parseDateTime($data, array $type, bool $immutable = false): \DateTimeInterface
{
$timezone = !empty($type['params'][1]) ? new \DateTimeZone($type['params'][1]) : $this->defaultTimezone;
$format = $this->getDeserializationFormat($type);
$formats = $this->getDeserializationFormats($type);

$formatTried = [];
foreach ($formats as $format) {
if ($immutable) {
$datetime = \DateTimeImmutable::createFromFormat($format, (string) $data, $timezone);
} else {
$datetime = \DateTime::createFromFormat($format, (string) $data, $timezone);
}

if ($immutable) {
$datetime = \DateTimeImmutable::createFromFormat($format, (string) $data, $timezone);
} else {
$datetime = \DateTime::createFromFormat($format, (string) $data, $timezone);
}
if (false !== $datetime) {
if ('U' === $format) {
$datetime = $datetime->setTimezone($timezone);
}

if (false === $datetime) {
throw new RuntimeException(sprintf('Invalid datetime "%s", expected format %s.', $data, $format));
}
return $datetime;
}

if ('U' === $format) {
$datetime = $datetime->setTimezone($timezone);
$formatTried[] = $format;
}

return $datetime;
throw new RuntimeException(sprintf(
'Invalid datetime "%s", expected one of the format %s.',
$data,
'"' . implode('", "', $formatTried) . '"'
));
}

private function parseDateInterval(string $data): \DateInterval
Expand All @@ -255,15 +264,13 @@ private function parseDateInterval(string $data): \DateInterval
/**
* @param array $type
*/
private function getDeserializationFormat(array $type): string
private function getDeserializationFormats(array $type): array
{
if (isset($type['params'][2])) {
return $type['params'][2];
}
if (isset($type['params'][0])) {
return $type['params'][0];
return is_array($type['params'][2]) ? $type['params'][2] : [$type['params'][2]];
}
return $this->defaultFormat;

return [$this->getFormat($type)];
}

/**
Expand Down
31 changes: 22 additions & 9 deletions src/Type/InnerParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ public function __construct()
[
'default' => [
'skip' => '\s+',
'array_' => '\[',
'_array' => '\]',
'parenthesis_' => '<',
'_parenthesis' => '>',
'empty_string' => '""|\'\'',
Expand Down Expand Up @@ -60,22 +62,33 @@ public function __construct()
14 => new Token(14, 'apostrophed_string', null, -1, true),
15 => new Token(15, '_apostrophe', null, -1, false),
16 => new Concatenation(16, [13, 14, 15], '#simple_type'),
'simple_type' => new Choice('simple_type', [2, 4, 6, 8, 12, 16], null),
18 => new Token(18, 'name', null, -1, true),
19 => new Token(19, 'parenthesis_', null, -1, false),
20 => new Token(20, 'comma', null, -1, false),
21 => new Concatenation(21, [20, 'type'], '#compound_type'),
22 => new Repetition(22, 0, -1, 21, null),
23 => new Token(23, '_parenthesis', null, -1, false),
'compound_type' => new Concatenation('compound_type', [18, 19, 'type', 22, 23], null),
17 => new Concatenation(17, ['array'], '#simple_type'),
'simple_type' => new Choice('simple_type', [2, 4, 6, 8, 12, 16, 17], null),
19 => new Token(19, 'name', null, -1, true),
20 => new Token(20, 'parenthesis_', null, -1, false),
21 => new Token(21, 'comma', null, -1, false),
22 => new Concatenation(22, [21, 'type'], '#compound_type'),
23 => new Repetition(23, 0, -1, 22, null),
24 => new Token(24, '_parenthesis', null, -1, false),
'compound_type' => new Concatenation('compound_type', [19, 20, 'type', 23, 24], null),
26 => new Token(26, 'array_', null, -1, false),
27 => new Token(27, 'comma', null, -1, false),
28 => new Concatenation(28, [27, 'simple_type'], '#array'),
29 => new Repetition(29, 0, -1, 28, null),
30 => new Concatenation(30, ['simple_type', 29], null),
31 => new Repetition(31, 0, 1, 30, null),
32 => new Token(32, '_array', null, -1, false),
'array' => new Concatenation('array', [26, 31, 32], null),
],
[]
);

$this->getRule('type')->setPPRepresentation(' simple_type() | compound_type()');
$this->getRule('simple_type')->setDefaultId('#simple_type');
$this->getRule('simple_type')->setPPRepresentation(' <name> | <number> | <null> | <empty_string> | ::quote_:: <quoted_string> ::_quote:: | ::apostrophe_:: <apostrophed_string> ::_apostrophe::');
$this->getRule('simple_type')->setPPRepresentation(' <name> | <number> | <null> | <empty_string> | ::quote_:: <quoted_string> ::_quote:: | ::apostrophe_:: <apostrophed_string> ::_apostrophe:: | array()');
$this->getRule('compound_type')->setDefaultId('#compound_type');
$this->getRule('compound_type')->setPPRepresentation(' <name> ::parenthesis_:: type() ( ::comma:: type() )* ::_parenthesis::');
$this->getRule('array')->setDefaultId('#array');
$this->getRule('array')->setPPRepresentation(' ::array_:: ( simple_type() ( ::comma:: simple_type() )* )? ::_array::');
}
}
17 changes: 17 additions & 0 deletions src/Type/TypeVisitor.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ public function visit(Element $element, &$handle = null, $eldnah = null)
return $this->visitSimpleType($element);
case '#compound_type':
return $this->visitCompoundType($element, $handle, $eldnah);
case '#array':
return $this->visitArrayType($element, $handle, $eldnah);
}

throw new InvalidNode();
Expand All @@ -33,6 +35,11 @@ public function visit(Element $element, &$handle = null, $eldnah = null)
private function visitSimpleType(TreeNode $element)
{
$tokenNode = $element->getChild(0);

if (!$tokenNode->isToken()) {
return $tokenNode->accept($this);
}

$token = $tokenNode->getValueToken();
$value = $tokenNode->getValueValue();

Expand Down Expand Up @@ -76,4 +83,14 @@ function (TreeNode $node) use ($handle, $eldnah) {
),
];
}

private function visitArrayType(TreeNode $node, ?int &$handle, ?int $eldnah): array
{
return array_map(
function (TreeNode $child) {
return $child->accept($this);
},
$node->getChildren()
);
}
}
6 changes: 6 additions & 0 deletions src/Type/grammar.pp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
%skip whitespace \s+

%token array_ \[
%token _array \]
%token parenthesis_ <
%token _parenthesis >
%token empty_string ""|''
Expand All @@ -26,10 +28,14 @@
| <empty_string>
| ::quote_:: <quoted_string> ::_quote::
| ::apostrophe_:: <apostrophed_string> ::_apostrophe::
| array()
#compound_type:
<name>
::parenthesis_::
type()
( ::comma:: type() )*
::_parenthesis::
#array:
::array_:: ( simple_type() ( ::comma:: simple_type() )* )? ::_array::
12 changes: 12 additions & 0 deletions tests/Handler/DateHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public function getParams()
[['Y-m-d']],
[['Y-m-d', '', 'Y-m-d|']],
[['Y-m-d', '', 'Y']],
[['Y-m-d', '', ['Y-m-d', 'Y/m/d']]],
];
}

Expand Down Expand Up @@ -65,6 +66,17 @@ public function testTimePartGetsRemoved()
);
}

public function testMultiFormatCase()
{
$visitor = new JsonDeserializationVisitor();

$type = ['name' => 'DateTime', 'params' => ['Y-m-d', '', ['Y-m-d|', 'Y/m/d']]];
self::assertEquals(
\DateTime::createFromFormat('Y/m/d', '2017/06/18', $this->timezone),
$this->handler->deserializeDateTimeFromJson($visitor, '2017/06/18', $type)
);
}

public function testTimePartGetsPreserved()
{
$visitor = new JsonDeserializationVisitor();
Expand Down
1 change: 1 addition & 0 deletions tests/Serializer/BaseSerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -665,6 +665,7 @@ public function getDateTime()
{
return [
['date_time', new \DateTime('2011-08-30 00:00', new \DateTimeZone('UTC')), 'DateTime'],
['date_time_multi_format', new \DateTime('2011-08-30 00:00', new \DateTimeZone('UTC')), "DateTime<'Y-m-d', '', ['Y-m-d','Y-m-d\TH:i:sP']>"],
];
}

Expand Down
1 change: 1 addition & 0 deletions tests/Serializer/JsonSerializationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ protected function getContent($key)
$outputs['object_when_null_and_serialized'] = '{"author":null,"text":"foo"}';
$outputs['date_time'] = '"2011-08-30T00:00:00+00:00"';
$outputs['date_time_immutable'] = '"2011-08-30T00:00:00+00:00"';
$outputs['date_time_multi_format'] = '"2011-08-30T00:00:00+00:00"';
$outputs['timestamp'] = '{"timestamp":1455148800}';
$outputs['timestamp_prev'] = '{"timestamp":"1455148800"}';
$outputs['date_interval'] = '"PT45M"';
Expand Down
24 changes: 24 additions & 0 deletions tests/Serializer/Type/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,30 @@ public function validTypesProvider(): iterable
'Foo<"asdf asdf">',
$type('Foo', ['asdf asdf']),
];
yield [
'Foo<[]>',
$type('Foo', [[]]),
];
yield [
'Foo<[[]]>',
$type('Foo', [[[]]]),
];
yield [
'Foo<[123]>',
$type('Foo', [[123]]),
];
yield [
'Foo<[123, 456]>',
$type('Foo', [[123, 456]]),
];
yield [
'Foo<[[123], 456, "bar"]>',
$type('Foo', [[[123], 456, 'bar']]),
];
yield [
'DateTime<null, null, [\'Y-m-d\TH:i:s\', \'Y-m-d\TH:i:sP\']>',
$type('DateTime', [null, null, ['Y-m-d\TH:i:s', 'Y-m-d\TH:i:sP']]),
];
}

public function testEmptyString(): void
Expand Down
2 changes: 2 additions & 0 deletions tests/Serializer/xml/date_time_multi_format.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<result><![CDATA[2011-08-30T00:00:00+00:00]]></result>
2 changes: 2 additions & 0 deletions tests/Serializer/xml/date_time_multi_format_no_cdata.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<result>2011-08-30T00:00:00+00:00</result>

0 comments on commit 5286388

Please sign in to comment.