Skip to content

Commit 3f92492

Browse files
committed
bug #51992 [Serializer] Fix using DateIntervalNormalizer with union types (Jeroeny)
This PR was squashed before being merged into the 5.4 branch. Discussion ---------- [Serializer] Fix using `DateIntervalNormalizer` with union types | Q | A | ------------- | --- | Branch? | 5.4 | Bug fix? | yes | New feature? | no | Deprecations? | no | License | MIT The union logic of `AbstractObjectNormalizer` tries to denormalize each union type and catches `NotNormalizableValueException` (among some other exceptions). If a non-catching exception is thrown, denormalization fails on that first type, while a later type might have succeeded. If I try to denormalize a `DateTimeInterface` value into a `DateInterval|DateTimeInterface` type, it will fail because the `DateIntervalNormalizer` throws `UnexpectedValueException` instead of `NotNormalizableValueException`. Denormalizing a `DateInterval` into `DateTimeInterface|DateInterval` does work, because `DateTimeNormalizer` throws `NotNormalizableValueException`. I also checked some other Object-specific normalizers like `Uid`, `Problem`, `DateTimeZone`, `DataUri`, `BackedEnum`, they are using `NotNormalizableValueException`. See reproducer: https://github.com/Jeroeny/reproduce/tree/union/src Commits ------- c727a2f [Serializer] Fix using `DateIntervalNormalizer` with union types
2 parents b34c4c7 + c727a2f commit 3f92492

File tree

2 files changed

+11
-12
lines changed

2 files changed

+11
-12
lines changed

src/Symfony/Component/Serializer/Normalizer/DateIntervalNormalizer.php

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\Component\Serializer\Normalizer;
1313

1414
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
15-
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
15+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
1616

1717
/**
1818
* Normalizes an instance of {@see \DateInterval} to an interval string.
@@ -70,17 +70,16 @@ public function hasCacheableSupportsMethod(): bool
7070
*
7171
* @return \DateInterval
7272
*
73-
* @throws InvalidArgumentException
74-
* @throws UnexpectedValueException
73+
* @throws NotNormalizableValueException
7574
*/
7675
public function denormalize($data, string $type, string $format = null, array $context = [])
7776
{
7877
if (!\is_string($data)) {
79-
throw new InvalidArgumentException(sprintf('Data expected to be a string, "%s" given.', get_debug_type($data)));
78+
throw NotNormalizableValueException::createForUnexpectedDataType('Data expected to be a string.', $data, ['string'], $context['deserialization_path'] ?? null, true);
8079
}
8180

8281
if (!$this->isISO8601($data)) {
83-
throw new UnexpectedValueException('Expected a valid ISO 8601 interval string.');
82+
throw NotNormalizableValueException::createForUnexpectedDataType('Expected a valid ISO 8601 interval string.', $data, ['string'], $context['deserialization_path'] ?? null, true);
8483
}
8584

8685
$dateIntervalFormat = $context[self::FORMAT_KEY] ?? $this->defaultContext[self::FORMAT_KEY];
@@ -98,7 +97,7 @@ public function denormalize($data, string $type, string $format = null, array $c
9897
}
9998
$valuePattern = '/^'.$signPattern.preg_replace('/%([yYmMdDhHiIsSwW])(\w)/', '(?:(?P<$1>\d+)$2)?', preg_replace('/(T.*)$/', '($1)?', $dateIntervalFormat)).'$/';
10099
if (!preg_match($valuePattern, $data)) {
101-
throw new UnexpectedValueException(sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat));
100+
throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('Value "%s" contains intervals not accepted by format "%s".', $data, $dateIntervalFormat), $data, ['string'], $context['deserialization_path'] ?? null, false);
102101
}
103102

104103
try {
@@ -115,7 +114,7 @@ public function denormalize($data, string $type, string $format = null, array $c
115114

116115
return new \DateInterval($data);
117116
} catch (\Exception $e) {
118-
throw new UnexpectedValueException($e->getMessage(), $e->getCode(), $e);
117+
throw NotNormalizableValueException::createForUnexpectedDataType($e->getMessage(), $data, ['string'], $context['deserialization_path'] ?? null, false, $e->getCode(), $e);
119118
}
120119
}
121120

src/Symfony/Component/Serializer/Tests/Normalizer/DateIntervalNormalizerTest.php

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
16-
use Symfony\Component\Serializer\Exception\UnexpectedValueException;
16+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
1717
use Symfony\Component\Serializer\Normalizer\DateIntervalNormalizer;
1818

1919
/**
@@ -123,26 +123,26 @@ public function testDenormalizeIntervalsWithOmittedPartsBeingZero()
123123

124124
public function testDenormalizeExpectsString()
125125
{
126-
$this->expectException(InvalidArgumentException::class);
126+
$this->expectException(NotNormalizableValueException::class);
127127
$this->normalizer->denormalize(1234, \DateInterval::class);
128128
}
129129

130130
public function testDenormalizeNonISO8601IntervalStringThrowsException()
131131
{
132-
$this->expectException(UnexpectedValueException::class);
132+
$this->expectException(NotNormalizableValueException::class);
133133
$this->expectExceptionMessage('Expected a valid ISO 8601 interval string.');
134134
$this->normalizer->denormalize('10 years 2 months 3 days', \DateInterval::class, null);
135135
}
136136

137137
public function testDenormalizeInvalidDataThrowsException()
138138
{
139-
$this->expectException(UnexpectedValueException::class);
139+
$this->expectException(NotNormalizableValueException::class);
140140
$this->normalizer->denormalize('invalid interval', \DateInterval::class);
141141
}
142142

143143
public function testDenormalizeFormatMismatchThrowsException()
144144
{
145-
$this->expectException(UnexpectedValueException::class);
145+
$this->expectException(NotNormalizableValueException::class);
146146
$this->normalizer->denormalize('P00Y00M00DT00H00M00S', \DateInterval::class, null, [DateIntervalNormalizer::FORMAT_KEY => 'P%yY%mM%dD']);
147147
}
148148

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy