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

Appearance settings

Commit 43e9064

Browse filesBrowse files
committed
Add NumberNormalizer
1 parent d4566b2 commit 43e9064
Copy full SHA for 43e9064

File tree

5 files changed

+216
-2
lines changed
Filter options

5 files changed

+216
-2
lines changed

‎src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
use Symfony\Component\Serializer\Normalizer\JsonSerializableNormalizer;
4545
use Symfony\Component\Serializer\Normalizer\MimeMessageNormalizer;
4646
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
47+
use Symfony\Component\Serializer\Normalizer\NumberNormalizer;
4748
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
4849
use Symfony\Component\Serializer\Normalizer\ProblemNormalizer;
4950
use Symfony\Component\Serializer\Normalizer\PropertyNormalizer;
@@ -221,5 +222,8 @@
221222

222223
->set('serializer.normalizer.backed_enum', BackedEnumNormalizer::class)
223224
->tag('serializer.normalizer', ['built_in' => true, 'priority' => -915])
225+
226+
->set('serializer.normalizer.number', NumberNormalizer::class)
227+
->tag('serializer.normalizer', ['built_in' => true, 'priority' => -915])
224228
;
225229
};

‎src/Symfony/Bundle/FrameworkBundle/composer.json

Copy file name to clipboardExpand all lines: src/Symfony/Bundle/FrameworkBundle/composer.json
+2-2Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
"symfony/scheduler": "^6.4.4|^7.0.4",
6060
"symfony/security-bundle": "^6.4|^7.0",
6161
"symfony/semaphore": "^6.4|^7.0",
62-
"symfony/serializer": "^7.1",
62+
"symfony/serializer": "^7.3",
6363
"symfony/stopwatch": "^6.4|^7.0",
6464
"symfony/string": "^6.4|^7.0",
6565
"symfony/translation": "^6.4.3|^7.0",
@@ -99,7 +99,7 @@
9999
"symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4",
100100
"symfony/security-csrf": "<7.2",
101101
"symfony/security-core": "<6.4",
102-
"symfony/serializer": "<7.1",
102+
"symfony/serializer": "<7.3",
103103
"symfony/stopwatch": "<6.4",
104104
"symfony/translation": "<6.4.3",
105105
"symfony/twig-bridge": "<6.4",

‎src/Symfony/Component/Serializer/CHANGELOG.md

Copy file name to clipboardExpand all lines: src/Symfony/Component/Serializer/CHANGELOG.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ CHANGELOG
55
---
66

77
* Deprecate the `CompiledClassMetadataFactory` and `CompiledClassMetadataCacheWarmer` classes
8+
* Add `NumberNormalizer` to normalize `BcMath\Number` as `string`
89

910
7.2
1011
---
+81Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
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+
namespace Symfony\Component\Serializer\Normalizer;
13+
14+
use BcMath\Number;
15+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
16+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
17+
18+
/**
19+
* Normalizes a {@see Number} to a string.
20+
*/
21+
final class NumberNormalizer implements NormalizerInterface, DenormalizerInterface
22+
{
23+
/**
24+
* If true, will denormalize any invalid value into null.
25+
*/
26+
public const ALLOW_INVALID_VALUES = 'allow_invalid_values';
27+
28+
public function getSupportedTypes(?string $format): array
29+
{
30+
return [
31+
Number::class => true,
32+
];
33+
}
34+
35+
public function normalize(mixed $data, ?string $format = null, array $context = []): int|string
36+
{
37+
if (!$data instanceof Number) {
38+
throw new InvalidArgumentException('The data must be an instance of '.Number::class.'.');
39+
}
40+
41+
return (string) $data;
42+
}
43+
44+
public function supportsNormalization(mixed $data, ?string $format = null, array $context = []): bool
45+
{
46+
return $data instanceof Number;
47+
}
48+
49+
/**
50+
* @throws NotNormalizableValueException
51+
*/
52+
public function denormalize(mixed $data, string $type, ?string $format = null, array $context = []): ?Number
53+
{
54+
if (Number::class !== $type) {
55+
throw new InvalidArgumentException('Only '.Number::class.' supported.');
56+
}
57+
58+
if (null === $data && ($context[self::ALLOW_INVALID_VALUES] ?? false)) {
59+
return null;
60+
}
61+
62+
if (!\is_int($data) && !\is_string($data)) {
63+
throw NotNormalizableValueException::createForUnexpectedDataType('The data is neither an integer nor a string, you should pass an integer or a string that can be parsed as a '.Number::class.'.', $data, ['int', 'string'], $context['deserialization_path'] ?? null, true);
64+
}
65+
66+
try {
67+
return new Number($data);
68+
} catch (\ValueError $e) {
69+
if ($context[self::ALLOW_INVALID_VALUES] ?? false) {
70+
return null;
71+
}
72+
73+
throw NotNormalizableValueException::createForUnexpectedDataType('The data must represent a number', $data, [$type], $context['deserialization_path'] ?? null, true, 0, $e);
74+
}
75+
}
76+
77+
public function supportsDenormalization(mixed $data, string $type, ?string $format = null, array $context = []): bool
78+
{
79+
return Number::class === $type;
80+
}
81+
}
+128Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
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+
namespace Symfony\Component\Serializer\Tests\Normalizer;
13+
14+
use BcMath\Number;
15+
use PHPUnit\Framework\TestCase;
16+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
17+
use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
18+
use Symfony\Component\Serializer\Normalizer\NumberNormalizer;
19+
20+
/**
21+
* @requires PHP 8.4
22+
* @requires extension bcmath
23+
*/
24+
class NumberNormalizerTest extends TestCase
25+
{
26+
private NumberNormalizer $normalizer;
27+
28+
protected function setUp(): void
29+
{
30+
$this->normalizer = new NumberNormalizer();
31+
}
32+
33+
public function testSupportsNormalization()
34+
{
35+
$this->assertTrue($this->normalizer->supportsNormalization(new Number('1.23')));
36+
$this->assertFalse($this->normalizer->supportsNormalization((object) ['value' => '1.23', 'scale' => 2]));
37+
$this->assertFalse($this->normalizer->supportsNormalization('1.23'));
38+
$this->assertFalse($this->normalizer->supportsNormalization(1.23));
39+
$this->assertFalse($this->normalizer->supportsNormalization(null));
40+
}
41+
42+
public function testNormalize()
43+
{
44+
$this->assertSame('1.23', $this->normalizer->normalize(new Number('1.23')));
45+
$this->assertSame('1', $this->normalizer->normalize(new Number('1')));
46+
$this->assertSame('123', $this->normalizer->normalize(new Number(123)));
47+
}
48+
49+
public function testNormalizeBadObjectTypeThrowsException()
50+
{
51+
$this->expectException(InvalidArgumentException::class);
52+
$this->normalizer->normalize(new \stdClass());
53+
}
54+
55+
public function testSupportsDenormalization()
56+
{
57+
$this->assertTrue($this->normalizer->supportsDenormalization(null, Number::class));
58+
$this->assertFalse($this->normalizer->supportsDenormalization(null, \stdClass::class));
59+
}
60+
61+
public function testDenormalize()
62+
{
63+
$this->assertEquals(new Number('1.23'), $number = $this->normalizer->denormalize('1.23', Number::class));
64+
$this->assertEquals(new Number('123'), $this->normalizer->denormalize('123', Number::class));
65+
$this->assertEquals(new Number('123'), $this->normalizer->denormalize(123, Number::class));
66+
}
67+
68+
public function testDenormalizeNullValueThrowsException()
69+
{
70+
$this->expectException(NotNormalizableValueException::class);
71+
$this->normalizer->denormalize(null, Number::class);
72+
}
73+
74+
public function testDenormalizeBooleanValueThrowsException()
75+
{
76+
$this->expectException(NotNormalizableValueException::class);
77+
$this->normalizer->denormalize(true, Number::class);
78+
}
79+
80+
public function testDenormalizeObjectThrowsException()
81+
{
82+
$this->expectException(NotNormalizableValueException::class);
83+
$this->normalizer->denormalize(new \stdClass(), Number::class);
84+
}
85+
86+
public function testDenormalizeBadNumberValueThrowsException()
87+
{
88+
$this->expectException(NotNormalizableValueException::class);
89+
$this->expectExceptionMessage('The data must represent a number');
90+
91+
$this->normalizer->denormalize('foobar', Number::class);
92+
}
93+
94+
public function testNormalizeShouldThrowExceptionForNonNumberObjects()
95+
{
96+
$this->expectException(\InvalidArgumentException::class);
97+
$this->expectExceptionMessage('The data must be an instance of BcMath\Number.');
98+
99+
$this->normalizer->normalize(\stdClass::class);
100+
}
101+
102+
public function testDenormalizeShouldThrowExceptionForNonNumberObjects()
103+
{
104+
$this->expectException(\InvalidArgumentException::class);
105+
$this->expectExceptionMessage('Only BcMath\Number supported.');
106+
107+
$this->normalizer->denormalize('1.23', \stdClass::class);
108+
}
109+
110+
public function testDenormalizeShouldThrowExceptionForFloats()
111+
{
112+
$this->expectException(NotNormalizableValueException::class);
113+
$this->expectExceptionMessage('The data is neither an integer nor a string, you should pass an integer or a string that can be parsed as a BcMath\Number.');
114+
115+
$this->normalizer->denormalize(1.23, Number::class);
116+
}
117+
118+
public function testSupportsNormalizationShouldFailForNonNumberObjects()
119+
{
120+
$this->assertFalse($this->normalizer->supportsNormalization(new \stdClass()));
121+
}
122+
123+
public function testItIgnoresInvalidValuesIfContextIsPassed()
124+
{
125+
$this->assertNull($this->normalizer->denormalize('foo', Number::class, null, [NumberNormalizer::ALLOW_INVALID_VALUES => true]));
126+
$this->assertNull($this->normalizer->denormalize(null, Number::class, null, [NumberNormalizer::ALLOW_INVALID_VALUES => true]));
127+
}
128+
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.