Skip to content

Commit d1d1ceb

Browse files
fbourigaultdunglas
authored andcommitted
[Serialized] allow configuring the serialized name of properties through metadata
1 parent 5a0cad2 commit d1d1ceb

File tree

22 files changed

+516
-6
lines changed

22 files changed

+516
-6
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,8 @@
7474
use Symfony\Component\PropertyAccess\PropertyAccessor;
7575
use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface;
7676
use Symfony\Component\PropertyInfo\PropertyDescriptionExtractorInterface;
77-
use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface;
7877
use Symfony\Component\PropertyInfo\PropertyInfoExtractorInterface;
78+
use Symfony\Component\PropertyInfo\PropertyInitializableExtractorInterface;
7979
use Symfony\Component\PropertyInfo\PropertyListExtractorInterface;
8080
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
8181
use Symfony\Component\Routing\Loader\AnnotationDirectoryLoader;
@@ -1363,7 +1363,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
13631363
}
13641364

13651365
if (isset($config['name_converter']) && $config['name_converter']) {
1366-
$container->getDefinition('serializer.normalizer.object')->replaceArgument(1, new Reference($config['name_converter']));
1366+
$container->getDefinition('serializer.name_converter.metadata_aware')->setArgument(1, new Reference($config['name_converter']));
13671367
}
13681368

13691369
if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) {

src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858

5959
<service id="serializer.normalizer.object" class="Symfony\Component\Serializer\Normalizer\ObjectNormalizer">
6060
<argument type="service" id="serializer.mapping.class_metadata_factory" />
61-
<argument>null</argument> <!-- name converter -->
61+
<argument type="service" id="serializer.name_converter.metadata_aware" />
6262
<argument type="service" id="serializer.property_accessor" />
6363
<argument type="service" id="property_info" on-invalid="ignore" />
6464
<argument type="service" id="serializer.mapping.class_discriminator_resolver" on-invalid="ignore" />
@@ -119,6 +119,10 @@
119119
<!-- Name converter -->
120120
<service id="serializer.name_converter.camel_case_to_snake_case" class="Symfony\Component\Serializer\NameConverter\CamelCaseToSnakeCaseNameConverter" />
121121

122+
<service id="serializer.name_converter.metadata_aware" class="Symfony\Component\Serializer\NameConverter\MetadataAwareNameConverter" >
123+
<argument type="service" id="serializer.mapping.class_metadata_factory"/>
124+
</service>
125+
122126
<!-- PropertyInfo extractor -->
123127
<service id="property_info.serializer_extractor" class="Symfony\Component\PropertyInfo\Extractor\SerializerExtractor">
124128
<argument type="service" id="serializer.mapping.class_metadata_factory" />

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -976,7 +976,7 @@ public function testSerializerEnabled()
976976
$this->assertCount(2, $argument);
977977
$this->assertEquals('Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader', $argument[0]->getClass());
978978
$this->assertNull($container->getDefinition('serializer.mapping.class_metadata_factory')->getArgument(1));
979-
$this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.normalizer.object')->getArgument(1));
979+
$this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.name_converter.metadata_aware')->getArgument(1));
980980
$this->assertEquals(new Reference('property_info', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), $container->getDefinition('serializer.normalizer.object')->getArgument(3));
981981
$this->assertEquals(array('setCircularReferenceHandler', array(new Reference('my.circular.reference.handler'))), $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[0]);
982982
$this->assertEquals(array('setMaxDepthHandler', array(new Reference('my.max.depth.handler'))), $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[1]);

src/Symfony/Bundle/FrameworkBundle/composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
"symfony/process": "~3.4|~4.0",
4646
"symfony/security-core": "~3.4|~4.0",
4747
"symfony/security-csrf": "~3.4|~4.0",
48-
"symfony/serializer": "^4.1",
48+
"symfony/serializer": "^4.2",
4949
"symfony/stopwatch": "~3.4|~4.0",
5050
"symfony/translation": "~4.2",
5151
"symfony/templating": "~3.4|~4.0",
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
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\Annotation;
13+
14+
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
15+
16+
/**
17+
* Annotation class for @SerializedName().
18+
*
19+
* @Annotation
20+
* @Target({"PROPERTY", "METHOD"})
21+
*
22+
* @author Fabien Bourigault <bourigaultfabien@gmail.com>
23+
*/
24+
final class SerializedName
25+
{
26+
/**
27+
* @var string
28+
*/
29+
private $serializedName;
30+
31+
public function __construct(array $data)
32+
{
33+
if (!isset($data['value'])) {
34+
throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" should be set.', \get_class($this)));
35+
}
36+
37+
if (!\is_string($data['value']) || empty($data['value'])) {
38+
throw new InvalidArgumentException(sprintf('Parameter of annotation "%s" must be a non-empty string.', \get_class($this)));
39+
}
40+
41+
$this->serializedName = $data['value'];
42+
}
43+
44+
public function getSerializedName(): string
45+
{
46+
return $this->serializedName;
47+
}
48+
}

src/Symfony/Component/Serializer/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ CHANGELOG
2222
either `EncoderInterface` or `DecoderInterface`
2323
* added the optional `$objectClassResolver` argument in `AbstractObjectNormalizer`
2424
and `ObjectNormalizer` constructor
25+
* added `MetadataAwareNameConverter` to configure the serialized name of properties through metadata
2526

2627
4.1.0
2728
-----

src/Symfony/Component/Serializer/Mapping/AttributeMetadata.php

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ class AttributeMetadata implements AttributeMetadataInterface
4141
*/
4242
public $maxDepth;
4343

44+
/**
45+
* @var string|null
46+
*
47+
* @internal This property is public in order to reduce the size of the
48+
* class' serialized representation. Do not access it. Use
49+
* {@link getSerializedName()} instead.
50+
*/
51+
public $serializedName;
52+
4453
public function __construct(string $name)
4554
{
4655
$this->name = $name;
@@ -88,6 +97,22 @@ public function getMaxDepth()
8897
return $this->maxDepth;
8998
}
9099

100+
/**
101+
* {@inheritdoc}
102+
*/
103+
public function setSerializedName(string $serializedName = null)
104+
{
105+
$this->serializedName = $serializedName;
106+
}
107+
108+
/**
109+
* {@inheritdoc}
110+
*/
111+
public function getSerializedName(): ?string
112+
{
113+
return $this->serializedName;
114+
}
115+
91116
/**
92117
* {@inheritdoc}
93118
*/
@@ -101,6 +126,11 @@ public function merge(AttributeMetadataInterface $attributeMetadata)
101126
if (null === $this->maxDepth) {
102127
$this->maxDepth = $attributeMetadata->getMaxDepth();
103128
}
129+
130+
// Overwrite only if not defined
131+
if (null === $this->serializedName) {
132+
$this->serializedName = $attributeMetadata->getSerializedName();
133+
}
104134
}
105135

106136
/**
@@ -110,6 +140,6 @@ public function merge(AttributeMetadataInterface $attributeMetadata)
110140
*/
111141
public function __sleep()
112142
{
113-
return array('name', 'groups', 'maxDepth');
143+
return array('name', 'groups', 'maxDepth', 'serializedName');
114144
}
115145
}

src/Symfony/Component/Serializer/Mapping/AttributeMetadataInterface.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,16 @@ public function setMaxDepth($maxDepth);
5757
*/
5858
public function getMaxDepth();
5959

60+
/**
61+
* Sets the serialization name for this attribute.
62+
*/
63+
public function setSerializedName(string $serializedName = null);
64+
65+
/**
66+
* Gets the serialization name for this attribute.
67+
*/
68+
public function getSerializedName(): ?string;
69+
6070
/**
6171
* Merges an {@see AttributeMetadataInterface} with in the current one.
6272
*/

src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
1616
use Symfony\Component\Serializer\Annotation\Groups;
1717
use Symfony\Component\Serializer\Annotation\MaxDepth;
18+
use Symfony\Component\Serializer\Annotation\SerializedName;
1819
use Symfony\Component\Serializer\Exception\MappingException;
1920
use Symfony\Component\Serializer\Mapping\AttributeMetadata;
2021
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
@@ -68,6 +69,8 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata)
6869
}
6970
} elseif ($annotation instanceof MaxDepth) {
7071
$attributesMetadata[$property->name]->setMaxDepth($annotation->getMaxDepth());
72+
} elseif ($annotation instanceof SerializedName) {
73+
$attributesMetadata[$property->name]->setSerializedName($annotation->getSerializedName());
7174
}
7275

7376
$loaded = true;
@@ -107,6 +110,12 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata)
107110
}
108111

109112
$attributeMetadata->setMaxDepth($annotation->getMaxDepth());
113+
} elseif ($annotation instanceof SerializedName) {
114+
if (!$accessorOrMutator) {
115+
throw new MappingException(sprintf('SerializedName on "%s::%s" cannot be added. SerializedName can only be added on methods beginning with "get", "is", "has" or "set".', $className, $method->name));
116+
}
117+
118+
$attributeMetadata->setSerializedName($annotation->getSerializedName());
110119
}
111120

112121
$loaded = true;

src/Symfony/Component/Serializer/Mapping/Loader/XmlFileLoader.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ public function loadClassMetadata(ClassMetadataInterface $classMetadata)
6666
if (isset($attribute['max-depth'])) {
6767
$attributeMetadata->setMaxDepth((int) $attribute['max-depth']);
6868
}
69+
70+
if (isset($attribute['serialized-name'])) {
71+
$attributeMetadata->setSerializedName((string) $attribute['serialized-name']);
72+
}
6973
}
7074

7175
if (isset($xml->{'discriminator-map'})) {

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