[Serializer] Add a MaxDepth handler

This commit is contained in:
Kévin Dunglas 2018-02-09 12:00:01 +01:00 committed by Fabien Potencier
parent 136408937b
commit ed975c764b
10 changed files with 51 additions and 2 deletions

View File

@ -731,6 +731,7 @@ class Configuration implements ConfigurationInterface
->booleanNode('enable_annotations')->{!class_exists(FullStack::class) && class_exists(Annotation::class) ? 'defaultTrue' : 'defaultFalse'}()->end()
->scalarNode('name_converter')->end()
->scalarNode('circular_reference_handler')->end()
->scalarNode('max_depth_handler')->end()
->arrayNode('mapping')
->addDefaultsIfNotSet()
->fixXmlConfig('path')

View File

@ -1273,6 +1273,10 @@ class FrameworkExtension extends Extension
if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) {
$container->getDefinition('serializer.normalizer.object')->addMethodCall('setCircularReferenceHandler', array(new Reference($config['circular_reference_handler'])));
}
if ($config['max_depth_handler'] ?? false) {
$container->getDefinition('serializer.normalizer.object')->addMethodCall('setMaxDepthHandler', array(new Reference($config['max_depth_handler'])));
}
}
private function registerPropertyInfoConfiguration(array $config, ContainerBuilder $container, XmlFileLoader $loader)

View File

@ -239,6 +239,7 @@
<xsd:attribute name="cache" type="xsd:string" />
<xsd:attribute name="enable-annotations" type="xsd:boolean" />
<xsd:attribute name="name-converter" type="xsd:string" />
<xsd:attribute name="max-depth-handler" type="xsd:string" />
</xsd:complexType>
<xsd:complexType name="property_info">

View File

@ -68,6 +68,7 @@ $container->loadFromExtension('framework', array(
'enabled' => true,
'enable_annotations' => true,
'name_converter' => 'serializer.name_converter.camel_case_to_snake_case',
'max_depth_handler' => 'my.max.depth.handler',
),
'property_info' => true,
'ide' => 'file%%link%%format',

View File

@ -41,7 +41,7 @@
</framework:translator>
<framework:validation enabled="true" />
<framework:annotations cache="file" debug="true" file-cache-dir="%kernel.cache_dir%/annotations" />
<framework:serializer enabled="true" enable-annotations="true" name-converter="serializer.name_converter.camel_case_to_snake_case" />
<framework:serializer enabled="true" enable-annotations="true" name-converter="serializer.name_converter.camel_case_to_snake_case" max-depth-handler="my.max.depth.handler" />
<framework:property-info />
</framework:config>
</container>

View File

@ -54,6 +54,7 @@ framework:
enabled: true
enable_annotations: true
name_converter: serializer.name_converter.camel_case_to_snake_case
max_depth_handler: my.max.depth.handler
property_info: ~
ide: file%%link%%format
request:

View File

@ -804,6 +804,7 @@ abstract class FrameworkExtensionTest extends TestCase
$this->assertNull($container->getDefinition('serializer.mapping.class_metadata_factory')->getArgument(1));
$this->assertEquals(new Reference('serializer.name_converter.camel_case_to_snake_case'), $container->getDefinition('serializer.normalizer.object')->getArgument(1));
$this->assertEquals(new Reference('property_info', ContainerBuilder::IGNORE_ON_INVALID_REFERENCE), $container->getDefinition('serializer.normalizer.object')->getArgument(3));
$this->assertEquals(array('setMaxDepthHandler', array(new Reference('my.max.depth.handler'))), $container->getDefinition('serializer.normalizer.object')->getMethodCalls()[0]);
}
public function testRegisterSerializerExtractor()

View File

@ -9,6 +9,8 @@ CHANGELOG
* added an optional `default_constructor_arguments` option of context to specify a default data in
case the object is not initializable by its constructor because of data missing
* added optional `bool $escapeFormulas = false` argument to `CsvEncoder::__construct`
* added `AbstractObjectNormalizer::setMaxDepthHandler` to set a handler to call when the configured
maximum depth is reached
4.0.0
-----

View File

@ -41,6 +41,11 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
private $attributesCache = array();
private $cache = array();
/**
* @var callable|null
*/
private $maxDepthHandler;
/**
* @var ClassDiscriminatorResolverInterface|null
*/
@ -86,11 +91,15 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
$attributesMetadata = $this->classMetadataFactory ? $this->classMetadataFactory->getMetadataFor($class)->getAttributesMetadata() : null;
foreach ($attributes as $attribute) {
if (null !== $attributesMetadata && $this->isMaxDepthReached($attributesMetadata, $class, $attribute, $context)) {
$maxDepthReached = false;
if (null !== $attributesMetadata && ($maxDepthReached = $this->isMaxDepthReached($attributesMetadata, $class, $attribute, $context)) && !$this->maxDepthHandler) {
continue;
}
$attributeValue = $this->getAttributeValue($object, $attribute, $format, $context);
if ($maxDepthReached) {
$attributeValue = \call_user_func($this->maxDepthHandler, $attributeValue);
}
if (isset($this->callbacks[$attribute])) {
$attributeValue = call_user_func($this->callbacks[$attribute], $attributeValue);
@ -204,6 +213,14 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer
*/
abstract protected function getAttributeValue($object, $attribute, $format = null, array $context = array());
/**
* Sets an handler function that will be called when the max depth is reached.
*/
public function setMaxDepthHandler(?callable $handler): void
{
$this->maxDepthHandler = $handler;
}
/**
* {@inheritdoc}
*/

View File

@ -613,6 +613,27 @@ class ObjectNormalizerTest extends TestCase
);
$this->assertEquals($expected, $result);
$expected = array(
'bar' => null,
'foo' => 'level1',
'child' => array(
'bar' => null,
'foo' => 'level2',
'child' => array(
'bar' => null,
'child' => null,
'foo' => 'handler',
),
),
);
$this->normalizer->setMaxDepthHandler(function ($obj) {
return 'handler';
});
$result = $serializer->normalize($level1, null, array(ObjectNormalizer::ENABLE_MAX_DEPTH => true));
$this->assertEquals($expected, $result);
}
/**